s3-vfs: Fix a null pointer deferference in vfs_media_harmony.
[samba.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                         fsp->fsp_name != NULL ?
1494                                 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1495                                 "0"));
1496         return status;
1497 }
1498
1499 /*
1500  * Success: return 0
1501  * Failure: set errno, return -1
1502  */
1503 static int mh_unlink(vfs_handle_struct *handle,
1504                 const struct smb_filename *smb_fname)
1505 {
1506         int status;
1507         struct smb_filename *clientFname;
1508         TALLOC_CTX *ctx;
1509
1510         DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1511         if (!is_in_media_files(smb_fname->base_name))
1512         {
1513                 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1514                 goto out;
1515         }
1516
1517         clientFname = NULL;
1518         ctx = talloc_tos();
1519
1520         if ((status = alloc_get_client_smb_fname(handle, ctx,
1521                                 smb_fname,
1522                                 &clientFname)))
1523         {
1524                 goto err;
1525         }
1526
1527         status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1528 err:
1529         TALLOC_FREE(clientFname);
1530 out:
1531         return status;
1532 }
1533
1534 /*
1535  * Success: return 0
1536  * Failure: set errno, return -1
1537  */
1538 static int mh_chmod(vfs_handle_struct *handle,
1539                 const char *path,
1540                 mode_t mode)
1541 {
1542         int status;
1543         char *clientPath;
1544         TALLOC_CTX *ctx;
1545
1546         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1547         if (!is_in_media_files(path))
1548         {
1549                 status = SMB_VFS_NEXT_CHMOD(handle, path, mode);
1550                 goto out;
1551         }
1552
1553         clientPath = NULL;
1554         ctx = talloc_tos();
1555
1556         if ((status = alloc_get_client_path(handle, ctx,
1557                                 path,
1558                                 &clientPath)))
1559         {
1560                 goto err;
1561         }
1562
1563         status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
1564 err:
1565         TALLOC_FREE(clientPath);
1566 out:
1567         return status;
1568 }
1569
1570 /*
1571  * Success: return 0
1572  * Failure: set errno, return -1
1573  */
1574 static int mh_chown(vfs_handle_struct *handle,
1575                 const char *path,
1576                 uid_t uid,
1577                 gid_t gid)
1578 {
1579         int status;
1580         char *clientPath;
1581         TALLOC_CTX *ctx;
1582
1583         DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1584         if (!is_in_media_files(path))
1585         {
1586                 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1587                 goto out;
1588         }
1589
1590         clientPath = NULL;
1591         ctx = talloc_tos();
1592
1593         if ((status = alloc_get_client_path(handle, ctx,
1594                                 path,
1595                                 &clientPath)))
1596         {
1597                 goto err;
1598         }
1599
1600         status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1601 err:
1602         TALLOC_FREE(clientPath);
1603 out:
1604         return status;
1605 }
1606
1607 /*
1608  * Success: return 0
1609  * Failure: set errno, return -1
1610  */
1611 static int mh_lchown(vfs_handle_struct *handle,
1612                 const char *path,
1613                 uid_t uid,
1614                 gid_t gid)
1615 {
1616         int status;
1617         char *clientPath;
1618         TALLOC_CTX *ctx;
1619
1620         DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1621         if (!is_in_media_files(path))
1622         {
1623                 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1624                 goto out;
1625         }
1626
1627         clientPath = NULL;
1628         ctx = talloc_tos();
1629
1630         if ((status = alloc_get_client_path(handle, ctx,
1631                                 path,
1632                                 &clientPath)))
1633         {
1634                 goto err;
1635         }
1636
1637         status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1638 err:
1639         TALLOC_FREE(clientPath);
1640 out:
1641         return status;
1642 }
1643
1644 /*
1645  * Success: return 0
1646  * Failure: set errno, return -1
1647  */
1648 static int mh_chdir(vfs_handle_struct *handle,
1649                 const char *path)
1650 {
1651         int status;
1652         char *clientPath;
1653         TALLOC_CTX *ctx;
1654
1655         DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1656         if (!is_in_media_files(path))
1657         {
1658                 status = SMB_VFS_NEXT_CHDIR(handle, path);
1659                 goto out;
1660         }
1661
1662         clientPath = NULL;
1663         ctx = talloc_tos();
1664
1665         if ((status = alloc_get_client_path(handle, ctx,
1666                                 path,
1667                                 &clientPath)))
1668         {
1669                 goto err;
1670         }
1671
1672         status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1673 err:
1674         TALLOC_FREE(clientPath);
1675 out:
1676         return status;
1677 }
1678
1679 /*
1680  * Success: return 0
1681  * Failure: set errno, return -1
1682  */
1683 static int mh_ntimes(vfs_handle_struct *handle,
1684                 const struct smb_filename *smb_fname,
1685                 struct smb_file_time *ft)
1686 {
1687         int status;
1688         struct smb_filename *clientFname;
1689         TALLOC_CTX *ctx;
1690
1691
1692         DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1693         if (!is_in_media_files(smb_fname->base_name))
1694         {
1695                 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1696                 goto out;
1697         }
1698
1699         clientFname = NULL;
1700         ctx = talloc_tos();
1701
1702         if ((status = alloc_get_client_smb_fname(handle, ctx,
1703                                 smb_fname,
1704                                 &clientFname)))
1705         {
1706                 goto err;
1707         }
1708
1709         status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1710 err:
1711         TALLOC_FREE(clientFname);
1712 out:
1713         return status;
1714 }
1715
1716 /*
1717  * Success: return 0
1718  * Failure: set errno, return -1
1719  */
1720 static int mh_symlink(vfs_handle_struct *handle,
1721                 const char *oldpath,
1722                 const char *newpath)
1723 {
1724         int status;
1725         char *oldClientPath;
1726         char *newClientPath;
1727         TALLOC_CTX *ctx;
1728
1729         DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1730         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1731         {
1732                 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1733                 goto out;
1734         }
1735
1736         oldClientPath = NULL;
1737         newClientPath = NULL;
1738         ctx = talloc_tos();
1739
1740         if ((status = alloc_get_client_path(handle, ctx,
1741                                 oldpath,
1742                                 &oldClientPath)))
1743         {
1744                 goto err;
1745         }
1746
1747         if ((status = alloc_get_client_path(handle, ctx,
1748                                 newpath,
1749                                 &newClientPath)))
1750         {
1751                 goto err;
1752         }
1753
1754         status = SMB_VFS_NEXT_SYMLINK(handle,
1755                         oldClientPath,
1756                         newClientPath);
1757
1758 err:
1759         TALLOC_FREE(newClientPath);
1760         TALLOC_FREE(oldClientPath);
1761 out:
1762         return status;
1763 }
1764
1765 /*
1766  * Success: return byte count
1767  * Failure: set errno, return -1
1768  */
1769 static int mh_readlink(vfs_handle_struct *handle,
1770                 const char *path,
1771                 char *buf,
1772                 size_t bufsiz)
1773 {
1774         int status;
1775         char *clientPath;
1776         TALLOC_CTX *ctx;
1777
1778         DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1779         if (!is_in_media_files(path))
1780         {
1781                 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1782                 goto out;
1783         }
1784
1785         clientPath = NULL;
1786         ctx = talloc_tos();
1787
1788         if ((status = alloc_get_client_path(handle, ctx,
1789                                 path,
1790                                 &clientPath)))
1791         {
1792                 goto err;
1793         }
1794
1795         status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1796 err:
1797         TALLOC_FREE(clientPath);
1798 out:
1799         return status;
1800 }
1801
1802 /*
1803  * Success: return 0
1804  * Failure: set errno, return -1
1805  */
1806 static int mh_link(vfs_handle_struct *handle,
1807                 const char *oldpath,
1808                 const char *newpath)
1809 {
1810         int status;
1811         char *oldClientPath;
1812         char *newClientPath;
1813         TALLOC_CTX *ctx;
1814
1815         DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1816         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1817         {
1818                 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1819                 goto out;
1820         }
1821
1822         oldClientPath = NULL;
1823         newClientPath = NULL;
1824         ctx = talloc_tos();
1825
1826         if ((status = alloc_get_client_path(handle, ctx,
1827                                 oldpath,
1828                                 &oldClientPath)))
1829         {
1830                 goto err;
1831         }
1832
1833         if ((status = alloc_get_client_path(handle, ctx,
1834                                 newpath,
1835                                 &newClientPath)))
1836         {
1837                 goto err;
1838         }
1839
1840         status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1841 err:
1842         TALLOC_FREE(newClientPath);
1843         TALLOC_FREE(oldClientPath);
1844 out:
1845         return status;
1846 }
1847
1848 /*
1849  * Success: return 0
1850  * Failure: set errno, return -1
1851  */
1852 static int mh_mknod(vfs_handle_struct *handle,
1853                 const char *pathname,
1854                 mode_t mode,
1855                 SMB_DEV_T dev)
1856 {
1857         int status;
1858         char *clientPath;
1859         TALLOC_CTX *ctx;
1860
1861         DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1862         if (!is_in_media_files(pathname))
1863         {
1864                 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1865                 goto out;
1866         }
1867
1868         clientPath = NULL;
1869         ctx = talloc_tos();
1870
1871         if ((status = alloc_get_client_path(handle, ctx,
1872                                 pathname,
1873                                 &clientPath)))
1874         {
1875                 goto err;
1876         }
1877
1878         status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1879 err:
1880         TALLOC_FREE(clientPath);
1881 out:
1882         return status;
1883 }
1884
1885 /*
1886  * Success: return path pointer
1887  * Failure: set errno, return NULL pointer
1888  */
1889 static char *mh_realpath(vfs_handle_struct *handle,
1890                 const char *path)
1891 {
1892         char *buf;
1893         char *clientPath;
1894         TALLOC_CTX *ctx;
1895
1896         DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1897         if (!is_in_media_files(path))
1898         {
1899                 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1900                 goto out;
1901         }
1902
1903         clientPath = NULL;
1904         ctx = talloc_tos();
1905
1906         if (alloc_get_client_path(handle, ctx,
1907                                 path,
1908                                 &clientPath))
1909         {
1910                 buf = NULL;
1911                 goto err;
1912         }
1913
1914         buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1915 err:
1916         TALLOC_FREE(clientPath);
1917 out:
1918         return buf;
1919 }
1920
1921 /*
1922  * Success: return 0
1923  * Failure: set errno, return -1
1924  */
1925 static int mh_chflags(vfs_handle_struct *handle,
1926                 const char *path,
1927                 unsigned int flags)
1928 {
1929         int status;
1930         char *clientPath;
1931         TALLOC_CTX *ctx;
1932
1933         DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1934         if (!is_in_media_files(path))
1935         {
1936                 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1937                 goto out;
1938         }
1939
1940         clientPath = NULL;
1941         ctx = talloc_tos();
1942
1943         if ((status = alloc_get_client_path(handle, ctx,
1944                                 path,
1945                                 &clientPath)))
1946         {
1947                 goto err;
1948         }
1949
1950         status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1951 err:
1952         TALLOC_FREE(clientPath);
1953 out:
1954         return status;
1955 }
1956
1957 /*
1958  * Success: return NT_STATUS_OK
1959  * Failure: return NT status error
1960  */
1961 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1962                 struct files_struct *fsp,
1963                 const char *fname,
1964                 TALLOC_CTX *ctx,
1965                 unsigned int *num_streams,
1966                 struct stream_struct **streams)
1967 {
1968         NTSTATUS status;
1969         char *clientPath;
1970         TALLOC_CTX *mem_ctx;
1971
1972         DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1973         if (!is_in_media_files(fname))
1974         {
1975                 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1976                                 ctx, num_streams, streams);
1977                 goto out;
1978         }
1979
1980         clientPath = NULL;
1981         mem_ctx = talloc_tos();
1982
1983         if (alloc_get_client_path(handle, mem_ctx,
1984                                 fname,
1985                                 &clientPath))
1986         {
1987                 status = map_nt_error_from_unix(errno);
1988                 goto err;
1989         }
1990
1991         /* This only works on files, so we don't have to worry about
1992          * our fake directory stat'ing here.
1993          */
1994         // But what does this function do, exactly?  Does it need
1995         // extra modifications for the Avid stuff?
1996         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
1997                                 ctx, num_streams, streams);
1998 err:
1999         TALLOC_FREE(clientPath);
2000 out:
2001         return status;
2002 }
2003
2004 /* Ignoring get_real_filename function because the default
2005  * doesn't do anything.
2006  */
2007
2008 /*
2009  * Success: return NT_STATUS_OK
2010  * Failure: return NT status error
2011  * In this case, "name" is a path.
2012  */
2013 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2014                               const char *name,
2015                               uint32 security_info,
2016                               TALLOC_CTX *mem_ctx,
2017                               struct security_descriptor **ppdesc)
2018 {
2019         NTSTATUS status;
2020         char *clientPath;
2021         TALLOC_CTX *ctx;
2022
2023         DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2024         if (!is_in_media_files(name))
2025         {
2026                 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name,
2027                                                  security_info,
2028                                                  mem_ctx, ppdesc);
2029                 goto out;
2030         }
2031
2032         clientPath = NULL;
2033         ctx = talloc_tos();
2034
2035         if (alloc_get_client_path(handle, ctx,
2036                                 name,
2037                                 &clientPath))
2038         {
2039                 status = map_nt_error_from_unix(errno);
2040                 goto err;
2041         }
2042
2043         status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
2044                                          security_info,
2045                                          mem_ctx, ppdesc);
2046 err:
2047         TALLOC_FREE(clientPath);
2048 out:
2049         return status;
2050 }
2051
2052 /*
2053  * Success: return 0
2054  * Failure: set errno, return -1
2055  */
2056 static int mh_chmod_acl(vfs_handle_struct *handle,
2057                 const char *path,
2058                 mode_t mode)
2059 {
2060         int status;
2061         char *clientPath;
2062         TALLOC_CTX *ctx;
2063
2064         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2065         if (!is_in_media_files(path))
2066         {
2067                 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2068                 goto out;
2069         }
2070
2071         clientPath = NULL;
2072         ctx = talloc_tos();
2073
2074         if ((status = alloc_get_client_path(handle, ctx,
2075                                 path,
2076                                 &clientPath)))
2077         {
2078                 goto err;
2079         }
2080
2081         status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2082 err:
2083         TALLOC_FREE(clientPath);
2084 out:
2085         return status;
2086 }
2087
2088 /*
2089  * Success: return acl pointer
2090  * Failure: set errno, return NULL
2091  */
2092 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2093                                      const char *path_p,
2094                                      SMB_ACL_TYPE_T type,
2095                                      TALLOC_CTX *mem_ctx)
2096 {
2097         SMB_ACL_T ret;
2098         char *clientPath;
2099         TALLOC_CTX *ctx;
2100
2101         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2102         if (!is_in_media_files(path_p))
2103         {
2104                 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2105                 goto out;
2106         }
2107
2108         clientPath = NULL;
2109         ctx = talloc_tos();
2110
2111         if (alloc_get_client_path(handle, ctx,
2112                                 path_p,
2113                                 &clientPath))
2114         {
2115                 ret = NULL;
2116                 goto err;
2117         }
2118
2119         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2120 err:
2121         TALLOC_FREE(clientPath);
2122 out:
2123         return ret;
2124 }
2125
2126 /*
2127  * Success: return 0
2128  * Failure: set errno, return -1
2129  * In this case, "name" is a path.
2130  */
2131 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2132                 const char *name,
2133                 SMB_ACL_TYPE_T acltype,
2134                 SMB_ACL_T theacl)
2135 {
2136         int status;
2137         char *clientPath;
2138         TALLOC_CTX *ctx;
2139
2140         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2141         if (!is_in_media_files(name))
2142         {
2143                 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2144                                 acltype, theacl);
2145                 goto out;
2146         }
2147
2148         clientPath = NULL;
2149         ctx = talloc_tos();
2150
2151         if ((status = alloc_get_client_path(handle, ctx,
2152                                 name,
2153                                 &clientPath)))
2154         {
2155                 goto err;
2156         }
2157
2158         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2159                         acltype, theacl);
2160 err:
2161         TALLOC_FREE(clientPath);
2162 out:
2163         return status;
2164 }
2165
2166 /*
2167  * Success: return 0
2168  * Failure: set errno, return -1
2169  */
2170 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2171                 const char *path)
2172 {
2173         int status;
2174         char *clientPath;
2175         TALLOC_CTX *ctx;
2176
2177         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2178         if (!is_in_media_files(path))
2179         {
2180                 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2181                                 path);
2182                 goto out;
2183         }
2184
2185         clientPath = NULL;
2186         ctx = talloc_tos();
2187
2188         if ((status = alloc_get_client_path(handle, ctx,
2189                                 path,
2190                                 &clientPath)))
2191         {
2192                 goto err;
2193         }
2194
2195         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2196 err:
2197         TALLOC_FREE(clientPath);
2198 out:
2199         return status;
2200 }
2201
2202 /*
2203  * Success: return positive number
2204  * Failure: set errno, return -1
2205  * In this case, "name" is an attr name.
2206  */
2207 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2208                 const char *path,
2209                 const char *name,
2210                 void *value,
2211                 size_t size)
2212 {
2213         ssize_t ret;
2214         char *clientPath;
2215         TALLOC_CTX *ctx;
2216
2217         DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2218         if (!is_in_media_files(path))
2219         {
2220                 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2221                                 size);
2222                 goto out;
2223         }
2224
2225         clientPath = NULL;
2226         ctx = talloc_tos();
2227
2228         if (alloc_get_client_path(handle, ctx,
2229                                 path,
2230                                 &clientPath))
2231         {
2232                 ret = -1;
2233                 goto err;
2234         }
2235
2236         ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2237 err:
2238         TALLOC_FREE(clientPath);
2239 out:
2240         return ret;
2241 }
2242
2243 /*
2244  * Success: return positive number
2245  * Failure: set errno, return -1
2246  */
2247 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2248                 const char *path,
2249                 char *list,
2250                 size_t size)
2251 {
2252         ssize_t ret;
2253         char *clientPath;
2254         TALLOC_CTX *ctx;
2255
2256         DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2257         if (!is_in_media_files(path))
2258         {
2259                 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2260                 goto out;
2261         }
2262
2263         clientPath = NULL;
2264         ctx = talloc_tos();
2265
2266         if (alloc_get_client_path(handle, ctx,
2267                                 path,
2268                                 &clientPath))
2269         {
2270                 ret = -1;
2271                 goto err;
2272         }
2273
2274         ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2275 err:
2276         TALLOC_FREE(clientPath);
2277 out:
2278         return ret;
2279 }
2280
2281 /*
2282  * Success: return 0
2283  * Failure: set errno, return -1
2284  * In this case, "name" is an attr name.
2285  */
2286 static int mh_removexattr(struct vfs_handle_struct *handle,
2287                 const char *path,
2288                 const char *name)
2289 {
2290         int status;
2291         char *clientPath;
2292         TALLOC_CTX *ctx;
2293
2294         DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2295         if (!is_in_media_files(path))
2296         {
2297                 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2298                 goto out;
2299         }
2300
2301         clientPath = NULL;
2302         ctx = talloc_tos();
2303
2304         if ((status = alloc_get_client_path(handle, ctx,
2305                                 path,
2306                                 &clientPath)))
2307         {
2308                 goto err;
2309         }
2310
2311         status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2312 err:
2313         TALLOC_FREE(clientPath);
2314 out:
2315         return status;
2316 }
2317
2318 /*
2319  * Success: return 0
2320  * Failure: set errno, return -1
2321  * In this case, "name" is an attr name.
2322  */
2323 static int mh_setxattr(struct vfs_handle_struct *handle,
2324                 const char *path,
2325                 const char *name,
2326                 const void *value,
2327                 size_t size,
2328                 int flags)
2329 {
2330         int status;
2331         char *clientPath;
2332         TALLOC_CTX *ctx;
2333
2334         DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2335         if (!is_in_media_files(path))
2336         {
2337                 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2338                                 size, flags);
2339                 goto out;
2340         }
2341
2342         clientPath = NULL;
2343         ctx = talloc_tos();
2344
2345         if ((status = alloc_get_client_path(handle, ctx,
2346                                 path,
2347                                 &clientPath)))
2348         {
2349                 goto err;
2350         }
2351
2352         status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2353                         size, flags);
2354 err:
2355         TALLOC_FREE(clientPath);
2356 out:
2357         return status;
2358 }
2359
2360 /*
2361  * Success: return true
2362  * Failure: set errno, return false
2363  */
2364 static bool mh_is_offline(struct vfs_handle_struct *handle,
2365                 const struct smb_filename *fname,
2366                 SMB_STRUCT_STAT *sbuf)
2367 {
2368         // check if sbuf is modified further down the chain.
2369         bool ret;
2370         struct smb_filename *clientFname;
2371         TALLOC_CTX *ctx;
2372
2373         DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2374         if (!is_in_media_files(fname->base_name))
2375         {
2376                 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2377                 goto out;
2378         }
2379
2380         clientFname = NULL;
2381         ctx = talloc_tos();
2382
2383         if(alloc_get_client_smb_fname(handle, ctx,
2384                                 fname,
2385                                 &clientFname))
2386         {
2387                 ret = -1;
2388                 goto err;
2389         }
2390
2391         ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2392 err:
2393         TALLOC_FREE(clientFname);
2394 out:
2395         return ret;
2396 }
2397
2398 /*
2399  * Success: return 0 (?)
2400  * Failure: set errno, return -1
2401  */
2402 static int mh_set_offline(struct vfs_handle_struct *handle,
2403                 const struct smb_filename *fname)
2404 {
2405         int status;
2406         struct smb_filename *clientFname;
2407         TALLOC_CTX *ctx;
2408
2409         DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2410         if (!is_in_media_files(fname->base_name))
2411         {
2412                 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2413                 goto out;
2414         }
2415
2416         clientFname = NULL;
2417         ctx = talloc_tos();
2418
2419         if ((status = alloc_get_client_smb_fname(handle, ctx,
2420                                 fname,
2421                                 &clientFname)))
2422         {
2423                 goto err;
2424         }
2425
2426         status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2427 err:
2428         TALLOC_FREE(clientFname);
2429 out:
2430         return status;
2431 }
2432
2433 /* VFS operations structure */
2434
2435 static struct vfs_fn_pointers vfs_mh_fns = {
2436         /* Disk operations */
2437
2438         .statvfs_fn = mh_statvfs,
2439
2440         /* Directory operations */
2441
2442         .opendir_fn = mh_opendir,
2443         .fdopendir_fn = mh_fdopendir,
2444         .readdir_fn = mh_readdir,
2445         .seekdir_fn = mh_seekdir,
2446         .telldir_fn = mh_telldir,
2447         .rewind_dir_fn = mh_rewinddir,
2448         .mkdir_fn = mh_mkdir,
2449         .rmdir_fn = mh_rmdir,
2450         .closedir_fn = mh_closedir,
2451         .init_search_op_fn = mh_init_search_op,
2452
2453         /* File operations */
2454
2455         .open_fn = mh_open,
2456         .create_file_fn = mh_create_file,
2457         .rename_fn = mh_rename,
2458         .stat_fn = mh_stat,
2459         .lstat_fn = mh_lstat,
2460         .fstat_fn = mh_fstat,
2461         .unlink_fn = mh_unlink,
2462         .chmod_fn = mh_chmod,
2463         .chown_fn = mh_chown,
2464         .lchown_fn = mh_lchown,
2465         .chdir_fn = mh_chdir,
2466         .ntimes_fn = mh_ntimes,
2467         .symlink_fn = mh_symlink,
2468         .readlink_fn = mh_readlink,
2469         .link_fn = mh_link,
2470         .mknod_fn = mh_mknod,
2471         .realpath_fn = mh_realpath,
2472         .chflags_fn = mh_chflags,
2473         .streaminfo_fn = mh_streaminfo,
2474
2475         /* NT ACL operations. */
2476
2477         .get_nt_acl_fn = mh_get_nt_acl,
2478
2479         /* POSIX ACL operations. */
2480
2481         .chmod_acl_fn = mh_chmod_acl,
2482
2483         .sys_acl_get_file_fn = mh_sys_acl_get_file,
2484         .sys_acl_set_file_fn = mh_sys_acl_set_file,
2485         .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2486
2487         /* EA operations. */
2488         .getxattr_fn = mh_getxattr,
2489         .listxattr_fn = mh_listxattr,
2490         .removexattr_fn = mh_removexattr,
2491         .setxattr_fn = mh_setxattr,
2492
2493         /* aio operations */
2494
2495         /* offline operations */
2496         .is_offline_fn = mh_is_offline,
2497         .set_offline_fn = mh_set_offline
2498 };
2499
2500 NTSTATUS vfs_media_harmony_init(void);
2501 NTSTATUS vfs_media_harmony_init(void)
2502 {
2503         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2504                                 "media_harmony", &vfs_mh_fns);
2505         if (!NT_STATUS_IS_OK(ret))
2506         {
2507                 goto out;
2508         }
2509
2510         vfs_mh_debug_level = debug_add_class("media_harmony");
2511
2512         if (vfs_mh_debug_level == -1) {
2513                 vfs_mh_debug_level = DBGC_VFS;
2514                 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2515                                 "debugging class.\n"));
2516         } else {
2517                 DEBUG(3, ("media_harmony_init: Debug class number of "
2518                                 "'media_harmony': %d\n",
2519                                 vfs_mh_debug_level));
2520         }
2521
2522 out:
2523         return ret;
2524 }