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