VFS: Modify chmod to take a const struct smb_filename * instead of const char *
[sfrench/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* 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 struct smb_filename *smb_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",
770                 smb_fname->base_name));
771
772         if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo))
773         {
774                 goto err;
775         }
776
777         if (!dirInfo->isInMediaFiles)
778         {
779                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
780                         smb_fname, mask, attr);
781         } else {
782                 struct smb_filename *smb_fname_clientpath =
783                                 synthetic_smb_fname(talloc_tos(),
784                                         dirInfo->clientPath,
785                                         NULL,
786                                         NULL);
787                 if (smb_fname_clientpath == NULL) {
788                         goto err;
789                 }
790
791                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
792                         smb_fname_clientpath, mask, attr);
793                 TALLOC_FREE(smb_fname_clientpath);
794         }
795
796         if (dirInfo->dirstream == NULL) {
797                 goto err;
798         }
799
800         /* Success is freed in closedir. */
801         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
802                                 "dirInfo->clientPath '%s'\n",
803                                 dirInfo->dirpath,
804                                 dirInfo->clientPath));
805         return (DIR*)dirInfo;
806 err:
807         /* Failure is freed here. */
808         DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n",
809                 smb_fname->base_name));
810         TALLOC_FREE(dirInfo);
811         return NULL;
812 }
813
814 static DIR *mh_fdopendir(vfs_handle_struct *handle,
815                 files_struct *fsp,
816                 const char *mask,
817                 uint32_t attr)
818 {
819         struct mh_dirinfo_struct *dirInfo = NULL;
820         DIR *dirstream;
821
822         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
823                               fsp->fsp_name->base_name));
824
825         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
826         if (!dirstream)
827         {
828                 goto err;
829         }
830
831         if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
832                                         &dirInfo))
833         {
834                 goto err;
835         }
836
837         dirInfo->dirstream = dirstream;
838
839         if (! dirInfo->isInMediaFiles) {
840                 goto out;
841         }
842
843         if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
844         {
845                 goto err;
846         }
847
848 out:
849         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
850                         "dirInfo->clientPath '%s', "
851                         "fsp->fsp_name->st.st_ex_mtime %s",
852                         dirInfo->dirpath,
853                         dirInfo->clientPath,
854                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
855         /* Success is freed in closedir. */
856         return (DIR *) dirInfo;
857 err:
858         /* Failure is freed here. */
859         DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
860                         fsp->fsp_name->base_name));
861         TALLOC_FREE(dirInfo);
862         return NULL;
863 }
864
865 /*
866  * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
867  * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
868  * filenames and CREATING_DIRNAME directory, replace this client's
869  * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
870  * directory with non suffixed.
871  *
872  * Success: return dirent
873  * End of data: return NULL
874  * Failure: set errno, return NULL
875  */
876 static struct dirent *mh_readdir(vfs_handle_struct *handle,
877                 DIR *dirp,
878                 SMB_STRUCT_STAT *sbuf)
879 {
880         mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
881         struct dirent *d = NULL;
882         int skip;
883
884         DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
885
886         DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
887                               "dirInfo->clientPath '%s', "
888                               "dirInfo->isInMediaFiles '%s', "
889                               "dirInfo->clientMDBFilename '%s', "
890                               "dirInfo->clientPMRFilename '%s', "
891                               "dirInfo->clientCreatingDirname '%s'\n",
892                               dirInfo->dirpath,
893                               dirInfo->clientPath,
894                               dirInfo->isInMediaFiles ? "True" : "False",
895                               dirInfo->clientMDBFilename,
896                               dirInfo->clientPMRFilename,
897                               dirInfo->clientCreatingDirname));
898
899         if (! dirInfo->isInMediaFiles)
900         {
901                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
902                 goto out;
903         }
904
905         do
906         {
907                 const char* dname;
908                 bool isAppleDouble;
909
910                 skip = False;
911                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
912
913                 if (d == NULL)
914                 {
915                         break;
916                 }
917
918                 /* ignore apple double prefix for logic below */
919                 if (is_apple_double(d->d_name))
920                 {
921                         dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
922                         isAppleDouble = True;
923                 }
924                 else
925                 {
926                         dname = d->d_name;
927                         isAppleDouble = False;
928                 }
929
930                 /* skip Avid-special files with no client suffix */
931                 if (
932                         strcmp(dname, MDB_FILENAME) == 0
933                         ||
934                         strcmp(dname, PMR_FILENAME) == 0
935                         ||
936                         strcmp(dname, CREATING_DIRNAME) == 0
937                 )
938                 {
939                         skip = True;
940                 }
941                 /* chop client suffix off this client's suffixed files */
942                 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
943                 {
944                         if (isAppleDouble)
945                         {
946                                 d->d_name[MDB_FILENAME_LEN
947                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
948                         }
949                         else
950                         {
951                                 d->d_name[MDB_FILENAME_LEN] = '\0';
952                         }
953                 }
954                 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
955                 {
956                         if (isAppleDouble)
957                         {
958                                 d->d_name[PMR_FILENAME_LEN
959                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
960                         }
961                         else
962                         {
963                                 d->d_name[PMR_FILENAME_LEN] = '\0';
964                         }
965                 }
966                 else if (strcmp(dname, dirInfo->clientCreatingDirname)
967                                 == 0)
968                 {
969                         if (isAppleDouble)
970                         {
971                                 d->d_name[CREATING_DIRNAME_LEN
972                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
973                         }
974                         else
975                         {
976                                 d->d_name[CREATING_DIRNAME_LEN] = '\0';
977                         }
978                 }
979                 /*
980                  * Anything that starts as an Avid-special file
981                  * that's made it this far should be skipped.  This
982                  * is different from the original behaviour, which
983                  * only skipped other client's suffixed files.
984                  */
985                 else if (
986                         strncmp(MDB_FILENAME, dname,
987                                 MDB_FILENAME_LEN) == 0
988                         ||
989                         strncmp(PMR_FILENAME, dname,
990                                 PMR_FILENAME_LEN) == 0
991                         ||
992                         strncmp(CREATING_DIRNAME, dname,
993                                 CREATING_DIRNAME_LEN) == 0
994                 )
995                 {
996                         skip = True;
997                 }
998         }
999         while (skip);
1000
1001 out:
1002         DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
1003         return d;
1004 }
1005
1006 /*
1007  * Success: no success result defined.
1008  * Failure: no failure result defined.
1009  */
1010 static void mh_seekdir(vfs_handle_struct *handle,
1011                 DIR *dirp,
1012                 long offset)
1013 {
1014         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1015         SMB_VFS_NEXT_SEEKDIR(handle,
1016                         ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1017 }
1018
1019 /*
1020  * Success: return long
1021  * Failure: no failure result defined.
1022  */
1023 static long mh_telldir(vfs_handle_struct *handle,
1024                 DIR *dirp)
1025 {
1026         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1027         return SMB_VFS_NEXT_TELLDIR(handle,
1028                         ((mh_dirinfo_struct*)dirp)->dirstream);
1029 }
1030
1031 /*
1032  * Success: no success result defined.
1033  * Failure: no failure result defined.
1034  */
1035 static void mh_rewinddir(vfs_handle_struct *handle,
1036                 DIR *dirp)
1037 {
1038         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1039         SMB_VFS_NEXT_REWINDDIR(handle,
1040                         ((mh_dirinfo_struct*)dirp)->dirstream);
1041 }
1042
1043 /*
1044  * Success: return 0
1045  * Failure: set errno, return -1
1046  */
1047 static int mh_mkdir(vfs_handle_struct *handle,
1048                 const struct smb_filename *smb_fname,
1049                 mode_t mode)
1050 {
1051         int status;
1052         struct smb_filename *clientFname = NULL;
1053         const char *path = smb_fname->base_name;
1054
1055         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1056
1057         if (!is_in_media_files(path))
1058         {
1059                 status = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1060                 goto out;
1061         }
1062
1063         status = alloc_get_client_smb_fname(handle,
1064                                 talloc_tos(),
1065                                 smb_fname,
1066                                 &clientFname);
1067         if (status != 0) {
1068                 goto err;
1069         }
1070
1071         status = SMB_VFS_NEXT_MKDIR(handle, clientFname, mode);
1072 err:
1073         TALLOC_FREE(clientFname);
1074 out:
1075         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1076         return status;
1077 }
1078
1079 /*
1080  * Success: return 0
1081  * Failure: set errno, return -1
1082  */
1083 static int mh_rmdir(vfs_handle_struct *handle,
1084                 const struct smb_filename *smb_fname)
1085 {
1086         int status;
1087         struct smb_filename *clientFname = NULL;
1088         const char *path = smb_fname->base_name;
1089
1090         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1091
1092         if (!is_in_media_files(path))
1093         {
1094                 status = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1095                 goto out;
1096         }
1097
1098         status = alloc_get_client_smb_fname(handle,
1099                                 talloc_tos(),
1100                                 smb_fname,
1101                                 &clientFname);
1102         if (status != 0) {
1103                 goto err;
1104         }
1105
1106         status = SMB_VFS_NEXT_RMDIR(handle, clientFname);
1107 err:
1108         TALLOC_FREE(clientFname);
1109 out:
1110         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1111         return status;
1112 }
1113
1114 /*
1115  * Success: return 0
1116  * Failure: set errno, return -1
1117  */
1118 static int mh_closedir(vfs_handle_struct *handle,
1119                 DIR *dirp)
1120 {
1121         DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1122
1123         DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1124         // Will this talloc_free destroy realdirp?
1125         TALLOC_FREE(dirp);
1126
1127         DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1128         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1129 }
1130
1131 /*
1132  * Success: no success result defined.
1133  * Failure: no failure result defined.
1134  */
1135 static void mh_init_search_op(vfs_handle_struct *handle,
1136                 DIR *dirp)
1137 {
1138         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1139         SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1140                         ((mh_dirinfo_struct*)dirp)->dirstream);
1141 }
1142
1143 /*
1144  * Success: return non-negative file descriptor
1145  * Failure: set errno, return -1
1146  */
1147 static int mh_open(vfs_handle_struct *handle,
1148                 struct smb_filename *smb_fname,
1149                 files_struct *fsp,
1150                 int flags,
1151                 mode_t mode)
1152 {
1153         int ret;
1154         struct smb_filename *clientFname;
1155         TALLOC_CTX *ctx;
1156
1157
1158         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1159                               smb_fname->base_name));
1160
1161         if (!is_in_media_files(smb_fname->base_name))
1162         {
1163                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1164                                 mode);
1165                 goto out;
1166         }
1167
1168         clientFname = NULL;
1169         ctx = talloc_tos();
1170
1171         if(alloc_get_client_smb_fname(handle, ctx,
1172                                 smb_fname,
1173                                 &clientFname))
1174         {
1175                 ret = -1;
1176                 goto err;
1177         }
1178
1179         // What about fsp->fsp_name?
1180         // We also have to get correct stat info into fsp and smb_fname
1181         // for DB files, don't we?
1182
1183         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1184                         "smb_fname->st.st_ex_mtime %s"
1185                         "               fsp->fsp_name->st.st_ex_mtime %s",
1186                         smb_fname->base_name,
1187                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1188                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1189
1190         ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1191 err:
1192         TALLOC_FREE(clientFname);
1193 out:
1194         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1195                                 smb_fname->base_name));
1196         return ret;
1197 }
1198
1199 /*
1200  * Success: return non-negative file descriptor
1201  * Failure: set errno, return -1
1202  */
1203 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1204                 struct smb_request *req,
1205                 uint16_t root_dir_fid,
1206                 struct smb_filename *smb_fname,
1207                 uint32_t access_mask,
1208                 uint32_t share_access,
1209                 uint32_t create_disposition,
1210                 uint32_t create_options,
1211                 uint32_t file_attributes,
1212                 uint32_t oplock_request,
1213                 struct smb2_lease *lease,
1214                 uint64_t allocation_size,
1215                 uint32_t private_flags,
1216                 struct security_descriptor *sd,
1217                 struct ea_list *ea_list,
1218                 files_struct **result_fsp,
1219                 int *pinfo,
1220                 const struct smb2_create_blobs *in_context_blobs,
1221                 struct smb2_create_blobs *out_context_blobs)
1222 {
1223         NTSTATUS status;
1224         struct smb_filename *clientFname;
1225         TALLOC_CTX *ctx;
1226
1227
1228         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1229                                 smb_fname->base_name));
1230         if (!is_in_media_files(smb_fname->base_name))
1231         {
1232                 status = SMB_VFS_NEXT_CREATE_FILE(
1233                         handle,
1234                         req,
1235                         root_dir_fid,
1236                         smb_fname,
1237                         access_mask,
1238                         share_access,
1239                         create_disposition,
1240                         create_options,
1241                         file_attributes,
1242                         oplock_request,
1243                         lease,
1244                         allocation_size,
1245                         private_flags,
1246                         sd,
1247                         ea_list,
1248                         result_fsp,
1249                         pinfo,
1250                         in_context_blobs,
1251                         out_context_blobs);
1252                 goto out;
1253         }
1254
1255         clientFname = NULL;
1256         ctx = talloc_tos();
1257
1258         if (alloc_get_client_smb_fname(handle, ctx,
1259                                 smb_fname,
1260                                 &clientFname))
1261         {
1262                 status = map_nt_error_from_unix(errno);
1263                 goto err;
1264         }
1265
1266         /* This only creates files, so we don't have to worry about
1267          * our fake directory stat'ing here.
1268          */
1269         // But we still need to route stat calls for DB files
1270         // properly, right?
1271         status = SMB_VFS_NEXT_CREATE_FILE(
1272                 handle,
1273                 req,
1274                 root_dir_fid,
1275                 clientFname,
1276                 access_mask,
1277                 share_access,
1278                 create_disposition,
1279                 create_options,
1280                 file_attributes,
1281                 oplock_request,
1282                 lease,
1283                 allocation_size,
1284                 private_flags,
1285                 sd,
1286                 ea_list,
1287                 result_fsp,
1288                 pinfo,
1289                 in_context_blobs,
1290                 out_context_blobs);
1291 err:
1292         TALLOC_FREE(clientFname);
1293 out:
1294         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1295                 "smb_fname->st.st_ex_mtime %s"
1296                 "               fsp->fsp_name->st.st_ex_mtime %s",
1297                 smb_fname->base_name,
1298                 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1299                 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1300                 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1301                 "No fsp time\n"));
1302         return status;
1303 }
1304
1305 /*
1306  * Success: return 0
1307  * Failure: set errno, return -1
1308  */
1309 static int mh_rename(vfs_handle_struct *handle,
1310                 const struct smb_filename *smb_fname_src,
1311                 const struct smb_filename *smb_fname_dst)
1312 {
1313         int status;
1314         struct smb_filename *srcClientFname;
1315         struct smb_filename *dstClientFname;
1316         TALLOC_CTX *ctx;
1317
1318
1319         DEBUG(MH_INFO_DEBUG, ("Entering with "
1320                               "smb_fname_src->base_name '%s', "
1321                               "smb_fname_dst->base_name '%s'\n",
1322                               smb_fname_src->base_name,
1323                               smb_fname_dst->base_name));
1324
1325         if (!is_in_media_files(smb_fname_src->base_name)
1326                                 &&
1327                         !is_in_media_files(smb_fname_dst->base_name))
1328         {
1329                 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1330                                 smb_fname_dst);
1331                 goto out;
1332         }
1333
1334         srcClientFname = NULL;
1335         dstClientFname = NULL;
1336         ctx = talloc_tos();
1337
1338         if ((status = alloc_get_client_smb_fname(handle, ctx,
1339                                 smb_fname_src,
1340                                 &srcClientFname)))
1341         {
1342                 goto err;
1343         }
1344
1345         if ((status = alloc_get_client_smb_fname(handle, ctx,
1346                                 smb_fname_dst,
1347                                 &dstClientFname)))
1348         {
1349                 goto err;
1350         }
1351
1352         status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1353                                 dstClientFname);
1354 err:
1355         TALLOC_FREE(dstClientFname);
1356         TALLOC_FREE(srcClientFname);
1357 out:
1358         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1359                                 " smb_fname_dst->base_name '%s'\n",
1360                                 smb_fname_src->base_name,
1361                                 smb_fname_dst->base_name));
1362         return status;
1363 }
1364
1365 /*
1366  * Success: return 0
1367  * Failure: set errno, return -1
1368  */
1369 static int mh_stat(vfs_handle_struct *handle,
1370                 struct smb_filename *smb_fname)
1371 {
1372         int status = 0;
1373         struct smb_filename *clientFname;
1374         TALLOC_CTX *ctx;
1375
1376
1377         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1378                               smb_fname->base_name));
1379
1380         if (!is_in_media_files(smb_fname->base_name))
1381         {
1382                 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1383                 goto out;
1384         }
1385
1386         clientFname = NULL;
1387         ctx = talloc_tos();
1388
1389         if ((status = alloc_get_client_smb_fname(handle, ctx,
1390                                 smb_fname,
1391                                 &clientFname)))
1392         {
1393                 goto err;
1394         }
1395         DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1396                                 clientFname->base_name));
1397         if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1398         {
1399                 goto err;
1400         }
1401         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1402         {
1403                 goto err;
1404         }
1405
1406         /* Unlike functions with const smb_filename, we have to
1407          * modify smb_fname itself to pass our info back up.
1408          */
1409         DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1410                                 "from clientFname '%s'\n",
1411                                 smb_fname->base_name,
1412                                 clientFname->base_name));
1413         smb_fname->st = clientFname->st;
1414 err:
1415         TALLOC_FREE(clientFname);
1416 out:
1417         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1418                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1419         return status;
1420 }
1421
1422 /*
1423  * Success: return 0
1424  * Failure: set errno, return -1
1425  */
1426 static int mh_lstat(vfs_handle_struct *handle,
1427                 struct smb_filename *smb_fname)
1428 {
1429         int status = 0;
1430         struct smb_filename *clientFname;
1431         TALLOC_CTX *ctx;
1432
1433         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1434                               smb_fname->base_name));
1435
1436         if (!is_in_media_files(smb_fname->base_name))
1437         {
1438                 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1439                 goto out;
1440         }
1441
1442         clientFname = NULL;
1443         ctx = talloc_tos();
1444
1445         if ((status = alloc_get_client_smb_fname(handle, ctx,
1446                                 smb_fname,
1447                                 &clientFname)))
1448         {
1449                 goto err;
1450         }
1451         if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1452         {
1453                 goto err;
1454         }
1455
1456         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1457         {
1458                 goto err;
1459         }
1460         /* Unlike functions with const smb_filename, we have to
1461          * modify smb_fname itself to pass our info back up.
1462          */
1463         smb_fname->st = clientFname->st;
1464 err:
1465         TALLOC_FREE(clientFname);
1466 out:
1467         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1468                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1469         return status;
1470 }
1471
1472 /*
1473  * Success: return 0
1474  * Failure: set errno, return -1
1475  */
1476 static int mh_fstat(vfs_handle_struct *handle,
1477                 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1478 {
1479         int status = 0;
1480
1481         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1482                                 "'%s'\n", fsp_str_dbg(fsp)));
1483
1484         if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1485         {
1486                 goto out;
1487         }
1488
1489         if (fsp->fsp_name == NULL
1490                         || !is_in_media_files(fsp->fsp_name->base_name))
1491         {
1492                 goto out;
1493         }
1494
1495         if ((status = mh_stat(handle, fsp->fsp_name)))
1496         {
1497                 goto out;
1498         }
1499
1500         *sbuf = fsp->fsp_name->st;
1501 out:
1502         DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1503                         "%s",
1504                         fsp->fsp_name != NULL ?
1505                                 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1506                                 "0"));
1507         return status;
1508 }
1509
1510 /*
1511  * Success: return 0
1512  * Failure: set errno, return -1
1513  */
1514 static int mh_unlink(vfs_handle_struct *handle,
1515                 const struct smb_filename *smb_fname)
1516 {
1517         int status;
1518         struct smb_filename *clientFname;
1519         TALLOC_CTX *ctx;
1520
1521         DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1522         if (!is_in_media_files(smb_fname->base_name))
1523         {
1524                 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1525                 goto out;
1526         }
1527
1528         clientFname = NULL;
1529         ctx = talloc_tos();
1530
1531         if ((status = alloc_get_client_smb_fname(handle, ctx,
1532                                 smb_fname,
1533                                 &clientFname)))
1534         {
1535                 goto err;
1536         }
1537
1538         status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1539 err:
1540         TALLOC_FREE(clientFname);
1541 out:
1542         return status;
1543 }
1544
1545 /*
1546  * Success: return 0
1547  * Failure: set errno, return -1
1548  */
1549 static int mh_chmod(vfs_handle_struct *handle,
1550                 const struct smb_filename *smb_fname,
1551                 mode_t mode)
1552 {
1553         int status;
1554         struct smb_filename *clientFname = NULL;
1555
1556         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1557         if (!is_in_media_files(smb_fname->base_name))
1558         {
1559                 status = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1560                 goto out;
1561         }
1562
1563         status = alloc_get_client_smb_fname(handle,
1564                                 talloc_tos(),
1565                                 smb_fname,
1566                                 &clientFname);
1567         if (status != 0) {
1568                 goto err;
1569         }
1570
1571         status = SMB_VFS_NEXT_CHMOD(handle, clientFname, mode);
1572 err:
1573         TALLOC_FREE(clientFname);
1574 out:
1575         return status;
1576 }
1577
1578 /*
1579  * Success: return 0
1580  * Failure: set errno, return -1
1581  */
1582 static int mh_chown(vfs_handle_struct *handle,
1583                 const char *path,
1584                 uid_t uid,
1585                 gid_t gid)
1586 {
1587         int status;
1588         char *clientPath;
1589         TALLOC_CTX *ctx;
1590
1591         DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1592         if (!is_in_media_files(path))
1593         {
1594                 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1595                 goto out;
1596         }
1597
1598         clientPath = NULL;
1599         ctx = talloc_tos();
1600
1601         if ((status = alloc_get_client_path(handle, ctx,
1602                                 path,
1603                                 &clientPath)))
1604         {
1605                 goto err;
1606         }
1607
1608         status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1609 err:
1610         TALLOC_FREE(clientPath);
1611 out:
1612         return status;
1613 }
1614
1615 /*
1616  * Success: return 0
1617  * Failure: set errno, return -1
1618  */
1619 static int mh_lchown(vfs_handle_struct *handle,
1620                 const char *path,
1621                 uid_t uid,
1622                 gid_t gid)
1623 {
1624         int status;
1625         char *clientPath;
1626         TALLOC_CTX *ctx;
1627
1628         DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1629         if (!is_in_media_files(path))
1630         {
1631                 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1632                 goto out;
1633         }
1634
1635         clientPath = NULL;
1636         ctx = talloc_tos();
1637
1638         if ((status = alloc_get_client_path(handle, ctx,
1639                                 path,
1640                                 &clientPath)))
1641         {
1642                 goto err;
1643         }
1644
1645         status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1646 err:
1647         TALLOC_FREE(clientPath);
1648 out:
1649         return status;
1650 }
1651
1652 /*
1653  * Success: return 0
1654  * Failure: set errno, return -1
1655  */
1656 static int mh_chdir(vfs_handle_struct *handle,
1657                 const char *path)
1658 {
1659         int status;
1660         char *clientPath;
1661         TALLOC_CTX *ctx;
1662
1663         DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1664         if (!is_in_media_files(path))
1665         {
1666                 status = SMB_VFS_NEXT_CHDIR(handle, path);
1667                 goto out;
1668         }
1669
1670         clientPath = NULL;
1671         ctx = talloc_tos();
1672
1673         if ((status = alloc_get_client_path(handle, ctx,
1674                                 path,
1675                                 &clientPath)))
1676         {
1677                 goto err;
1678         }
1679
1680         status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1681 err:
1682         TALLOC_FREE(clientPath);
1683 out:
1684         return status;
1685 }
1686
1687 /*
1688  * Success: return 0
1689  * Failure: set errno, return -1
1690  */
1691 static int mh_ntimes(vfs_handle_struct *handle,
1692                 const struct smb_filename *smb_fname,
1693                 struct smb_file_time *ft)
1694 {
1695         int status;
1696         struct smb_filename *clientFname;
1697         TALLOC_CTX *ctx;
1698
1699
1700         DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1701         if (!is_in_media_files(smb_fname->base_name))
1702         {
1703                 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1704                 goto out;
1705         }
1706
1707         clientFname = NULL;
1708         ctx = talloc_tos();
1709
1710         if ((status = alloc_get_client_smb_fname(handle, ctx,
1711                                 smb_fname,
1712                                 &clientFname)))
1713         {
1714                 goto err;
1715         }
1716
1717         status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1718 err:
1719         TALLOC_FREE(clientFname);
1720 out:
1721         return status;
1722 }
1723
1724 /*
1725  * Success: return 0
1726  * Failure: set errno, return -1
1727  */
1728 static int mh_symlink(vfs_handle_struct *handle,
1729                 const char *oldpath,
1730                 const char *newpath)
1731 {
1732         int status;
1733         char *oldClientPath;
1734         char *newClientPath;
1735         TALLOC_CTX *ctx;
1736
1737         DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1738         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1739         {
1740                 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1741                 goto out;
1742         }
1743
1744         oldClientPath = NULL;
1745         newClientPath = NULL;
1746         ctx = talloc_tos();
1747
1748         if ((status = alloc_get_client_path(handle, ctx,
1749                                 oldpath,
1750                                 &oldClientPath)))
1751         {
1752                 goto err;
1753         }
1754
1755         if ((status = alloc_get_client_path(handle, ctx,
1756                                 newpath,
1757                                 &newClientPath)))
1758         {
1759                 goto err;
1760         }
1761
1762         status = SMB_VFS_NEXT_SYMLINK(handle,
1763                         oldClientPath,
1764                         newClientPath);
1765
1766 err:
1767         TALLOC_FREE(newClientPath);
1768         TALLOC_FREE(oldClientPath);
1769 out:
1770         return status;
1771 }
1772
1773 /*
1774  * Success: return byte count
1775  * Failure: set errno, return -1
1776  */
1777 static int mh_readlink(vfs_handle_struct *handle,
1778                 const char *path,
1779                 char *buf,
1780                 size_t bufsiz)
1781 {
1782         int status;
1783         char *clientPath;
1784         TALLOC_CTX *ctx;
1785
1786         DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1787         if (!is_in_media_files(path))
1788         {
1789                 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1790                 goto out;
1791         }
1792
1793         clientPath = NULL;
1794         ctx = talloc_tos();
1795
1796         if ((status = alloc_get_client_path(handle, ctx,
1797                                 path,
1798                                 &clientPath)))
1799         {
1800                 goto err;
1801         }
1802
1803         status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1804 err:
1805         TALLOC_FREE(clientPath);
1806 out:
1807         return status;
1808 }
1809
1810 /*
1811  * Success: return 0
1812  * Failure: set errno, return -1
1813  */
1814 static int mh_link(vfs_handle_struct *handle,
1815                 const char *oldpath,
1816                 const char *newpath)
1817 {
1818         int status;
1819         char *oldClientPath;
1820         char *newClientPath;
1821         TALLOC_CTX *ctx;
1822
1823         DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1824         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1825         {
1826                 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1827                 goto out;
1828         }
1829
1830         oldClientPath = NULL;
1831         newClientPath = NULL;
1832         ctx = talloc_tos();
1833
1834         if ((status = alloc_get_client_path(handle, ctx,
1835                                 oldpath,
1836                                 &oldClientPath)))
1837         {
1838                 goto err;
1839         }
1840
1841         if ((status = alloc_get_client_path(handle, ctx,
1842                                 newpath,
1843                                 &newClientPath)))
1844         {
1845                 goto err;
1846         }
1847
1848         status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1849 err:
1850         TALLOC_FREE(newClientPath);
1851         TALLOC_FREE(oldClientPath);
1852 out:
1853         return status;
1854 }
1855
1856 /*
1857  * Success: return 0
1858  * Failure: set errno, return -1
1859  */
1860 static int mh_mknod(vfs_handle_struct *handle,
1861                 const char *pathname,
1862                 mode_t mode,
1863                 SMB_DEV_T dev)
1864 {
1865         int status;
1866         char *clientPath;
1867         TALLOC_CTX *ctx;
1868
1869         DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1870         if (!is_in_media_files(pathname))
1871         {
1872                 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1873                 goto out;
1874         }
1875
1876         clientPath = NULL;
1877         ctx = talloc_tos();
1878
1879         if ((status = alloc_get_client_path(handle, ctx,
1880                                 pathname,
1881                                 &clientPath)))
1882         {
1883                 goto err;
1884         }
1885
1886         status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1887 err:
1888         TALLOC_FREE(clientPath);
1889 out:
1890         return status;
1891 }
1892
1893 /*
1894  * Success: return path pointer
1895  * Failure: set errno, return NULL pointer
1896  */
1897 static char *mh_realpath(vfs_handle_struct *handle,
1898                 const char *path)
1899 {
1900         char *buf;
1901         char *clientPath;
1902         TALLOC_CTX *ctx;
1903
1904         DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1905         if (!is_in_media_files(path))
1906         {
1907                 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1908                 goto out;
1909         }
1910
1911         clientPath = NULL;
1912         ctx = talloc_tos();
1913
1914         if (alloc_get_client_path(handle, ctx,
1915                                 path,
1916                                 &clientPath))
1917         {
1918                 buf = NULL;
1919                 goto err;
1920         }
1921
1922         buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1923 err:
1924         TALLOC_FREE(clientPath);
1925 out:
1926         return buf;
1927 }
1928
1929 /*
1930  * Success: return 0
1931  * Failure: set errno, return -1
1932  */
1933 static int mh_chflags(vfs_handle_struct *handle,
1934                 const char *path,
1935                 unsigned int flags)
1936 {
1937         int status;
1938         char *clientPath;
1939         TALLOC_CTX *ctx;
1940
1941         DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1942         if (!is_in_media_files(path))
1943         {
1944                 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1945                 goto out;
1946         }
1947
1948         clientPath = NULL;
1949         ctx = talloc_tos();
1950
1951         if ((status = alloc_get_client_path(handle, ctx,
1952                                 path,
1953                                 &clientPath)))
1954         {
1955                 goto err;
1956         }
1957
1958         status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1959 err:
1960         TALLOC_FREE(clientPath);
1961 out:
1962         return status;
1963 }
1964
1965 /*
1966  * Success: return NT_STATUS_OK
1967  * Failure: return NT status error
1968  */
1969 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1970                 struct files_struct *fsp,
1971                 const char *fname,
1972                 TALLOC_CTX *ctx,
1973                 unsigned int *num_streams,
1974                 struct stream_struct **streams)
1975 {
1976         NTSTATUS status;
1977         char *clientPath;
1978         TALLOC_CTX *mem_ctx;
1979
1980         DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1981         if (!is_in_media_files(fname))
1982         {
1983                 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1984                                 ctx, num_streams, streams);
1985                 goto out;
1986         }
1987
1988         clientPath = NULL;
1989         mem_ctx = talloc_tos();
1990
1991         if (alloc_get_client_path(handle, mem_ctx,
1992                                 fname,
1993                                 &clientPath))
1994         {
1995                 status = map_nt_error_from_unix(errno);
1996                 goto err;
1997         }
1998
1999         /* This only works on files, so we don't have to worry about
2000          * our fake directory stat'ing here.
2001          */
2002         // But what does this function do, exactly?  Does it need
2003         // extra modifications for the Avid stuff?
2004         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
2005                                 ctx, num_streams, streams);
2006 err:
2007         TALLOC_FREE(clientPath);
2008 out:
2009         return status;
2010 }
2011
2012 /* Ignoring get_real_filename function because the default
2013  * doesn't do anything.
2014  */
2015
2016 /*
2017  * Success: return NT_STATUS_OK
2018  * Failure: return NT status error
2019  * In this case, "name" is a path.
2020  */
2021 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2022                               const struct smb_filename *smb_fname,
2023                               uint32_t security_info,
2024                               TALLOC_CTX *mem_ctx,
2025                               struct security_descriptor **ppdesc)
2026 {
2027         NTSTATUS status;
2028         char *clientPath;
2029         struct smb_filename *client_smb_fname = NULL;
2030         TALLOC_CTX *ctx;
2031
2032         DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2033         if (!is_in_media_files(smb_fname->base_name))
2034         {
2035                 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
2036                                                  security_info,
2037                                                  mem_ctx, ppdesc);
2038                 goto out;
2039         }
2040
2041         clientPath = NULL;
2042         ctx = talloc_tos();
2043
2044         if (alloc_get_client_path(handle, ctx,
2045                                 smb_fname->base_name,
2046                                 &clientPath))
2047         {
2048                 status = map_nt_error_from_unix(errno);
2049                 goto err;
2050         }
2051
2052         client_smb_fname = synthetic_smb_fname(talloc_tos(),
2053                                         clientPath,
2054                                         NULL,
2055                                         NULL);
2056         if (client_smb_fname == NULL) {
2057                 TALLOC_FREE(clientPath);
2058                 return NT_STATUS_NO_MEMORY;
2059         }
2060
2061         status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
2062                                          security_info,
2063                                          mem_ctx, ppdesc);
2064 err:
2065         TALLOC_FREE(clientPath);
2066         TALLOC_FREE(client_smb_fname);
2067 out:
2068         return status;
2069 }
2070
2071 /*
2072  * Success: return 0
2073  * Failure: set errno, return -1
2074  */
2075 static int mh_chmod_acl(vfs_handle_struct *handle,
2076                 const char *path,
2077                 mode_t mode)
2078 {
2079         int status;
2080         char *clientPath;
2081         TALLOC_CTX *ctx;
2082
2083         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2084         if (!is_in_media_files(path))
2085         {
2086                 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2087                 goto out;
2088         }
2089
2090         clientPath = NULL;
2091         ctx = talloc_tos();
2092
2093         if ((status = alloc_get_client_path(handle, ctx,
2094                                 path,
2095                                 &clientPath)))
2096         {
2097                 goto err;
2098         }
2099
2100         status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2101 err:
2102         TALLOC_FREE(clientPath);
2103 out:
2104         return status;
2105 }
2106
2107 /*
2108  * Success: return acl pointer
2109  * Failure: set errno, return NULL
2110  */
2111 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2112                                      const char *path_p,
2113                                      SMB_ACL_TYPE_T type,
2114                                      TALLOC_CTX *mem_ctx)
2115 {
2116         SMB_ACL_T ret;
2117         char *clientPath;
2118         TALLOC_CTX *ctx;
2119
2120         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2121         if (!is_in_media_files(path_p))
2122         {
2123                 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2124                 goto out;
2125         }
2126
2127         clientPath = NULL;
2128         ctx = talloc_tos();
2129
2130         if (alloc_get_client_path(handle, ctx,
2131                                 path_p,
2132                                 &clientPath))
2133         {
2134                 ret = NULL;
2135                 goto err;
2136         }
2137
2138         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2139 err:
2140         TALLOC_FREE(clientPath);
2141 out:
2142         return ret;
2143 }
2144
2145 /*
2146  * Success: return 0
2147  * Failure: set errno, return -1
2148  * In this case, "name" is a path.
2149  */
2150 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2151                 const char *name,
2152                 SMB_ACL_TYPE_T acltype,
2153                 SMB_ACL_T theacl)
2154 {
2155         int status;
2156         char *clientPath;
2157         TALLOC_CTX *ctx;
2158
2159         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2160         if (!is_in_media_files(name))
2161         {
2162                 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2163                                 acltype, theacl);
2164                 goto out;
2165         }
2166
2167         clientPath = NULL;
2168         ctx = talloc_tos();
2169
2170         if ((status = alloc_get_client_path(handle, ctx,
2171                                 name,
2172                                 &clientPath)))
2173         {
2174                 goto err;
2175         }
2176
2177         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2178                         acltype, theacl);
2179 err:
2180         TALLOC_FREE(clientPath);
2181 out:
2182         return status;
2183 }
2184
2185 /*
2186  * Success: return 0
2187  * Failure: set errno, return -1
2188  */
2189 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2190                 const char *path)
2191 {
2192         int status;
2193         char *clientPath;
2194         TALLOC_CTX *ctx;
2195
2196         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2197         if (!is_in_media_files(path))
2198         {
2199                 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2200                                 path);
2201                 goto out;
2202         }
2203
2204         clientPath = NULL;
2205         ctx = talloc_tos();
2206
2207         if ((status = alloc_get_client_path(handle, ctx,
2208                                 path,
2209                                 &clientPath)))
2210         {
2211                 goto err;
2212         }
2213
2214         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2215 err:
2216         TALLOC_FREE(clientPath);
2217 out:
2218         return status;
2219 }
2220
2221 /*
2222  * Success: return positive number
2223  * Failure: set errno, return -1
2224  * In this case, "name" is an attr name.
2225  */
2226 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2227                 const char *path,
2228                 const char *name,
2229                 void *value,
2230                 size_t size)
2231 {
2232         ssize_t ret;
2233         char *clientPath;
2234         TALLOC_CTX *ctx;
2235
2236         DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2237         if (!is_in_media_files(path))
2238         {
2239                 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2240                                 size);
2241                 goto out;
2242         }
2243
2244         clientPath = NULL;
2245         ctx = talloc_tos();
2246
2247         if (alloc_get_client_path(handle, ctx,
2248                                 path,
2249                                 &clientPath))
2250         {
2251                 ret = -1;
2252                 goto err;
2253         }
2254
2255         ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2256 err:
2257         TALLOC_FREE(clientPath);
2258 out:
2259         return ret;
2260 }
2261
2262 /*
2263  * Success: return positive number
2264  * Failure: set errno, return -1
2265  */
2266 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2267                 const char *path,
2268                 char *list,
2269                 size_t size)
2270 {
2271         ssize_t ret;
2272         char *clientPath;
2273         TALLOC_CTX *ctx;
2274
2275         DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2276         if (!is_in_media_files(path))
2277         {
2278                 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2279                 goto out;
2280         }
2281
2282         clientPath = NULL;
2283         ctx = talloc_tos();
2284
2285         if (alloc_get_client_path(handle, ctx,
2286                                 path,
2287                                 &clientPath))
2288         {
2289                 ret = -1;
2290                 goto err;
2291         }
2292
2293         ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2294 err:
2295         TALLOC_FREE(clientPath);
2296 out:
2297         return ret;
2298 }
2299
2300 /*
2301  * Success: return 0
2302  * Failure: set errno, return -1
2303  * In this case, "name" is an attr name.
2304  */
2305 static int mh_removexattr(struct vfs_handle_struct *handle,
2306                 const char *path,
2307                 const char *name)
2308 {
2309         int status;
2310         char *clientPath;
2311         TALLOC_CTX *ctx;
2312
2313         DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2314         if (!is_in_media_files(path))
2315         {
2316                 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2317                 goto out;
2318         }
2319
2320         clientPath = NULL;
2321         ctx = talloc_tos();
2322
2323         if ((status = alloc_get_client_path(handle, ctx,
2324                                 path,
2325                                 &clientPath)))
2326         {
2327                 goto err;
2328         }
2329
2330         status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2331 err:
2332         TALLOC_FREE(clientPath);
2333 out:
2334         return status;
2335 }
2336
2337 /*
2338  * Success: return 0
2339  * Failure: set errno, return -1
2340  * In this case, "name" is an attr name.
2341  */
2342 static int mh_setxattr(struct vfs_handle_struct *handle,
2343                 const char *path,
2344                 const char *name,
2345                 const void *value,
2346                 size_t size,
2347                 int flags)
2348 {
2349         int status;
2350         char *clientPath;
2351         TALLOC_CTX *ctx;
2352
2353         DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2354         if (!is_in_media_files(path))
2355         {
2356                 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2357                                 size, flags);
2358                 goto out;
2359         }
2360
2361         clientPath = NULL;
2362         ctx = talloc_tos();
2363
2364         if ((status = alloc_get_client_path(handle, ctx,
2365                                 path,
2366                                 &clientPath)))
2367         {
2368                 goto err;
2369         }
2370
2371         status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2372                         size, flags);
2373 err:
2374         TALLOC_FREE(clientPath);
2375 out:
2376         return status;
2377 }
2378
2379 /*
2380  * Success: return true
2381  * Failure: set errno, return false
2382  */
2383 static bool mh_is_offline(struct vfs_handle_struct *handle,
2384                 const struct smb_filename *fname,
2385                 SMB_STRUCT_STAT *sbuf)
2386 {
2387         // check if sbuf is modified further down the chain.
2388         bool ret;
2389         struct smb_filename *clientFname;
2390         TALLOC_CTX *ctx;
2391
2392         DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2393         if (!is_in_media_files(fname->base_name))
2394         {
2395                 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2396                 goto out;
2397         }
2398
2399         clientFname = NULL;
2400         ctx = talloc_tos();
2401
2402         if(alloc_get_client_smb_fname(handle, ctx,
2403                                 fname,
2404                                 &clientFname))
2405         {
2406                 ret = -1;
2407                 goto err;
2408         }
2409
2410         ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2411 err:
2412         TALLOC_FREE(clientFname);
2413 out:
2414         return ret;
2415 }
2416
2417 /*
2418  * Success: return 0 (?)
2419  * Failure: set errno, return -1
2420  */
2421 static int mh_set_offline(struct vfs_handle_struct *handle,
2422                 const struct smb_filename *fname)
2423 {
2424         int status;
2425         struct smb_filename *clientFname;
2426         TALLOC_CTX *ctx;
2427
2428         DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2429         if (!is_in_media_files(fname->base_name))
2430         {
2431                 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2432                 goto out;
2433         }
2434
2435         clientFname = NULL;
2436         ctx = talloc_tos();
2437
2438         if ((status = alloc_get_client_smb_fname(handle, ctx,
2439                                 fname,
2440                                 &clientFname)))
2441         {
2442                 goto err;
2443         }
2444
2445         status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2446 err:
2447         TALLOC_FREE(clientFname);
2448 out:
2449         return status;
2450 }
2451
2452 /* VFS operations structure */
2453
2454 static struct vfs_fn_pointers vfs_mh_fns = {
2455         /* Disk operations */
2456
2457         .statvfs_fn = mh_statvfs,
2458
2459         /* Directory operations */
2460
2461         .opendir_fn = mh_opendir,
2462         .fdopendir_fn = mh_fdopendir,
2463         .readdir_fn = mh_readdir,
2464         .seekdir_fn = mh_seekdir,
2465         .telldir_fn = mh_telldir,
2466         .rewind_dir_fn = mh_rewinddir,
2467         .mkdir_fn = mh_mkdir,
2468         .rmdir_fn = mh_rmdir,
2469         .closedir_fn = mh_closedir,
2470         .init_search_op_fn = mh_init_search_op,
2471
2472         /* File operations */
2473
2474         .open_fn = mh_open,
2475         .create_file_fn = mh_create_file,
2476         .rename_fn = mh_rename,
2477         .stat_fn = mh_stat,
2478         .lstat_fn = mh_lstat,
2479         .fstat_fn = mh_fstat,
2480         .unlink_fn = mh_unlink,
2481         .chmod_fn = mh_chmod,
2482         .chown_fn = mh_chown,
2483         .lchown_fn = mh_lchown,
2484         .chdir_fn = mh_chdir,
2485         .ntimes_fn = mh_ntimes,
2486         .symlink_fn = mh_symlink,
2487         .readlink_fn = mh_readlink,
2488         .link_fn = mh_link,
2489         .mknod_fn = mh_mknod,
2490         .realpath_fn = mh_realpath,
2491         .chflags_fn = mh_chflags,
2492         .streaminfo_fn = mh_streaminfo,
2493
2494         /* NT ACL operations. */
2495
2496         .get_nt_acl_fn = mh_get_nt_acl,
2497
2498         /* POSIX ACL operations. */
2499
2500         .chmod_acl_fn = mh_chmod_acl,
2501
2502         .sys_acl_get_file_fn = mh_sys_acl_get_file,
2503         .sys_acl_set_file_fn = mh_sys_acl_set_file,
2504         .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2505
2506         /* EA operations. */
2507         .getxattr_fn = mh_getxattr,
2508         .listxattr_fn = mh_listxattr,
2509         .removexattr_fn = mh_removexattr,
2510         .setxattr_fn = mh_setxattr,
2511
2512         /* aio operations */
2513
2514         /* offline operations */
2515         .is_offline_fn = mh_is_offline,
2516         .set_offline_fn = mh_set_offline
2517 };
2518
2519 NTSTATUS vfs_media_harmony_init(void);
2520 NTSTATUS vfs_media_harmony_init(void)
2521 {
2522         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2523                                 "media_harmony", &vfs_mh_fns);
2524         if (!NT_STATUS_IS_OK(ret))
2525         {
2526                 goto out;
2527         }
2528
2529         vfs_mh_debug_level = debug_add_class("media_harmony");
2530
2531         if (vfs_mh_debug_level == -1) {
2532                 vfs_mh_debug_level = DBGC_VFS;
2533                 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2534                                 "debugging class.\n"));
2535         } else {
2536                 DEBUG(3, ("media_harmony_init: Debug class number of "
2537                                 "'media_harmony': %d\n",
2538                                 vfs_mh_debug_level));
2539         }
2540
2541 out:
2542         return ret;
2543 }