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