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