param: rename lp function and variable from "fake_dir_create_times" to "fake_director...
[kamenim/samba-autobuild/.git] / source3 / modules / vfs_media_harmony.c
1 /*
2  * $Id: media_harmony.c,v 1.1 2007/11/06 10:07:22 stuart_hc Exp $
3  *
4  * Samba VFS module supporting multiple AVID clients sharing media.
5  *
6  * Copyright (C) 2005  Philip de Nier <philipn@users.sourceforge.net>
7  * Copyright (C) 2012  Andrew Klaassen <clawsoon@yahoo.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA.
23  */
24
25
26 /*
27  * Media Harmony is a Samba VFS module that allows multiple AVID
28  * clients to share media. Each client sees their own copy of the
29  * AVID msmMMOB.mdb and msmFMID.pmr files and Creating directories.
30  *
31  * Add this module to the vfs objects option in your Samba share
32  * configuration.
33  * eg.
34  *
35  *   [avid_win]
36  *      path = /video
37  *      vfs objects = media_harmony
38  *      ...
39  *
40  * It is recommended that you separate out Samba shares for Mac
41  * and Windows clients, and add the following options to the shares
42  * for Windows clients  (NOTE: replace @ with *):
43  *
44  *      veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
45  *      delete veto files = yes
46  *
47  * This prevents hidden files from Mac clients interfering with Windows
48  * clients. If you find any more problem hidden files then add them to
49  * the list.
50  *
51  *
52  * Andrew Klaassen, 2012-03-14
53  * To prevent Avid clients from interrupting each other (via Avid's habit
54  * of launching a database refresh whenever it notices an mtime update
55  * on media directories, i.e. whenever one editor adds new material to a
56  * shared share), I've added code that causes stat information for anything
57  * directly under "Avid MediaFile/MXF" to be taken from
58  * dirname_clientaddr_clientuser if it exists.  These files ~aren't~
59  * hidden, unlike the client-suffixed database files.
60  *
61  * For example, stat information for
62  *      Avid MediaFiles/MXF/1
63  * will come from
64  *      Avid MediaFiles/MXF/1_192.168.1.10_dave
65  * for dave working on 192.168.1.10, but will come from
66  *      Avid MediaFile/MXF/1_192.168.1.11_susan
67  * for susan working on 192.168.1.11.  If those alternate
68  * directories don't exist, the user will get the actual directory's stat
69  * info.  When an editor wants to force a database refresh, they update
70  * the mtime on "their" file.  This will cause Avid
71  * on that client to see an updated mtime for "Avid MediaFiles/MXF/1",
72  * which will trigger an Avid database refresh just for that editor.
73  *
74  *
75  * Notes:
76  * - This module is designed to work with AVID editing applications that
77  * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
78  * It is not designed to work as expected in all circumstances for
79  * general use. For example: it is possibly to open client specific
80  * files such as msmMMOB.mdb_192.168.1.10_userx even though is doesn't
81  * show up in a directory listing.
82  *
83  */
84
85
86 #include "includes.h"
87 #include "system/filesys.h"
88 #include "smbd/smbd.h"
89 #include "../smbd/globals.h"
90 #include "auth.h"
91 #include "../lib/tsocket/tsocket.h"
92
93 #define MH_INFO_DEBUG 10
94 #define MH_ERR_DEBUG 0
95
96 static const char* MH_MODULE_NAME = "media_harmony";
97 static const char* MDB_FILENAME = "msmMMOB.mdb";
98 static const size_t MDB_FILENAME_LEN = 11;
99 static const char* PMR_FILENAME = "msmFMID.pmr";
100 static const size_t PMR_FILENAME_LEN = 11;
101 static const char* CREATING_DIRNAME = "Creating";
102 static const size_t CREATING_DIRNAME_LEN = 8;
103 static const char* AVID_MEDIAFILES_DIRNAME = "Avid MediaFiles";
104 static const size_t AVID_MEDIAFILES_DIRNAME_LEN = 15;
105 static const char* OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
106 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
107 static const char* APPLE_DOUBLE_PREFIX = "._";
108 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
109 static const char* AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
110 static const size_t AVID_MXF_DIRNAME_LEN = 19;
111
112 static int vfs_mh_debug_level = DBGC_VFS;
113
114 /* supplements the directory list stream */
115 typedef struct mh_dirinfo_struct
116 {
117         DIR* dirstream;
118         char *dirpath;
119         char *clientPath;
120         bool isInMediaFiles;
121         char *clientMDBFilename;
122         char *clientPMRFilename;
123         char *clientCreatingDirname;
124 } mh_dirinfo_struct;
125
126
127 /* Add "_<ip address>_<user name>" suffix to path or filename.
128  *
129  * Success: return 0
130  * Failure: set errno, path NULL, return -1
131  */
132 static int alloc_append_client_suffix(vfs_handle_struct *handle,
133                 char **path)
134 {
135         int status = 0;
136         char *raddr = NULL;
137
138         DEBUG(MH_INFO_DEBUG, ("Entering with *path '%s'\n", *path));
139
140         raddr = tsocket_address_inet_addr_string(
141                         handle->conn->sconn->remote_address, talloc_tos());
142         if (raddr == NULL)
143         {
144                 errno = ENOMEM;
145                 status = -1;
146                 goto err;
147         }
148
149         /* talloc_asprintf_append uses talloc_realloc, which
150          * frees original 'path' memory so we don't have to.
151          */
152         *path = talloc_asprintf_append(*path, "_%s_%s",
153                 raddr,
154                 handle->conn->session_info->unix_info->sanitized_username);
155         if (*path == NULL)
156         {
157                 DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
158                                         "out of memory\n"));
159                 errno = ENOMEM;
160                 status = -1;
161                 goto err;
162         }
163         DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
164 err:
165         TALLOC_FREE(raddr);
166         return status;
167 }
168
169
170 /* Returns True if the file or directory begins with the appledouble
171  * prefix.
172  */
173 static bool is_apple_double(const char* fname)
174 {
175         bool ret = False;
176
177         DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
178
179         if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
180                         == 0)
181         {
182                 ret = True;
183         }
184         DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
185                                 ret == True ? "True" : "False"));
186         return ret;
187 }
188
189 static bool starts_with_media_dir(const char* media_dirname,
190                 size_t media_dirname_len, const char* path)
191 {
192         bool ret = False;
193         char* path_start;
194
195         DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
196                               "path '%s'\n", media_dirname, path));
197
198         /* Sometimes Samba gives us "./OMFI MediaFiles". */
199         if (strncmp(path, "./", 2) == 0)
200         {
201                 path_start = &path[2];
202         }
203         else {
204                 path_start = path;
205         }
206
207         if (strncmp(media_dirname, path_start, media_dirname_len) == 0
208                         &&
209                 (
210                         path_start[media_dirname_len] == '\0'
211                         ||
212                         path_start[media_dirname_len] == '/'
213                 )
214         )
215         {
216                 ret = True;
217         }
218
219         DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
220                                 ret == True ? "True" : "False"));
221         return ret;
222 }
223
224 /*
225  * Returns True if the file or directory referenced by the path is below
226  * the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME directory
227  * The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME are assumed to
228  * be in the root directory, which is generally a safe assumption
229  * in the fixed-path world of Avid.
230  */
231 static bool is_in_media_files(const char* path)
232 {
233         bool ret = False;
234
235         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
236
237         if (
238                 starts_with_media_dir(AVID_MEDIAFILES_DIRNAME,
239                                 AVID_MEDIAFILES_DIRNAME_LEN, path)
240                 ||
241                 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
242                                 OMFI_MEDIAFILES_DIRNAME_LEN, path)
243         )
244         {
245                 ret = True;
246         }
247         DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
248                                 ret == True ? "True" : "False"));
249         return ret;
250 }
251
252 /*
253  * Returns depth of path under media directory.  Deals with the
254  * occasional ..../. and ..../.. paths that get passed to stat.
255  *
256  * Assumes is_in_media_files has already been called and has returned
257  * true for the path; if it hasn't, this function will likely crash
258  * and burn.
259  *
260  * Not foolproof; something like "Avid MediaFiles/MXF/../foo/1"
261  * would fool it.  Haven't seen paths like that getting to the
262  * stat function yet, so ignoring that possibility for now.
263  */
264 static int depth_from_media_dir(const char* media_dirname,
265                 size_t media_dirname_len, const char* path)
266 {
267         int transition_count = 0;
268         char* path_start;
269         char* pathPtr;
270
271         DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
272                               "path '%s'\n", media_dirname, path));
273
274         /* Sometimes Samba gives us "./OMFI MediaFiles". */
275         if (strncmp(path, "./", 2) == 0)
276         {
277                 path_start = &path[2];
278         }
279         else {
280                 path_start = path;
281         }
282
283         if (path_start[media_dirname_len] == '\0')
284         {
285                 goto out;
286         }
287
288         pathPtr = &path_start[media_dirname_len + 1];
289
290         while(1)
291         {
292                 if (*pathPtr == '\0' || *pathPtr == '/')
293                 {
294                         if (
295                                 *(pathPtr - 1) == '.'
296                                         &&
297                                 *(pathPtr - 2) == '.'
298                                         &&
299                                 *(pathPtr - 3) == '/'
300                         )
301                         {
302                                 transition_count--;
303                         }
304                         else if (
305                                 !
306                                 (
307                                         *(pathPtr - 1) == '/'
308                                         ||
309                                         (
310                                                 *(pathPtr - 1) == '.'
311                                                         &&
312                                                 *(pathPtr - 2) == '/'
313                                         )
314                                 )
315                         )
316                         {
317                                 transition_count++;
318                         }
319                 }
320                 if (*pathPtr == '\0')
321                 {
322                         break;
323                 }
324                 pathPtr++;
325         }
326
327         DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
328                                 transition_count));
329 out:
330         return transition_count;
331 }
332
333 /* Identifies MDB and PMR files at end of path. */
334 static bool is_avid_database(
335                 char *path,
336                 size_t path_len,
337                 const char *avid_db_filename,
338                 const size_t avid_db_filename_len)
339 {
340         bool ret = False;
341
342         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
343                               "avid_db_filename '%s', "
344                               "path_len '%i', "
345                               "avid_db_filename_len '%i'\n",
346                               path, avid_db_filename,
347                               (int)path_len, (int)avid_db_filename_len));
348
349         if (
350                 path_len > avid_db_filename_len
351                         &&
352                 strcmp(&path[path_len - avid_db_filename_len],
353                                 avid_db_filename) == 0
354                         &&
355                 (
356                         path[path_len - avid_db_filename_len - 1] == '/'
357                         ||
358                         path_len > avid_db_filename_len
359                                 + APPLE_DOUBLE_PREFIX_LEN
360                                 &&
361                         path[path_len - avid_db_filename_len
362                                 - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
363                                 &&
364                         is_apple_double(&path[path_len
365                                 - avid_db_filename_len
366                                 - APPLE_DOUBLE_PREFIX_LEN])
367                 )
368         )
369         {
370                 ret = True;
371         }
372         DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
373                                 ret == True ? "True" : "False"));
374         return ret;
375 }
376
377
378 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
379  * CREATING_SUBDIRNAME.
380  *
381  * Caller must free newPath.
382  *
383  * Success: return 0
384  * Failure: set errno, newPath NULL, return -1
385  */
386 static int alloc_get_client_path(vfs_handle_struct *handle,
387                 TALLOC_CTX *ctx,
388                 const char *path,
389                 char **newPath)
390 {
391         /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
392          * directory in path - potentially in middle of path
393          * - with suffixed name.
394          */
395         int status = 0;
396         char* pathPtr;
397         size_t intermPathLen;
398
399         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
400
401         *newPath = talloc_strdup(ctx, path);
402         if (*newPath == NULL)
403         {
404                 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
405                 errno = ENOMEM;
406                 status = -1;
407                 goto out;
408         }
409         DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
410         if (
411                 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
412                         &&
413                 (
414                         *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
415                         ||
416                         *(pathPtr + CREATING_DIRNAME_LEN) == '/'
417                 )
418                         &&
419                 (
420                         pathPtr - path > 0
421                                 &&
422                         *(pathPtr - 1) == '/'
423                         ||
424                         pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
425                                 &&
426                         *(pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1) == '/'
427                                 &&
428                         is_apple_double(pathPtr - APPLE_DOUBLE_PREFIX_LEN)
429                 )
430         )
431         {
432                 /* Insert client suffix into path. */
433                 (*newPath)[pathPtr - path + CREATING_DIRNAME_LEN] = '\0';
434                 DEBUG(MH_INFO_DEBUG, ("newPath #2 %s\n", *newPath));
435
436                 if ((status = alloc_append_client_suffix(handle, newPath)))
437                 {
438                         goto out;
439                 }
440
441                 DEBUG(MH_INFO_DEBUG, ("newPath #3 %s\n", *newPath));
442                 *newPath = talloc_strdup_append(*newPath,
443                                 pathPtr + CREATING_DIRNAME_LEN);
444                 if (*newPath == NULL)
445                 {
446                         DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path "
447                                                 "ENOMEM #2\n"));
448                         errno = ENOMEM;
449                         status = -1;
450                         goto out;
451                 }
452                 DEBUG(MH_INFO_DEBUG, ("newPath #4 %s\n", *newPath));
453         }
454
455         /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
456          * or /._PMR_FILENAME at newPath end with suffixed name.
457          */
458         intermPathLen = strlen(*newPath);
459         if (
460                 is_avid_database(*newPath, intermPathLen,
461                         MDB_FILENAME, MDB_FILENAME_LEN)
462                 ||
463                 is_avid_database(*newPath, intermPathLen,
464                         PMR_FILENAME, PMR_FILENAME_LEN)
465         )
466         {
467                 DEBUG(MH_INFO_DEBUG, ("newPath #5 %s\n", *newPath));
468                 if ((status = alloc_append_client_suffix(handle, newPath)))
469                 {
470                         goto out;
471                 }
472                 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
473         }
474 out:
475         /* newPath must be freed in caller. */
476         DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
477         return status;
478 }
479
480 /*
481  * Success: return 0
482  * Failure: set errno, return -1
483  */
484 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
485                 TALLOC_CTX *ctx,
486                 const struct smb_filename *smb_fname,
487                 struct smb_filename **clientFname)
488 {
489         int status = 0;
490         NTSTATUS copystatus;
491
492         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
493                               smb_fname->base_name));
494
495         clientFname = cp_smb_filename(ctx, smb_fname);
496         if (clientFname == NULL) {
497                 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
498                                         "NTERR\n"));
499                 errno = ENOMEM;
500                 status = -1;
501                 goto err;
502         }
503         if ((status = alloc_get_client_path(handle, ctx,
504                                 smb_fname->base_name,
505                                 &(*clientFname)->base_name)))
506         {
507                 goto err;
508         }
509         DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
510                                 "'%s'\n", (*clientFname)->base_name));
511 err:
512         return status;
513 }
514
515
516 /*
517  * Success: return 0
518  * Failure: set errno, return -1
519  */
520 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
521                 TALLOC_CTX *ctx,
522                 char **path,
523                 const char *avid_db_filename)
524 {
525         int status = 0;
526
527         DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
528                               avid_db_filename));
529
530         if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
531         {
532                 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
533                                         "ENOMEM\n"));
534                 errno = ENOMEM;
535                 status = -1;
536                 goto err;
537         }
538         if ((status = alloc_append_client_suffix(handle, path)))
539         {
540                 goto err;
541         }
542         DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
543 err:
544         return status;
545 }
546
547 /*
548  * Replace mtime on clientFname with mtime from client-suffixed
549  * equivalent, if it exists.
550  *
551  * Success: return 0
552  * Failure: set errno, return -1
553  */
554 static int set_fake_mtime(vfs_handle_struct *handle,
555                 TALLOC_CTX *ctx,
556                 struct smb_filename **clientFname,
557                 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
558 {
559         int status = 0;
560         char *statPath;
561         SMB_STRUCT_STAT fakeStat;
562         int copy_len;
563
564         DEBUG(MH_INFO_DEBUG, ("Entering with (*clientFname)->base_name "
565                               "'%s', (*clientFname)->st.st_ex_mtime %s",
566                               (*clientFname)->base_name,
567                               ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
568
569         if (
570                 depth_from_media_dir(AVID_MXF_DIRNAME,
571                                 AVID_MXF_DIRNAME_LEN,
572                                 (*clientFname)->base_name)
573                         != 1
574                         &&
575                 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
576                                 OMFI_MEDIAFILES_DIRNAME_LEN,
577                                 (*clientFname)->base_name)
578                         != 0
579         )
580         {
581                 goto out;
582         }
583
584         copy_len = strlen((*clientFname)->base_name);
585
586         /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
587          * We know we're under a media dir, so paths are at least 2 chars
588          * long.
589          */
590         if ((*clientFname)->base_name[copy_len - 1] == '.' &&
591                         (*clientFname)->base_name[copy_len - 2] == '/')
592         {
593                 copy_len -= 2;
594         }
595
596         if (((statPath = talloc_strndup(ctx,
597                         (*clientFname)->base_name, copy_len)) == NULL))
598         {
599                 errno = ENOMEM;
600                 status = -1;
601                 goto err;
602         }
603         if ((status = alloc_append_client_suffix(handle, &statPath)))
604         {
605                 goto err;
606         }
607
608         DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
609         if (statFn(statPath, &fakeStat,
610                         lp_fake_directory_create_times(SNUM(handle->conn))))
611         {
612                 /* This can fail for legitimate reasons - i.e. the
613                  * fakeStat directory doesn't exist, which is okay
614                  * - so we don't set status.  But if it does fail,
615                  * we need to skip over the mtime assignment.
616                  */
617                 goto err;
618         }
619
620         DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
621         (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
622 err:
623         TALLOC_FREE(statPath);
624 out:
625         DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
626                         "'%s', (*clientFname)->st.st_ex_mtime %s",
627                         (*clientFname)->base_name,
628                         ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
629         return status;
630 }
631
632 /*
633  * Success: return 0
634  * Failure: set errno, return -1
635  */
636 static int mh_statvfs(struct vfs_handle_struct *handle,
637                 const char *path,
638                 struct vfs_statvfs_struct *statbuf)
639 {
640         int status;
641         char *clientPath;
642         TALLOC_CTX *ctx;
643
644         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
645
646         if (!is_in_media_files(path))
647         {
648                 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
649                 goto out;
650         }
651
652         clientPath = NULL;
653         ctx = talloc_tos();
654
655         if ((status = alloc_get_client_path(handle, ctx,
656                                 path,
657                                 &clientPath)))
658         {
659                 goto err;
660         }
661
662         status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
663 err:
664         TALLOC_FREE(clientPath);
665 out:
666         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
667         return status;
668 }
669
670 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
671                 const char *fname,
672                 struct mh_dirinfo_struct **dirInfo)
673 {
674         int status = 0;
675         char *clientPath;
676         TALLOC_CTX *ctx;
677
678         DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
679
680         *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
681         if (*dirInfo == NULL)
682         {
683                 goto err;
684         }
685
686         (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
687         if ((*dirInfo)->dirpath == NULL)
688         {
689                 goto err;
690         }
691
692         if (!is_in_media_files(fname))
693         {
694                 (*dirInfo)->clientPath = NULL;
695                 (*dirInfo)->clientMDBFilename = NULL;
696                 (*dirInfo)->clientPMRFilename = NULL;
697                 (*dirInfo)->clientCreatingDirname = NULL;
698                 (*dirInfo)->isInMediaFiles = False;
699                 goto out;
700         }
701
702         (*dirInfo)->isInMediaFiles = True;
703
704         if (alloc_set_client_dirinfo_path(handle,
705                                 *dirInfo,
706                                 &((*dirInfo)->clientMDBFilename),
707                                 MDB_FILENAME))
708         {
709                 goto err;
710         }
711
712         if (alloc_set_client_dirinfo_path(handle,
713                                 *dirInfo,
714                                 &((*dirInfo)->clientPMRFilename),
715                                 PMR_FILENAME))
716         {
717                 goto err;
718         }
719
720         if (alloc_set_client_dirinfo_path(handle,
721                                 *dirInfo,
722                                 &((*dirInfo)->clientCreatingDirname),
723                                 CREATING_DIRNAME))
724         {
725                 goto err;
726         }
727
728         clientPath = NULL;
729         ctx = talloc_tos();
730
731         if (alloc_get_client_path(handle, ctx,
732                                 fname,
733                                 &clientPath))
734         {
735                 goto err;
736         }
737
738         (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
739         if ((*dirInfo)->clientPath == NULL)
740         {
741                 goto err;
742         }
743
744         TALLOC_FREE(clientPath);
745
746 out:
747         DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
748                                 "(*dirInfo)->clientPath '%s'\n",
749                                 (*dirInfo)->dirpath,
750                                 (*dirInfo)->clientPath));
751         return status;
752
753 err:
754         DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
755         TALLOC_FREE(*dirInfo);
756         status = -1;
757         errno = ENOMEM;
758         return status;
759 }
760
761 /* Success: return a mh_dirinfo_struct cast as a DIR
762  * Failure: set errno, return NULL
763  */
764 static DIR *mh_opendir(vfs_handle_struct *handle,
765                 const char *fname,
766                 const char *mask,
767                 uint32 attr)
768 {
769         struct mh_dirinfo_struct *dirInfo;
770
771         DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
772
773         if (alloc_set_client_dirinfo(handle, fname, &dirInfo))
774         {
775                 goto err;
776         }
777
778         if (!dirInfo->isInMediaFiles)
779         {
780                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
781                         fname, mask, attr);
782         } else {
783                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
784                         dirInfo->clientPath, mask, attr);
785         }
786
787         if (dirInfo->dirstream == NULL) {
788                 goto err;
789         }
790
791 out:
792         /* Success is freed in closedir. */
793         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
794                                 "dirInfo->clientPath '%s'\n",
795                                 dirInfo->dirpath,
796                                 dirInfo->clientPath));
797         return (DIR*)dirInfo;
798 err:
799         /* Failure is freed here. */
800         DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
801         TALLOC_FREE(dirInfo);
802         return NULL;
803 }
804
805 static DIR *mh_fdopendir(vfs_handle_struct *handle,
806                 files_struct *fsp,
807                 const char *mask,
808                 uint32 attr)
809 {
810         struct mh_dirinfo_struct *dirInfo = NULL;
811         DIR *dirstream;
812
813         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
814                               fsp->fsp_name->base_name));
815
816         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
817         if (!dirstream)
818         {
819                 goto err;
820         }
821
822         if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
823                                         &dirInfo))
824         {
825                 goto err;
826         }
827
828         dirInfo->dirstream = dirstream;
829
830         if (! dirInfo->isInMediaFiles) {
831                 goto out;
832         }
833
834         if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
835         {
836                 goto err;
837         }
838
839 out:
840         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
841                         "dirInfo->clientPath '%s', "
842                         "fsp->fsp_name->st.st_ex_mtime %s",
843                         dirInfo->dirpath,
844                         dirInfo->clientPath,
845                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
846         /* Success is freed in closedir. */
847         return (DIR *) dirInfo;
848 err:
849         /* Failure is freed here. */
850         DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
851                         fsp->fsp_name->base_name));
852         TALLOC_FREE(dirInfo);
853         return NULL;
854 }
855
856 /*
857  * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
858  * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
859  * filenames and CREATING_DIRNAME directory, replace this client's
860  * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
861  * directory with non suffixed.
862  *
863  * Success: return dirent
864  * End of data: return NULL
865  * Failure: set errno, return NULL
866  */
867 static struct dirent *mh_readdir(vfs_handle_struct *handle,
868                 DIR *dirp,
869                 SMB_STRUCT_STAT *sbuf)
870 {
871         mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
872         struct dirent *d = NULL;
873         int skip;
874
875         DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
876
877         DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
878                               "dirInfo->clientPath '%s', "
879                               "dirInfo->isInMediaFiles '%s', "
880                               "dirInfo->clientMDBFilename '%s', "
881                               "dirInfo->clientPMRFilename '%s', "
882                               "dirInfo->clientCreatingDirname '%s'\n",
883                               dirInfo->dirpath,
884                               dirInfo->clientPath,
885                               dirInfo->isInMediaFiles ? "True" : "False",
886                               dirInfo->clientMDBFilename,
887                               dirInfo->clientPMRFilename,
888                               dirInfo->clientCreatingDirname));
889
890         if (! dirInfo->isInMediaFiles)
891         {
892                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
893                 goto out;
894         }
895
896         do
897         {
898                 const char* dname;
899                 bool isAppleDouble;
900
901                 skip = False;
902                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
903
904                 if (d == NULL)
905                 {
906                         break;
907                 }
908
909                 /* ignore apple double prefix for logic below */
910                 if (is_apple_double(d->d_name))
911                 {
912                         dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
913                         isAppleDouble = True;
914                 }
915                 else
916                 {
917                         dname = d->d_name;
918                         isAppleDouble = False;
919                 }
920
921                 /* skip Avid-special files with no client suffix */
922                 if (
923                         strcmp(dname, MDB_FILENAME) == 0
924                         ||
925                         strcmp(dname, PMR_FILENAME) == 0
926                         ||
927                         strcmp(dname, CREATING_DIRNAME) == 0
928                 )
929                 {
930                         skip = True;
931                 }
932                 /* chop client suffix off this client's suffixed files */
933                 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
934                 {
935                         if (isAppleDouble)
936                         {
937                                 d->d_name[MDB_FILENAME_LEN
938                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
939                         }
940                         else
941                         {
942                                 d->d_name[MDB_FILENAME_LEN] = '\0';
943                         }
944                 }
945                 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
946                 {
947                         if (isAppleDouble)
948                         {
949                                 d->d_name[PMR_FILENAME_LEN
950                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
951                         }
952                         else
953                         {
954                                 d->d_name[PMR_FILENAME_LEN] = '\0';
955                         }
956                 }
957                 else if (strcmp(dname, dirInfo->clientCreatingDirname)
958                                 == 0)
959                 {
960                         if (isAppleDouble)
961                         {
962                                 d->d_name[CREATING_DIRNAME_LEN
963                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
964                         }
965                         else
966                         {
967                                 d->d_name[CREATING_DIRNAME_LEN] = '\0';
968                         }
969                 }
970                 /*
971                  * Anything that starts as an Avid-special file
972                  * that's made it this far should be skipped.  This
973                  * is different from the original behaviour, which
974                  * only skipped other client's suffixed files.
975                  */
976                 else if (
977                         strncmp(MDB_FILENAME, dname,
978                                 MDB_FILENAME_LEN) == 0
979                         ||
980                         strncmp(PMR_FILENAME, dname,
981                                 PMR_FILENAME_LEN) == 0
982                         ||
983                         strncmp(CREATING_DIRNAME, dname,
984                                 CREATING_DIRNAME_LEN) == 0
985                 )
986                 {
987                         skip = True;
988                 }
989         }
990         while (skip);
991
992 out:
993         DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
994         return d;
995 }
996
997 /*
998  * Success: no success result defined.
999  * Failure: no failure result defined.
1000  */
1001 static void mh_seekdir(vfs_handle_struct *handle,
1002                 DIR *dirp,
1003                 long offset)
1004 {
1005         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1006         SMB_VFS_NEXT_SEEKDIR(handle,
1007                         ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1008 }
1009
1010 /*
1011  * Success: return long
1012  * Failure: no failure result defined.
1013  */
1014 static long mh_telldir(vfs_handle_struct *handle,
1015                 DIR *dirp)
1016 {
1017         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1018         return SMB_VFS_NEXT_TELLDIR(handle,
1019                         ((mh_dirinfo_struct*)dirp)->dirstream);
1020 }
1021
1022 /*
1023  * Success: no success result defined.
1024  * Failure: no failure result defined.
1025  */
1026 static void mh_rewinddir(vfs_handle_struct *handle,
1027                 DIR *dirp)
1028 {
1029         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1030         SMB_VFS_NEXT_REWINDDIR(handle,
1031                         ((mh_dirinfo_struct*)dirp)->dirstream);
1032 }
1033
1034 /*
1035  * Success: return 0
1036  * Failure: set errno, return -1
1037  */
1038 static int mh_mkdir(vfs_handle_struct *handle,
1039                 const char *path,
1040                 mode_t mode)
1041 {
1042         int status;
1043         char *clientPath;
1044         TALLOC_CTX *ctx;
1045
1046
1047         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1048
1049         if (!is_in_media_files(path))
1050         {
1051                 status = SMB_VFS_NEXT_MKDIR(handle, path, mode);
1052                 goto out;
1053         }
1054
1055         clientPath = NULL;
1056         ctx = talloc_tos();
1057
1058         if ((status = alloc_get_client_path(handle, ctx,
1059                                 path,
1060                                 &clientPath)))
1061         {
1062                 goto err;
1063         }
1064
1065         status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
1066 err:
1067         TALLOC_FREE(clientPath);
1068 out:
1069         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1070         return status;
1071 }
1072
1073 /*
1074  * Success: return 0
1075  * Failure: set errno, return -1
1076  */
1077 static int mh_rmdir(vfs_handle_struct *handle,
1078                 const char *path)
1079 {
1080         int status;
1081         char *clientPath;
1082         TALLOC_CTX *ctx;
1083
1084
1085         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1086
1087         if (!is_in_media_files(path))
1088         {
1089                 status = SMB_VFS_NEXT_RMDIR(handle, path);
1090                 goto out;
1091         }
1092
1093         clientPath = NULL;
1094         ctx = talloc_tos();
1095
1096         if ((status = alloc_get_client_path(handle, ctx,
1097                                 path,
1098                                 &clientPath)))
1099         {
1100                 goto err;
1101         }
1102
1103         status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
1104 err:
1105         TALLOC_FREE(clientPath);
1106 out:
1107         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1108         return status;
1109 }
1110
1111 /*
1112  * Success: return 0
1113  * Failure: set errno, return -1
1114  */
1115 static int mh_closedir(vfs_handle_struct *handle,
1116                 DIR *dirp)
1117 {
1118         DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1119
1120         DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1121         // Will this talloc_free destroy realdirp?
1122         TALLOC_FREE(dirp);
1123
1124         DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1125         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1126 }
1127
1128 /*
1129  * Success: no success result defined.
1130  * Failure: no failure result defined.
1131  */
1132 static void mh_init_search_op(vfs_handle_struct *handle,
1133                 DIR *dirp)
1134 {
1135         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1136         SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1137                         ((mh_dirinfo_struct*)dirp)->dirstream);
1138 }
1139
1140 /*
1141  * Success: return non-negative file descriptor
1142  * Failure: set errno, return -1
1143  */
1144 static int mh_open(vfs_handle_struct *handle,
1145                 struct smb_filename *smb_fname,
1146                 files_struct *fsp,
1147                 int flags,
1148                 mode_t mode)
1149 {
1150         int ret;
1151         struct smb_filename *clientFname;
1152         TALLOC_CTX *ctx;
1153
1154
1155         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1156                               smb_fname->base_name));
1157
1158         if (!is_in_media_files(smb_fname->base_name))
1159         {
1160                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1161                                 mode);
1162                 goto out;
1163         }
1164
1165         clientFname = NULL;
1166         ctx = talloc_tos();
1167
1168         if(alloc_get_client_smb_fname(handle, ctx,
1169                                 smb_fname,
1170                                 &clientFname))
1171         {
1172                 ret = -1;
1173                 goto err;
1174         }
1175
1176         // What about fsp->fsp_name?
1177         // We also have to get correct stat info into fsp and smb_fname
1178         // for DB files, don't we?
1179
1180         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1181                         "smb_fname->st.st_ex_mtime %s"
1182                         "               fsp->fsp_name->st.st_ex_mtime %s",
1183                         smb_fname->base_name,
1184                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1185                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1186
1187         ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1188 err:
1189         TALLOC_FREE(clientFname);
1190 out:
1191         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1192                                 smb_fname->base_name));
1193         return ret;
1194 }
1195
1196 /*
1197  * Success: return non-negative file descriptor
1198  * Failure: set errno, return -1
1199  */
1200 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1201                 struct smb_request *req,
1202                 uint16_t root_dir_fid,
1203                 struct smb_filename *smb_fname,
1204                 uint32_t access_mask,
1205                 uint32_t share_access,
1206                 uint32_t create_disposition,
1207                 uint32_t create_options,
1208                 uint32_t file_attributes,
1209                 uint32_t oplock_request,
1210                 uint64_t allocation_size,
1211                 uint32_t private_flags,
1212                 struct security_descriptor *sd,
1213                 struct ea_list *ea_list,
1214                 files_struct **result_fsp,
1215                 int *pinfo)
1216 {
1217         NTSTATUS status;
1218         struct smb_filename *clientFname;
1219         TALLOC_CTX *ctx;
1220
1221
1222         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1223                                 smb_fname->base_name));
1224         if (!is_in_media_files(smb_fname->base_name))
1225         {
1226                 status = SMB_VFS_NEXT_CREATE_FILE(
1227                         handle,
1228                         req,
1229                         root_dir_fid,
1230                         smb_fname,
1231                         access_mask,
1232                         share_access,
1233                         create_disposition,
1234                         create_options,
1235                         file_attributes,
1236                         oplock_request,
1237                         allocation_size,
1238                         private_flags,
1239                         sd,
1240                         ea_list,
1241                         result_fsp,
1242                         pinfo);
1243                 goto out;
1244         }
1245
1246         clientFname = NULL;
1247         ctx = talloc_tos();
1248
1249         if (alloc_get_client_smb_fname(handle, ctx,
1250                                 smb_fname,
1251                                 &clientFname))
1252         {
1253                 status = map_nt_error_from_unix(errno);
1254                 goto err;
1255         }
1256
1257         /* This only creates files, so we don't have to worry about
1258          * our fake directory stat'ing here.
1259          */
1260         // But we still need to route stat calls for DB files
1261         // properly, right?
1262         status = SMB_VFS_NEXT_CREATE_FILE(
1263                 handle,
1264                 req,
1265                 root_dir_fid,
1266                 clientFname,
1267                 access_mask,
1268                 share_access,
1269                 create_disposition,
1270                 create_options,
1271                 file_attributes,
1272                 oplock_request,
1273                 allocation_size,
1274                 private_flags,
1275                 sd,
1276                 ea_list,
1277                 result_fsp,
1278                 pinfo);
1279 err:
1280         TALLOC_FREE(clientFname);
1281 out:
1282         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1283                 "smb_fname->st.st_ex_mtime %s"
1284                 "               fsp->fsp_name->st.st_ex_mtime %s",
1285                 smb_fname->base_name,
1286                 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1287                 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1288                 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1289                 "No fsp time\n"));
1290         return status;
1291 }
1292
1293 /*
1294  * Success: return 0
1295  * Failure: set errno, return -1
1296  */
1297 static int mh_rename(vfs_handle_struct *handle,
1298                 const struct smb_filename *smb_fname_src,
1299                 const struct smb_filename *smb_fname_dst)
1300 {
1301         int status;
1302         struct smb_filename *srcClientFname;
1303         struct smb_filename *dstClientFname;
1304         TALLOC_CTX *ctx;
1305
1306
1307         DEBUG(MH_INFO_DEBUG, ("Entering with "
1308                               "smb_fname_src->base_name '%s', "
1309                               "smb_fname_dst->base_name '%s'\n",
1310                               smb_fname_src->base_name,
1311                               smb_fname_dst->base_name));
1312
1313         if (!is_in_media_files(smb_fname_src->base_name)
1314                                 &&
1315                         !is_in_media_files(smb_fname_dst->base_name))
1316         {
1317                 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1318                                 smb_fname_dst);
1319                 goto out;
1320         }
1321
1322         srcClientFname = NULL;
1323         dstClientFname = NULL;
1324         ctx = talloc_tos();
1325
1326         if ((status = alloc_get_client_smb_fname(handle, ctx,
1327                                 smb_fname_src,
1328                                 &srcClientFname)))
1329         {
1330                 goto err;
1331         }
1332
1333         if ((status = alloc_get_client_smb_fname(handle, ctx,
1334                                 smb_fname_dst,
1335                                 &dstClientFname)))
1336         {
1337                 goto err;
1338         }
1339
1340         status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1341                                 dstClientFname);
1342 err:
1343         TALLOC_FREE(dstClientFname);
1344         TALLOC_FREE(srcClientFname);
1345 out:
1346         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1347                                 " smb_fname_dst->base_name '%s'\n",
1348                                 smb_fname_src->base_name,
1349                                 smb_fname_dst->base_name));
1350         return status;
1351 }
1352
1353 /*
1354  * Success: return 0
1355  * Failure: set errno, return -1
1356  */
1357 static int mh_stat(vfs_handle_struct *handle,
1358                 struct smb_filename *smb_fname)
1359 {
1360         int status = 0;
1361         struct smb_filename *clientFname;
1362         TALLOC_CTX *ctx;
1363
1364
1365         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1366                               smb_fname->base_name));
1367
1368         if (!is_in_media_files(smb_fname->base_name))
1369         {
1370                 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1371                 goto out;
1372         }
1373
1374         clientFname = NULL;
1375         ctx = talloc_tos();
1376
1377         if ((status = alloc_get_client_smb_fname(handle, ctx,
1378                                 smb_fname,
1379                                 &clientFname)))
1380         {
1381                 goto err;
1382         }
1383         DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1384                                 clientFname->base_name));
1385         if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1386         {
1387                 goto err;
1388         }
1389         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1390         {
1391                 goto err;
1392         }
1393
1394         /* Unlike functions with const smb_filename, we have to
1395          * modify smb_fname itself to pass our info back up.
1396          */
1397         DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1398                                 "from clientFname '%s'\n",
1399                                 smb_fname->base_name,
1400                                 clientFname->base_name));
1401         smb_fname->st = clientFname->st;
1402 err:
1403         TALLOC_FREE(clientFname);
1404 out:
1405         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1406                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1407         return status;
1408 }
1409
1410 /*
1411  * Success: return 0
1412  * Failure: set errno, return -1
1413  */
1414 static int mh_lstat(vfs_handle_struct *handle,
1415                 struct smb_filename *smb_fname)
1416 {
1417         int status = 0;
1418         struct smb_filename *clientFname;
1419         TALLOC_CTX *ctx;
1420
1421         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1422                               smb_fname->base_name));
1423
1424         if (!is_in_media_files(smb_fname->base_name))
1425         {
1426                 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1427                 goto out;
1428         }
1429
1430         clientFname = NULL;
1431         ctx = talloc_tos();
1432
1433         if ((status = alloc_get_client_smb_fname(handle, ctx,
1434                                 smb_fname,
1435                                 &clientFname)))
1436         {
1437                 goto err;
1438         }
1439         if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1440         {
1441                 goto err;
1442         }
1443
1444         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1445         {
1446                 goto err;
1447         }
1448         /* Unlike functions with const smb_filename, we have to
1449          * modify smb_fname itself to pass our info back up.
1450          */
1451         smb_fname->st = clientFname->st;
1452 err:
1453         TALLOC_FREE(clientFname);
1454 out:
1455         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1456                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1457         return status;
1458 }
1459
1460 /*
1461  * Success: return 0
1462  * Failure: set errno, return -1
1463  */
1464 static int mh_fstat(vfs_handle_struct *handle,
1465                 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1466 {
1467         int status = 0;
1468
1469         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1470                                 "'%s'\n", fsp_str_dbg(fsp)));
1471
1472         if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1473         {
1474                 goto out;
1475         }
1476
1477         if (fsp->fsp_name == NULL
1478                         || !is_in_media_files(fsp->fsp_name->base_name))
1479         {
1480                 goto out;
1481         }
1482
1483         if ((status = mh_stat(handle, fsp->fsp_name)))
1484         {
1485                 goto out;
1486         }
1487
1488         *sbuf = fsp->fsp_name->st;
1489 out:
1490         DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1491                         "%s",
1492                         fsp->fsp_name != NULL ?
1493                                 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1494                                 "0"));
1495         return status;
1496 }
1497
1498 /*
1499  * Success: return 0
1500  * Failure: set errno, return -1
1501  */
1502 static int mh_unlink(vfs_handle_struct *handle,
1503                 const struct smb_filename *smb_fname)
1504 {
1505         int status;
1506         struct smb_filename *clientFname;
1507         TALLOC_CTX *ctx;
1508
1509         DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1510         if (!is_in_media_files(smb_fname->base_name))
1511         {
1512                 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1513                 goto out;
1514         }
1515
1516         clientFname = NULL;
1517         ctx = talloc_tos();
1518
1519         if ((status = alloc_get_client_smb_fname(handle, ctx,
1520                                 smb_fname,
1521                                 &clientFname)))
1522         {
1523                 goto err;
1524         }
1525
1526         status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1527 err:
1528         TALLOC_FREE(clientFname);
1529 out:
1530         return status;
1531 }
1532
1533 /*
1534  * Success: return 0
1535  * Failure: set errno, return -1
1536  */
1537 static int mh_chmod(vfs_handle_struct *handle,
1538                 const char *path,
1539                 mode_t mode)
1540 {
1541         int status;
1542         char *clientPath;
1543         TALLOC_CTX *ctx;
1544
1545         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1546         if (!is_in_media_files(path))
1547         {
1548                 status = SMB_VFS_NEXT_CHMOD(handle, path, mode);
1549                 goto out;
1550         }
1551
1552         clientPath = NULL;
1553         ctx = talloc_tos();
1554
1555         if ((status = alloc_get_client_path(handle, ctx,
1556                                 path,
1557                                 &clientPath)))
1558         {
1559                 goto err;
1560         }
1561
1562         status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
1563 err:
1564         TALLOC_FREE(clientPath);
1565 out:
1566         return status;
1567 }
1568
1569 /*
1570  * Success: return 0
1571  * Failure: set errno, return -1
1572  */
1573 static int mh_chown(vfs_handle_struct *handle,
1574                 const char *path,
1575                 uid_t uid,
1576                 gid_t gid)
1577 {
1578         int status;
1579         char *clientPath;
1580         TALLOC_CTX *ctx;
1581
1582         DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1583         if (!is_in_media_files(path))
1584         {
1585                 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1586                 goto out;
1587         }
1588
1589         clientPath = NULL;
1590         ctx = talloc_tos();
1591
1592         if ((status = alloc_get_client_path(handle, ctx,
1593                                 path,
1594                                 &clientPath)))
1595         {
1596                 goto err;
1597         }
1598
1599         status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1600 err:
1601         TALLOC_FREE(clientPath);
1602 out:
1603         return status;
1604 }
1605
1606 /*
1607  * Success: return 0
1608  * Failure: set errno, return -1
1609  */
1610 static int mh_lchown(vfs_handle_struct *handle,
1611                 const char *path,
1612                 uid_t uid,
1613                 gid_t gid)
1614 {
1615         int status;
1616         char *clientPath;
1617         TALLOC_CTX *ctx;
1618
1619         DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1620         if (!is_in_media_files(path))
1621         {
1622                 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1623                 goto out;
1624         }
1625
1626         clientPath = NULL;
1627         ctx = talloc_tos();
1628
1629         if ((status = alloc_get_client_path(handle, ctx,
1630                                 path,
1631                                 &clientPath)))
1632         {
1633                 goto err;
1634         }
1635
1636         status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1637 err:
1638         TALLOC_FREE(clientPath);
1639 out:
1640         return status;
1641 }
1642
1643 /*
1644  * Success: return 0
1645  * Failure: set errno, return -1
1646  */
1647 static int mh_chdir(vfs_handle_struct *handle,
1648                 const char *path)
1649 {
1650         int status;
1651         char *clientPath;
1652         TALLOC_CTX *ctx;
1653
1654         DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1655         if (!is_in_media_files(path))
1656         {
1657                 status = SMB_VFS_NEXT_CHDIR(handle, path);
1658                 goto out;
1659         }
1660
1661         clientPath = NULL;
1662         ctx = talloc_tos();
1663
1664         if ((status = alloc_get_client_path(handle, ctx,
1665                                 path,
1666                                 &clientPath)))
1667         {
1668                 goto err;
1669         }
1670
1671         status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1672 err:
1673         TALLOC_FREE(clientPath);
1674 out:
1675         return status;
1676 }
1677
1678 /*
1679  * Success: return 0
1680  * Failure: set errno, return -1
1681  */
1682 static int mh_ntimes(vfs_handle_struct *handle,
1683                 const struct smb_filename *smb_fname,
1684                 struct smb_file_time *ft)
1685 {
1686         int status;
1687         struct smb_filename *clientFname;
1688         TALLOC_CTX *ctx;
1689
1690
1691         DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1692         if (!is_in_media_files(smb_fname->base_name))
1693         {
1694                 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1695                 goto out;
1696         }
1697
1698         clientFname = NULL;
1699         ctx = talloc_tos();
1700
1701         if ((status = alloc_get_client_smb_fname(handle, ctx,
1702                                 smb_fname,
1703                                 &clientFname)))
1704         {
1705                 goto err;
1706         }
1707
1708         status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1709 err:
1710         TALLOC_FREE(clientFname);
1711 out:
1712         return status;
1713 }
1714
1715 /*
1716  * Success: return 0
1717  * Failure: set errno, return -1
1718  */
1719 static int mh_symlink(vfs_handle_struct *handle,
1720                 const char *oldpath,
1721                 const char *newpath)
1722 {
1723         int status;
1724         char *oldClientPath;
1725         char *newClientPath;
1726         TALLOC_CTX *ctx;
1727
1728         DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1729         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1730         {
1731                 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1732                 goto out;
1733         }
1734
1735         oldClientPath = NULL;
1736         newClientPath = NULL;
1737         ctx = talloc_tos();
1738
1739         if ((status = alloc_get_client_path(handle, ctx,
1740                                 oldpath,
1741                                 &oldClientPath)))
1742         {
1743                 goto err;
1744         }
1745
1746         if ((status = alloc_get_client_path(handle, ctx,
1747                                 newpath,
1748                                 &newClientPath)))
1749         {
1750                 goto err;
1751         }
1752
1753         status = SMB_VFS_NEXT_SYMLINK(handle,
1754                         oldClientPath,
1755                         newClientPath);
1756
1757 err:
1758         TALLOC_FREE(newClientPath);
1759         TALLOC_FREE(oldClientPath);
1760 out:
1761         return status;
1762 }
1763
1764 /*
1765  * Success: return byte count
1766  * Failure: set errno, return -1
1767  */
1768 static int mh_readlink(vfs_handle_struct *handle,
1769                 const char *path,
1770                 char *buf,
1771                 size_t bufsiz)
1772 {
1773         int status;
1774         char *clientPath;
1775         TALLOC_CTX *ctx;
1776
1777         DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1778         if (!is_in_media_files(path))
1779         {
1780                 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1781                 goto out;
1782         }
1783
1784         clientPath = NULL;
1785         ctx = talloc_tos();
1786
1787         if ((status = alloc_get_client_path(handle, ctx,
1788                                 path,
1789                                 &clientPath)))
1790         {
1791                 goto err;
1792         }
1793
1794         status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1795 err:
1796         TALLOC_FREE(clientPath);
1797 out:
1798         return status;
1799 }
1800
1801 /*
1802  * Success: return 0
1803  * Failure: set errno, return -1
1804  */
1805 static int mh_link(vfs_handle_struct *handle,
1806                 const char *oldpath,
1807                 const char *newpath)
1808 {
1809         int status;
1810         char *oldClientPath;
1811         char *newClientPath;
1812         TALLOC_CTX *ctx;
1813
1814         DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1815         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1816         {
1817                 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1818                 goto out;
1819         }
1820
1821         oldClientPath = NULL;
1822         newClientPath = NULL;
1823         ctx = talloc_tos();
1824
1825         if ((status = alloc_get_client_path(handle, ctx,
1826                                 oldpath,
1827                                 &oldClientPath)))
1828         {
1829                 goto err;
1830         }
1831
1832         if ((status = alloc_get_client_path(handle, ctx,
1833                                 newpath,
1834                                 &newClientPath)))
1835         {
1836                 goto err;
1837         }
1838
1839         status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1840 err:
1841         TALLOC_FREE(newClientPath);
1842         TALLOC_FREE(oldClientPath);
1843 out:
1844         return status;
1845 }
1846
1847 /*
1848  * Success: return 0
1849  * Failure: set errno, return -1
1850  */
1851 static int mh_mknod(vfs_handle_struct *handle,
1852                 const char *pathname,
1853                 mode_t mode,
1854                 SMB_DEV_T dev)
1855 {
1856         int status;
1857         char *clientPath;
1858         TALLOC_CTX *ctx;
1859
1860         DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1861         if (!is_in_media_files(pathname))
1862         {
1863                 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1864                 goto out;
1865         }
1866
1867         clientPath = NULL;
1868         ctx = talloc_tos();
1869
1870         if ((status = alloc_get_client_path(handle, ctx,
1871                                 pathname,
1872                                 &clientPath)))
1873         {
1874                 goto err;
1875         }
1876
1877         status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1878 err:
1879         TALLOC_FREE(clientPath);
1880 out:
1881         return status;
1882 }
1883
1884 /*
1885  * Success: return path pointer
1886  * Failure: set errno, return NULL pointer
1887  */
1888 static char *mh_realpath(vfs_handle_struct *handle,
1889                 const char *path)
1890 {
1891         char *buf;
1892         char *clientPath;
1893         TALLOC_CTX *ctx;
1894
1895         DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1896         if (!is_in_media_files(path))
1897         {
1898                 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1899                 goto out;
1900         }
1901
1902         clientPath = NULL;
1903         ctx = talloc_tos();
1904
1905         if (alloc_get_client_path(handle, ctx,
1906                                 path,
1907                                 &clientPath))
1908         {
1909                 buf = NULL;
1910                 goto err;
1911         }
1912
1913         buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1914 err:
1915         TALLOC_FREE(clientPath);
1916 out:
1917         return buf;
1918 }
1919
1920 /*
1921  * Success: return 0
1922  * Failure: set errno, return -1
1923  */
1924 static int mh_chflags(vfs_handle_struct *handle,
1925                 const char *path,
1926                 unsigned int flags)
1927 {
1928         int status;
1929         char *clientPath;
1930         TALLOC_CTX *ctx;
1931
1932         DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1933         if (!is_in_media_files(path))
1934         {
1935                 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1936                 goto out;
1937         }
1938
1939         clientPath = NULL;
1940         ctx = talloc_tos();
1941
1942         if ((status = alloc_get_client_path(handle, ctx,
1943                                 path,
1944                                 &clientPath)))
1945         {
1946                 goto err;
1947         }
1948
1949         status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1950 err:
1951         TALLOC_FREE(clientPath);
1952 out:
1953         return status;
1954 }
1955
1956 /*
1957  * Success: return NT_STATUS_OK
1958  * Failure: return NT status error
1959  */
1960 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1961                 struct files_struct *fsp,
1962                 const char *fname,
1963                 TALLOC_CTX *ctx,
1964                 unsigned int *num_streams,
1965                 struct stream_struct **streams)
1966 {
1967         NTSTATUS status;
1968         char *clientPath;
1969         TALLOC_CTX *mem_ctx;
1970
1971         DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1972         if (!is_in_media_files(fname))
1973         {
1974                 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1975                                 ctx, num_streams, streams);
1976                 goto out;
1977         }
1978
1979         clientPath = NULL;
1980         mem_ctx = talloc_tos();
1981
1982         if (alloc_get_client_path(handle, mem_ctx,
1983                                 fname,
1984                                 &clientPath))
1985         {
1986                 status = map_nt_error_from_unix(errno);
1987                 goto err;
1988         }
1989
1990         /* This only works on files, so we don't have to worry about
1991          * our fake directory stat'ing here.
1992          */
1993         // But what does this function do, exactly?  Does it need
1994         // extra modifications for the Avid stuff?
1995         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
1996                                 ctx, num_streams, streams);
1997 err:
1998         TALLOC_FREE(clientPath);
1999 out:
2000         return status;
2001 }
2002
2003 /* Ignoring get_real_filename function because the default
2004  * doesn't do anything.
2005  */
2006
2007 /*
2008  * Success: return NT_STATUS_OK
2009  * Failure: return NT status error
2010  * In this case, "name" is a path.
2011  */
2012 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2013                               const char *name,
2014                               uint32 security_info,
2015                               TALLOC_CTX *mem_ctx,
2016                               struct security_descriptor **ppdesc)
2017 {
2018         NTSTATUS status;
2019         char *clientPath;
2020         TALLOC_CTX *ctx;
2021
2022         DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2023         if (!is_in_media_files(name))
2024         {
2025                 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name,
2026                                                  security_info,
2027                                                  mem_ctx, ppdesc);
2028                 goto out;
2029         }
2030
2031         clientPath = NULL;
2032         ctx = talloc_tos();
2033
2034         if (alloc_get_client_path(handle, ctx,
2035                                 name,
2036                                 &clientPath))
2037         {
2038                 status = map_nt_error_from_unix(errno);
2039                 goto err;
2040         }
2041
2042         status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
2043                                          security_info,
2044                                          mem_ctx, ppdesc);
2045 err:
2046         TALLOC_FREE(clientPath);
2047 out:
2048         return status;
2049 }
2050
2051 /*
2052  * Success: return 0
2053  * Failure: set errno, return -1
2054  */
2055 static int mh_chmod_acl(vfs_handle_struct *handle,
2056                 const char *path,
2057                 mode_t mode)
2058 {
2059         int status;
2060         char *clientPath;
2061         TALLOC_CTX *ctx;
2062
2063         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2064         if (!is_in_media_files(path))
2065         {
2066                 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2067                 goto out;
2068         }
2069
2070         clientPath = NULL;
2071         ctx = talloc_tos();
2072
2073         if ((status = alloc_get_client_path(handle, ctx,
2074                                 path,
2075                                 &clientPath)))
2076         {
2077                 goto err;
2078         }
2079
2080         status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2081 err:
2082         TALLOC_FREE(clientPath);
2083 out:
2084         return status;
2085 }
2086
2087 /*
2088  * Success: return acl pointer
2089  * Failure: set errno, return NULL
2090  */
2091 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2092                                      const char *path_p,
2093                                      SMB_ACL_TYPE_T type,
2094                                      TALLOC_CTX *mem_ctx)
2095 {
2096         SMB_ACL_T ret;
2097         char *clientPath;
2098         TALLOC_CTX *ctx;
2099
2100         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2101         if (!is_in_media_files(path_p))
2102         {
2103                 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2104                 goto out;
2105         }
2106
2107         clientPath = NULL;
2108         ctx = talloc_tos();
2109
2110         if (alloc_get_client_path(handle, ctx,
2111                                 path_p,
2112                                 &clientPath))
2113         {
2114                 ret = NULL;
2115                 goto err;
2116         }
2117
2118         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2119 err:
2120         TALLOC_FREE(clientPath);
2121 out:
2122         return ret;
2123 }
2124
2125 /*
2126  * Success: return 0
2127  * Failure: set errno, return -1
2128  * In this case, "name" is a path.
2129  */
2130 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2131                 const char *name,
2132                 SMB_ACL_TYPE_T acltype,
2133                 SMB_ACL_T theacl)
2134 {
2135         int status;
2136         char *clientPath;
2137         TALLOC_CTX *ctx;
2138
2139         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2140         if (!is_in_media_files(name))
2141         {
2142                 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2143                                 acltype, theacl);
2144                 goto out;
2145         }
2146
2147         clientPath = NULL;
2148         ctx = talloc_tos();
2149
2150         if ((status = alloc_get_client_path(handle, ctx,
2151                                 name,
2152                                 &clientPath)))
2153         {
2154                 goto err;
2155         }
2156
2157         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2158                         acltype, theacl);
2159 err:
2160         TALLOC_FREE(clientPath);
2161 out:
2162         return status;
2163 }
2164
2165 /*
2166  * Success: return 0
2167  * Failure: set errno, return -1
2168  */
2169 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2170                 const char *path)
2171 {
2172         int status;
2173         char *clientPath;
2174         TALLOC_CTX *ctx;
2175
2176         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2177         if (!is_in_media_files(path))
2178         {
2179                 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2180                                 path);
2181                 goto out;
2182         }
2183
2184         clientPath = NULL;
2185         ctx = talloc_tos();
2186
2187         if ((status = alloc_get_client_path(handle, ctx,
2188                                 path,
2189                                 &clientPath)))
2190         {
2191                 goto err;
2192         }
2193
2194         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2195 err:
2196         TALLOC_FREE(clientPath);
2197 out:
2198         return status;
2199 }
2200
2201 /*
2202  * Success: return positive number
2203  * Failure: set errno, return -1
2204  * In this case, "name" is an attr name.
2205  */
2206 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2207                 const char *path,
2208                 const char *name,
2209                 void *value,
2210                 size_t size)
2211 {
2212         ssize_t ret;
2213         char *clientPath;
2214         TALLOC_CTX *ctx;
2215
2216         DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2217         if (!is_in_media_files(path))
2218         {
2219                 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2220                                 size);
2221                 goto out;
2222         }
2223
2224         clientPath = NULL;
2225         ctx = talloc_tos();
2226
2227         if (alloc_get_client_path(handle, ctx,
2228                                 path,
2229                                 &clientPath))
2230         {
2231                 ret = -1;
2232                 goto err;
2233         }
2234
2235         ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2236 err:
2237         TALLOC_FREE(clientPath);
2238 out:
2239         return ret;
2240 }
2241
2242 /*
2243  * Success: return positive number
2244  * Failure: set errno, return -1
2245  */
2246 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2247                 const char *path,
2248                 char *list,
2249                 size_t size)
2250 {
2251         ssize_t ret;
2252         char *clientPath;
2253         TALLOC_CTX *ctx;
2254
2255         DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2256         if (!is_in_media_files(path))
2257         {
2258                 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2259                 goto out;
2260         }
2261
2262         clientPath = NULL;
2263         ctx = talloc_tos();
2264
2265         if (alloc_get_client_path(handle, ctx,
2266                                 path,
2267                                 &clientPath))
2268         {
2269                 ret = -1;
2270                 goto err;
2271         }
2272
2273         ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2274 err:
2275         TALLOC_FREE(clientPath);
2276 out:
2277         return ret;
2278 }
2279
2280 /*
2281  * Success: return 0
2282  * Failure: set errno, return -1
2283  * In this case, "name" is an attr name.
2284  */
2285 static int mh_removexattr(struct vfs_handle_struct *handle,
2286                 const char *path,
2287                 const char *name)
2288 {
2289         int status;
2290         char *clientPath;
2291         TALLOC_CTX *ctx;
2292
2293         DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2294         if (!is_in_media_files(path))
2295         {
2296                 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2297                 goto out;
2298         }
2299
2300         clientPath = NULL;
2301         ctx = talloc_tos();
2302
2303         if ((status = alloc_get_client_path(handle, ctx,
2304                                 path,
2305                                 &clientPath)))
2306         {
2307                 goto err;
2308         }
2309
2310         status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2311 err:
2312         TALLOC_FREE(clientPath);
2313 out:
2314         return status;
2315 }
2316
2317 /*
2318  * Success: return 0
2319  * Failure: set errno, return -1
2320  * In this case, "name" is an attr name.
2321  */
2322 static int mh_setxattr(struct vfs_handle_struct *handle,
2323                 const char *path,
2324                 const char *name,
2325                 const void *value,
2326                 size_t size,
2327                 int flags)
2328 {
2329         int status;
2330         char *clientPath;
2331         TALLOC_CTX *ctx;
2332
2333         DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2334         if (!is_in_media_files(path))
2335         {
2336                 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2337                                 size, flags);
2338                 goto out;
2339         }
2340
2341         clientPath = NULL;
2342         ctx = talloc_tos();
2343
2344         if ((status = alloc_get_client_path(handle, ctx,
2345                                 path,
2346                                 &clientPath)))
2347         {
2348                 goto err;
2349         }
2350
2351         status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2352                         size, flags);
2353 err:
2354         TALLOC_FREE(clientPath);
2355 out:
2356         return status;
2357 }
2358
2359 /*
2360  * Success: return true
2361  * Failure: set errno, return false
2362  */
2363 static bool mh_is_offline(struct vfs_handle_struct *handle,
2364                 const struct smb_filename *fname,
2365                 SMB_STRUCT_STAT *sbuf)
2366 {
2367         // check if sbuf is modified further down the chain.
2368         bool ret;
2369         struct smb_filename *clientFname;
2370         TALLOC_CTX *ctx;
2371
2372         DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2373         if (!is_in_media_files(fname->base_name))
2374         {
2375                 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2376                 goto out;
2377         }
2378
2379         clientFname = NULL;
2380         ctx = talloc_tos();
2381
2382         if(alloc_get_client_smb_fname(handle, ctx,
2383                                 fname,
2384                                 &clientFname))
2385         {
2386                 ret = -1;
2387                 goto err;
2388         }
2389
2390         ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2391 err:
2392         TALLOC_FREE(clientFname);
2393 out:
2394         return ret;
2395 }
2396
2397 /*
2398  * Success: return 0 (?)
2399  * Failure: set errno, return -1
2400  */
2401 static int mh_set_offline(struct vfs_handle_struct *handle,
2402                 const struct smb_filename *fname)
2403 {
2404         int status;
2405         struct smb_filename *clientFname;
2406         TALLOC_CTX *ctx;
2407
2408         DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2409         if (!is_in_media_files(fname->base_name))
2410         {
2411                 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2412                 goto out;
2413         }
2414
2415         clientFname = NULL;
2416         ctx = talloc_tos();
2417
2418         if ((status = alloc_get_client_smb_fname(handle, ctx,
2419                                 fname,
2420                                 &clientFname)))
2421         {
2422                 goto err;
2423         }
2424
2425         status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2426 err:
2427         TALLOC_FREE(clientFname);
2428 out:
2429         return status;
2430 }
2431
2432 /* VFS operations structure */
2433
2434 static struct vfs_fn_pointers vfs_mh_fns = {
2435         /* Disk operations */
2436
2437         .statvfs_fn = mh_statvfs,
2438
2439         /* Directory operations */
2440
2441         .opendir_fn = mh_opendir,
2442         .fdopendir_fn = mh_fdopendir,
2443         .readdir_fn = mh_readdir,
2444         .seekdir_fn = mh_seekdir,
2445         .telldir_fn = mh_telldir,
2446         .rewind_dir_fn = mh_rewinddir,
2447         .mkdir_fn = mh_mkdir,
2448         .rmdir_fn = mh_rmdir,
2449         .closedir_fn = mh_closedir,
2450         .init_search_op_fn = mh_init_search_op,
2451
2452         /* File operations */
2453
2454         .open_fn = mh_open,
2455         .create_file_fn = mh_create_file,
2456         .rename_fn = mh_rename,
2457         .stat_fn = mh_stat,
2458         .lstat_fn = mh_lstat,
2459         .fstat_fn = mh_fstat,
2460         .unlink_fn = mh_unlink,
2461         .chmod_fn = mh_chmod,
2462         .chown_fn = mh_chown,
2463         .lchown_fn = mh_lchown,
2464         .chdir_fn = mh_chdir,
2465         .ntimes_fn = mh_ntimes,
2466         .symlink_fn = mh_symlink,
2467         .readlink_fn = mh_readlink,
2468         .link_fn = mh_link,
2469         .mknod_fn = mh_mknod,
2470         .realpath_fn = mh_realpath,
2471         .chflags_fn = mh_chflags,
2472         .streaminfo_fn = mh_streaminfo,
2473
2474         /* NT ACL operations. */
2475
2476         .get_nt_acl_fn = mh_get_nt_acl,
2477
2478         /* POSIX ACL operations. */
2479
2480         .chmod_acl_fn = mh_chmod_acl,
2481
2482         .sys_acl_get_file_fn = mh_sys_acl_get_file,
2483         .sys_acl_set_file_fn = mh_sys_acl_set_file,
2484         .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2485
2486         /* EA operations. */
2487         .getxattr_fn = mh_getxattr,
2488         .listxattr_fn = mh_listxattr,
2489         .removexattr_fn = mh_removexattr,
2490         .setxattr_fn = mh_setxattr,
2491
2492         /* aio operations */
2493
2494         /* offline operations */
2495         .is_offline_fn = mh_is_offline,
2496         .set_offline_fn = mh_set_offline
2497 };
2498
2499 NTSTATUS vfs_media_harmony_init(void);
2500 NTSTATUS vfs_media_harmony_init(void)
2501 {
2502         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2503                                 "media_harmony", &vfs_mh_fns);
2504         if (!NT_STATUS_IS_OK(ret))
2505         {
2506                 goto out;
2507         }
2508
2509         vfs_mh_debug_level = debug_add_class("media_harmony");
2510
2511         if (vfs_mh_debug_level == -1) {
2512                 vfs_mh_debug_level = DBGC_VFS;
2513                 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2514                                 "debugging class.\n"));
2515         } else {
2516                 DEBUG(3, ("media_harmony_init: Debug class number of "
2517                                 "'media_harmony': %d\n",
2518                                 vfs_mh_debug_level));
2519         }
2520
2521 out:
2522         return ret;
2523 }