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