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