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