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