s3: VFS: Change SMB_VFS_LISTXATTR to use const struct smb_filename * instead of const...
[kamenim/samba-autobuild/.git] / source3 / modules / vfs_media_harmony.c
1 /*
2  * $Id: media_harmony.c,v 1.1 2007/11/06 10:07:22 stuart_hc Exp $
3  *
4  * Samba VFS module supporting multiple AVID clients sharing media.
5  *
6  * Copyright (C) 2005  Philip de Nier <philipn@users.sourceforge.net>
7  * Copyright (C) 2012  Andrew Klaassen <clawsoon@yahoo.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA.
23  */
24
25
26 /*
27  * Media Harmony is a Samba VFS module that allows multiple AVID
28  * clients to share media. Each client sees their own copy of the
29  * AVID msmMMOB.mdb and msmFMID.pmr files and Creating directories.
30  *
31  * Add this module to the vfs objects option in your Samba share
32  * configuration.
33  * eg.
34  *
35  *   [avid_win]
36  *      path = /video
37  *      vfs objects = media_harmony
38  *      ...
39  *
40  * It is recommended that you separate out Samba shares for Mac
41  * and Windows clients, and add the following options to the shares
42  * for Windows clients  (NOTE: replace @ with *):
43  *
44  *      veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
45  *      delete veto files = yes
46  *
47  * This prevents hidden files from Mac clients interfering with Windows
48  * clients. If you find any more problem hidden files then add them to
49  * the list.
50  *
51  *
52  * Andrew Klaassen, 2012-03-14
53  * To prevent Avid clients from interrupting each other (via Avid's habit
54  * of launching a database refresh whenever it notices an mtime update
55  * on media directories, i.e. whenever one editor adds new material to a
56  * shared share), I've added code that causes stat information for anything
57  * directly under "Avid MediaFile/MXF" to be taken from
58  * dirname_clientaddr_clientuser if it exists.  These files ~aren't~
59  * hidden, unlike the client-suffixed database files.
60  *
61  * For example, stat information for
62  *      Avid MediaFiles/MXF/1
63  * will come from
64  *      Avid MediaFiles/MXF/1_192.168.1.10_dave
65  * for dave working on 192.168.1.10, but will come from
66  *      Avid MediaFile/MXF/1_192.168.1.11_susan
67  * for susan working on 192.168.1.11.  If those alternate
68  * directories don't exist, the user will get the actual directory's stat
69  * info.  When an editor wants to force a database refresh, they update
70  * the mtime on "their" file.  This will cause Avid
71  * on that client to see an updated mtime for "Avid MediaFiles/MXF/1",
72  * which will trigger an Avid database refresh just for that editor.
73  *
74  *
75  * Notes:
76  * - This module is designed to work with AVID editing applications that
77  * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
78  * It is not designed to work as expected in all circumstances for
79  * general use. For example: it is possibly to open client specific
80  * files such as msmMMOB.mdb_192.168.1.10_userx even though is doesn't
81  * show up in a directory listing.
82  *
83  */
84
85
86 #include "includes.h"
87 #include "system/filesys.h"
88 #include "smbd/smbd.h"
89 #include "../smbd/globals.h"
90 #include "auth.h"
91 #include "../lib/tsocket/tsocket.h"
92
93 #define MH_INFO_DEBUG 10
94 #define MH_ERR_DEBUG 0
95
96 static const char* 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 char *path,
636                 struct vfs_statvfs_struct *statbuf)
637 {
638         int status;
639         char *clientPath;
640         TALLOC_CTX *ctx;
641
642         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
643
644         if (!is_in_media_files(path))
645         {
646                 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
647                 goto out;
648         }
649
650         clientPath = NULL;
651         ctx = talloc_tos();
652
653         if ((status = alloc_get_client_path(handle, ctx,
654                                 path,
655                                 &clientPath)))
656         {
657                 goto err;
658         }
659
660         status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
661 err:
662         TALLOC_FREE(clientPath);
663 out:
664         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
665         return status;
666 }
667
668 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
669                 const char *fname,
670                 struct mh_dirinfo_struct **dirInfo)
671 {
672         int status = 0;
673         char *clientPath;
674         TALLOC_CTX *ctx;
675
676         DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
677
678         *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
679         if (*dirInfo == NULL)
680         {
681                 goto err;
682         }
683
684         (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
685         if ((*dirInfo)->dirpath == NULL)
686         {
687                 goto err;
688         }
689
690         if (!is_in_media_files(fname))
691         {
692                 (*dirInfo)->clientPath = NULL;
693                 (*dirInfo)->clientMDBFilename = NULL;
694                 (*dirInfo)->clientPMRFilename = NULL;
695                 (*dirInfo)->clientCreatingDirname = NULL;
696                 (*dirInfo)->isInMediaFiles = False;
697                 goto out;
698         }
699
700         (*dirInfo)->isInMediaFiles = True;
701
702         if (alloc_set_client_dirinfo_path(handle,
703                                 *dirInfo,
704                                 &((*dirInfo)->clientMDBFilename),
705                                 MDB_FILENAME))
706         {
707                 goto err;
708         }
709
710         if (alloc_set_client_dirinfo_path(handle,
711                                 *dirInfo,
712                                 &((*dirInfo)->clientPMRFilename),
713                                 PMR_FILENAME))
714         {
715                 goto err;
716         }
717
718         if (alloc_set_client_dirinfo_path(handle,
719                                 *dirInfo,
720                                 &((*dirInfo)->clientCreatingDirname),
721                                 CREATING_DIRNAME))
722         {
723                 goto err;
724         }
725
726         clientPath = NULL;
727         ctx = talloc_tos();
728
729         if (alloc_get_client_path(handle, ctx,
730                                 fname,
731                                 &clientPath))
732         {
733                 goto err;
734         }
735
736         (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
737         if ((*dirInfo)->clientPath == NULL)
738         {
739                 goto err;
740         }
741
742         TALLOC_FREE(clientPath);
743
744 out:
745         DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
746                                 "(*dirInfo)->clientPath '%s'\n",
747                                 (*dirInfo)->dirpath,
748                                 (*dirInfo)->clientPath));
749         return status;
750
751 err:
752         DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
753         TALLOC_FREE(*dirInfo);
754         status = -1;
755         errno = ENOMEM;
756         return status;
757 }
758
759 /* Success: return a mh_dirinfo_struct cast as a DIR
760  * Failure: set errno, return NULL
761  */
762 static DIR *mh_opendir(vfs_handle_struct *handle,
763                 const struct smb_filename *smb_fname,
764                 const char *mask,
765                 uint32_t attr)
766 {
767         struct mh_dirinfo_struct *dirInfo;
768
769         DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n",
770                 smb_fname->base_name));
771
772         if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo))
773         {
774                 goto err;
775         }
776
777         if (!dirInfo->isInMediaFiles)
778         {
779                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
780                         smb_fname, mask, attr);
781         } else {
782                 struct smb_filename *smb_fname_clientpath =
783                                 synthetic_smb_fname(talloc_tos(),
784                                         dirInfo->clientPath,
785                                         NULL,
786                                         NULL,
787                                         smb_fname->flags);
788                 if (smb_fname_clientpath == NULL) {
789                         goto err;
790                 }
791
792                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
793                         smb_fname_clientpath, mask, attr);
794                 TALLOC_FREE(smb_fname_clientpath);
795         }
796
797         if (dirInfo->dirstream == NULL) {
798                 goto err;
799         }
800
801         /* Success is freed in closedir. */
802         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
803                                 "dirInfo->clientPath '%s'\n",
804                                 dirInfo->dirpath,
805                                 dirInfo->clientPath));
806         return (DIR*)dirInfo;
807 err:
808         /* Failure is freed here. */
809         DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n",
810                 smb_fname->base_name));
811         TALLOC_FREE(dirInfo);
812         return NULL;
813 }
814
815 static DIR *mh_fdopendir(vfs_handle_struct *handle,
816                 files_struct *fsp,
817                 const char *mask,
818                 uint32_t attr)
819 {
820         struct mh_dirinfo_struct *dirInfo = NULL;
821         DIR *dirstream;
822
823         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
824                               fsp->fsp_name->base_name));
825
826         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
827         if (!dirstream)
828         {
829                 goto err;
830         }
831
832         if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
833                                         &dirInfo))
834         {
835                 goto err;
836         }
837
838         dirInfo->dirstream = dirstream;
839
840         if (! dirInfo->isInMediaFiles) {
841                 goto out;
842         }
843
844         if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
845         {
846                 goto err;
847         }
848
849 out:
850         DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
851                         "dirInfo->clientPath '%s', "
852                         "fsp->fsp_name->st.st_ex_mtime %s",
853                         dirInfo->dirpath,
854                         dirInfo->clientPath,
855                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
856         /* Success is freed in closedir. */
857         return (DIR *) dirInfo;
858 err:
859         /* Failure is freed here. */
860         DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
861                         fsp->fsp_name->base_name));
862         TALLOC_FREE(dirInfo);
863         return NULL;
864 }
865
866 /*
867  * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
868  * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
869  * filenames and CREATING_DIRNAME directory, replace this client's
870  * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
871  * directory with non suffixed.
872  *
873  * Success: return dirent
874  * End of data: return NULL
875  * Failure: set errno, return NULL
876  */
877 static struct dirent *mh_readdir(vfs_handle_struct *handle,
878                 DIR *dirp,
879                 SMB_STRUCT_STAT *sbuf)
880 {
881         mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
882         struct dirent *d = NULL;
883         int skip;
884
885         DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
886
887         DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
888                               "dirInfo->clientPath '%s', "
889                               "dirInfo->isInMediaFiles '%s', "
890                               "dirInfo->clientMDBFilename '%s', "
891                               "dirInfo->clientPMRFilename '%s', "
892                               "dirInfo->clientCreatingDirname '%s'\n",
893                               dirInfo->dirpath,
894                               dirInfo->clientPath,
895                               dirInfo->isInMediaFiles ? "True" : "False",
896                               dirInfo->clientMDBFilename,
897                               dirInfo->clientPMRFilename,
898                               dirInfo->clientCreatingDirname));
899
900         if (! dirInfo->isInMediaFiles)
901         {
902                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
903                 goto out;
904         }
905
906         do
907         {
908                 const char* dname;
909                 bool isAppleDouble;
910
911                 skip = False;
912                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
913
914                 if (d == NULL)
915                 {
916                         break;
917                 }
918
919                 /* ignore apple double prefix for logic below */
920                 if (is_apple_double(d->d_name))
921                 {
922                         dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
923                         isAppleDouble = True;
924                 }
925                 else
926                 {
927                         dname = d->d_name;
928                         isAppleDouble = False;
929                 }
930
931                 /* skip Avid-special files with no client suffix */
932                 if (
933                         strcmp(dname, MDB_FILENAME) == 0
934                         ||
935                         strcmp(dname, PMR_FILENAME) == 0
936                         ||
937                         strcmp(dname, CREATING_DIRNAME) == 0
938                 )
939                 {
940                         skip = True;
941                 }
942                 /* chop client suffix off this client's suffixed files */
943                 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
944                 {
945                         if (isAppleDouble)
946                         {
947                                 d->d_name[MDB_FILENAME_LEN
948                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
949                         }
950                         else
951                         {
952                                 d->d_name[MDB_FILENAME_LEN] = '\0';
953                         }
954                 }
955                 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
956                 {
957                         if (isAppleDouble)
958                         {
959                                 d->d_name[PMR_FILENAME_LEN
960                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
961                         }
962                         else
963                         {
964                                 d->d_name[PMR_FILENAME_LEN] = '\0';
965                         }
966                 }
967                 else if (strcmp(dname, dirInfo->clientCreatingDirname)
968                                 == 0)
969                 {
970                         if (isAppleDouble)
971                         {
972                                 d->d_name[CREATING_DIRNAME_LEN
973                                         + APPLE_DOUBLE_PREFIX_LEN] = '\0';
974                         }
975                         else
976                         {
977                                 d->d_name[CREATING_DIRNAME_LEN] = '\0';
978                         }
979                 }
980                 /*
981                  * Anything that starts as an Avid-special file
982                  * that's made it this far should be skipped.  This
983                  * is different from the original behaviour, which
984                  * only skipped other client's suffixed files.
985                  */
986                 else if (
987                         strncmp(MDB_FILENAME, dname,
988                                 MDB_FILENAME_LEN) == 0
989                         ||
990                         strncmp(PMR_FILENAME, dname,
991                                 PMR_FILENAME_LEN) == 0
992                         ||
993                         strncmp(CREATING_DIRNAME, dname,
994                                 CREATING_DIRNAME_LEN) == 0
995                 )
996                 {
997                         skip = True;
998                 }
999         }
1000         while (skip);
1001
1002 out:
1003         DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
1004         return d;
1005 }
1006
1007 /*
1008  * Success: no success result defined.
1009  * Failure: no failure result defined.
1010  */
1011 static void mh_seekdir(vfs_handle_struct *handle,
1012                 DIR *dirp,
1013                 long offset)
1014 {
1015         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1016         SMB_VFS_NEXT_SEEKDIR(handle,
1017                         ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1018 }
1019
1020 /*
1021  * Success: return long
1022  * Failure: no failure result defined.
1023  */
1024 static long mh_telldir(vfs_handle_struct *handle,
1025                 DIR *dirp)
1026 {
1027         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1028         return SMB_VFS_NEXT_TELLDIR(handle,
1029                         ((mh_dirinfo_struct*)dirp)->dirstream);
1030 }
1031
1032 /*
1033  * Success: no success result defined.
1034  * Failure: no failure result defined.
1035  */
1036 static void mh_rewinddir(vfs_handle_struct *handle,
1037                 DIR *dirp)
1038 {
1039         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1040         SMB_VFS_NEXT_REWINDDIR(handle,
1041                         ((mh_dirinfo_struct*)dirp)->dirstream);
1042 }
1043
1044 /*
1045  * Success: return 0
1046  * Failure: set errno, return -1
1047  */
1048 static int mh_mkdir(vfs_handle_struct *handle,
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         {
1060                 status = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1061                 goto out;
1062         }
1063
1064         status = alloc_get_client_smb_fname(handle,
1065                                 talloc_tos(),
1066                                 smb_fname,
1067                                 &clientFname);
1068         if (status != 0) {
1069                 goto err;
1070         }
1071
1072         status = SMB_VFS_NEXT_MKDIR(handle, clientFname, mode);
1073 err:
1074         TALLOC_FREE(clientFname);
1075 out:
1076         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1077         return status;
1078 }
1079
1080 /*
1081  * Success: return 0
1082  * Failure: set errno, return -1
1083  */
1084 static int mh_rmdir(vfs_handle_struct *handle,
1085                 const struct smb_filename *smb_fname)
1086 {
1087         int status;
1088         struct smb_filename *clientFname = NULL;
1089         const char *path = smb_fname->base_name;
1090
1091         DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1092
1093         if (!is_in_media_files(path))
1094         {
1095                 status = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1096                 goto out;
1097         }
1098
1099         status = alloc_get_client_smb_fname(handle,
1100                                 talloc_tos(),
1101                                 smb_fname,
1102                                 &clientFname);
1103         if (status != 0) {
1104                 goto err;
1105         }
1106
1107         status = SMB_VFS_NEXT_RMDIR(handle, clientFname);
1108 err:
1109         TALLOC_FREE(clientFname);
1110 out:
1111         DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1112         return status;
1113 }
1114
1115 /*
1116  * Success: return 0
1117  * Failure: set errno, return -1
1118  */
1119 static int mh_closedir(vfs_handle_struct *handle,
1120                 DIR *dirp)
1121 {
1122         DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1123
1124         DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1125         // Will this talloc_free destroy realdirp?
1126         TALLOC_FREE(dirp);
1127
1128         DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1129         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1130 }
1131
1132 /*
1133  * Success: no success result defined.
1134  * Failure: no failure result defined.
1135  */
1136 static void mh_init_search_op(vfs_handle_struct *handle,
1137                 DIR *dirp)
1138 {
1139         DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1140         SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1141                         ((mh_dirinfo_struct*)dirp)->dirstream);
1142 }
1143
1144 /*
1145  * Success: return non-negative file descriptor
1146  * Failure: set errno, return -1
1147  */
1148 static int mh_open(vfs_handle_struct *handle,
1149                 struct smb_filename *smb_fname,
1150                 files_struct *fsp,
1151                 int flags,
1152                 mode_t mode)
1153 {
1154         int ret;
1155         struct smb_filename *clientFname;
1156         TALLOC_CTX *ctx;
1157
1158
1159         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1160                               smb_fname->base_name));
1161
1162         if (!is_in_media_files(smb_fname->base_name))
1163         {
1164                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1165                                 mode);
1166                 goto out;
1167         }
1168
1169         clientFname = NULL;
1170         ctx = talloc_tos();
1171
1172         if(alloc_get_client_smb_fname(handle, ctx,
1173                                 smb_fname,
1174                                 &clientFname))
1175         {
1176                 ret = -1;
1177                 goto err;
1178         }
1179
1180         // What about fsp->fsp_name?
1181         // We also have to get correct stat info into fsp and smb_fname
1182         // for DB files, don't we?
1183
1184         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1185                         "smb_fname->st.st_ex_mtime %s"
1186                         "               fsp->fsp_name->st.st_ex_mtime %s",
1187                         smb_fname->base_name,
1188                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1189                         ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1190
1191         ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1192 err:
1193         TALLOC_FREE(clientFname);
1194 out:
1195         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1196                                 smb_fname->base_name));
1197         return ret;
1198 }
1199
1200 /*
1201  * Success: return non-negative file descriptor
1202  * Failure: set errno, return -1
1203  */
1204 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1205                 struct smb_request *req,
1206                 uint16_t root_dir_fid,
1207                 struct smb_filename *smb_fname,
1208                 uint32_t access_mask,
1209                 uint32_t share_access,
1210                 uint32_t create_disposition,
1211                 uint32_t create_options,
1212                 uint32_t file_attributes,
1213                 uint32_t oplock_request,
1214                 struct smb2_lease *lease,
1215                 uint64_t allocation_size,
1216                 uint32_t private_flags,
1217                 struct security_descriptor *sd,
1218                 struct ea_list *ea_list,
1219                 files_struct **result_fsp,
1220                 int *pinfo,
1221                 const struct smb2_create_blobs *in_context_blobs,
1222                 struct smb2_create_blobs *out_context_blobs)
1223 {
1224         NTSTATUS status;
1225         struct smb_filename *clientFname;
1226         TALLOC_CTX *ctx;
1227
1228
1229         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1230                                 smb_fname->base_name));
1231         if (!is_in_media_files(smb_fname->base_name))
1232         {
1233                 status = SMB_VFS_NEXT_CREATE_FILE(
1234                         handle,
1235                         req,
1236                         root_dir_fid,
1237                         smb_fname,
1238                         access_mask,
1239                         share_access,
1240                         create_disposition,
1241                         create_options,
1242                         file_attributes,
1243                         oplock_request,
1244                         lease,
1245                         allocation_size,
1246                         private_flags,
1247                         sd,
1248                         ea_list,
1249                         result_fsp,
1250                         pinfo,
1251                         in_context_blobs,
1252                         out_context_blobs);
1253                 goto out;
1254         }
1255
1256         clientFname = NULL;
1257         ctx = talloc_tos();
1258
1259         if (alloc_get_client_smb_fname(handle, ctx,
1260                                 smb_fname,
1261                                 &clientFname))
1262         {
1263                 status = map_nt_error_from_unix(errno);
1264                 goto err;
1265         }
1266
1267         /* This only creates files, so we don't have to worry about
1268          * our fake directory stat'ing here.
1269          */
1270         // But we still need to route stat calls for DB files
1271         // properly, right?
1272         status = SMB_VFS_NEXT_CREATE_FILE(
1273                 handle,
1274                 req,
1275                 root_dir_fid,
1276                 clientFname,
1277                 access_mask,
1278                 share_access,
1279                 create_disposition,
1280                 create_options,
1281                 file_attributes,
1282                 oplock_request,
1283                 lease,
1284                 allocation_size,
1285                 private_flags,
1286                 sd,
1287                 ea_list,
1288                 result_fsp,
1289                 pinfo,
1290                 in_context_blobs,
1291                 out_context_blobs);
1292 err:
1293         TALLOC_FREE(clientFname);
1294 out:
1295         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1296                 "smb_fname->st.st_ex_mtime %s"
1297                 "               fsp->fsp_name->st.st_ex_mtime %s",
1298                 smb_fname->base_name,
1299                 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1300                 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1301                 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1302                 "No fsp time\n"));
1303         return status;
1304 }
1305
1306 /*
1307  * Success: return 0
1308  * Failure: set errno, return -1
1309  */
1310 static int mh_rename(vfs_handle_struct *handle,
1311                 const struct smb_filename *smb_fname_src,
1312                 const struct smb_filename *smb_fname_dst)
1313 {
1314         int status;
1315         struct smb_filename *srcClientFname;
1316         struct smb_filename *dstClientFname;
1317         TALLOC_CTX *ctx;
1318
1319
1320         DEBUG(MH_INFO_DEBUG, ("Entering with "
1321                               "smb_fname_src->base_name '%s', "
1322                               "smb_fname_dst->base_name '%s'\n",
1323                               smb_fname_src->base_name,
1324                               smb_fname_dst->base_name));
1325
1326         if (!is_in_media_files(smb_fname_src->base_name)
1327                                 &&
1328                         !is_in_media_files(smb_fname_dst->base_name))
1329         {
1330                 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1331                                 smb_fname_dst);
1332                 goto out;
1333         }
1334
1335         srcClientFname = NULL;
1336         dstClientFname = NULL;
1337         ctx = talloc_tos();
1338
1339         if ((status = alloc_get_client_smb_fname(handle, ctx,
1340                                 smb_fname_src,
1341                                 &srcClientFname)))
1342         {
1343                 goto err;
1344         }
1345
1346         if ((status = alloc_get_client_smb_fname(handle, ctx,
1347                                 smb_fname_dst,
1348                                 &dstClientFname)))
1349         {
1350                 goto err;
1351         }
1352
1353         status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1354                                 dstClientFname);
1355 err:
1356         TALLOC_FREE(dstClientFname);
1357         TALLOC_FREE(srcClientFname);
1358 out:
1359         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1360                                 " smb_fname_dst->base_name '%s'\n",
1361                                 smb_fname_src->base_name,
1362                                 smb_fname_dst->base_name));
1363         return status;
1364 }
1365
1366 /*
1367  * Success: return 0
1368  * Failure: set errno, return -1
1369  */
1370 static int mh_stat(vfs_handle_struct *handle,
1371                 struct smb_filename *smb_fname)
1372 {
1373         int status = 0;
1374         struct smb_filename *clientFname;
1375         TALLOC_CTX *ctx;
1376
1377
1378         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1379                               smb_fname->base_name));
1380
1381         if (!is_in_media_files(smb_fname->base_name))
1382         {
1383                 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1384                 goto out;
1385         }
1386
1387         clientFname = NULL;
1388         ctx = talloc_tos();
1389
1390         if ((status = alloc_get_client_smb_fname(handle, ctx,
1391                                 smb_fname,
1392                                 &clientFname)))
1393         {
1394                 goto err;
1395         }
1396         DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1397                                 clientFname->base_name));
1398         if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1399         {
1400                 goto err;
1401         }
1402         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1403         {
1404                 goto err;
1405         }
1406
1407         /* Unlike functions with const smb_filename, we have to
1408          * modify smb_fname itself to pass our info back up.
1409          */
1410         DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1411                                 "from clientFname '%s'\n",
1412                                 smb_fname->base_name,
1413                                 clientFname->base_name));
1414         smb_fname->st = clientFname->st;
1415 err:
1416         TALLOC_FREE(clientFname);
1417 out:
1418         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1419                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1420         return status;
1421 }
1422
1423 /*
1424  * Success: return 0
1425  * Failure: set errno, return -1
1426  */
1427 static int mh_lstat(vfs_handle_struct *handle,
1428                 struct smb_filename *smb_fname)
1429 {
1430         int status = 0;
1431         struct smb_filename *clientFname;
1432         TALLOC_CTX *ctx;
1433
1434         DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1435                               smb_fname->base_name));
1436
1437         if (!is_in_media_files(smb_fname->base_name))
1438         {
1439                 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1440                 goto out;
1441         }
1442
1443         clientFname = NULL;
1444         ctx = talloc_tos();
1445
1446         if ((status = alloc_get_client_smb_fname(handle, ctx,
1447                                 smb_fname,
1448                                 &clientFname)))
1449         {
1450                 goto err;
1451         }
1452         if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1453         {
1454                 goto err;
1455         }
1456
1457         if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1458         {
1459                 goto err;
1460         }
1461         /* Unlike functions with const smb_filename, we have to
1462          * modify smb_fname itself to pass our info back up.
1463          */
1464         smb_fname->st = clientFname->st;
1465 err:
1466         TALLOC_FREE(clientFname);
1467 out:
1468         DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1469                         ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1470         return status;
1471 }
1472
1473 /*
1474  * Success: return 0
1475  * Failure: set errno, return -1
1476  */
1477 static int mh_fstat(vfs_handle_struct *handle,
1478                 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1479 {
1480         int status = 0;
1481
1482         DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1483                                 "'%s'\n", fsp_str_dbg(fsp)));
1484
1485         if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1486         {
1487                 goto out;
1488         }
1489
1490         if (fsp->fsp_name == NULL
1491                         || !is_in_media_files(fsp->fsp_name->base_name))
1492         {
1493                 goto out;
1494         }
1495
1496         if ((status = mh_stat(handle, fsp->fsp_name)))
1497         {
1498                 goto out;
1499         }
1500
1501         *sbuf = fsp->fsp_name->st;
1502 out:
1503         DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1504                         "%s",
1505                         fsp->fsp_name != NULL ?
1506                                 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1507                                 "0"));
1508         return status;
1509 }
1510
1511 /*
1512  * Success: return 0
1513  * Failure: set errno, return -1
1514  */
1515 static int mh_unlink(vfs_handle_struct *handle,
1516                 const struct smb_filename *smb_fname)
1517 {
1518         int status;
1519         struct smb_filename *clientFname;
1520         TALLOC_CTX *ctx;
1521
1522         DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1523         if (!is_in_media_files(smb_fname->base_name))
1524         {
1525                 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1526                 goto out;
1527         }
1528
1529         clientFname = NULL;
1530         ctx = talloc_tos();
1531
1532         if ((status = alloc_get_client_smb_fname(handle, ctx,
1533                                 smb_fname,
1534                                 &clientFname)))
1535         {
1536                 goto err;
1537         }
1538
1539         status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1540 err:
1541         TALLOC_FREE(clientFname);
1542 out:
1543         return status;
1544 }
1545
1546 /*
1547  * Success: return 0
1548  * Failure: set errno, return -1
1549  */
1550 static int mh_chmod(vfs_handle_struct *handle,
1551                 const struct smb_filename *smb_fname,
1552                 mode_t mode)
1553 {
1554         int status;
1555         struct smb_filename *clientFname = NULL;
1556
1557         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1558         if (!is_in_media_files(smb_fname->base_name))
1559         {
1560                 status = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1561                 goto out;
1562         }
1563
1564         status = alloc_get_client_smb_fname(handle,
1565                                 talloc_tos(),
1566                                 smb_fname,
1567                                 &clientFname);
1568         if (status != 0) {
1569                 goto err;
1570         }
1571
1572         status = SMB_VFS_NEXT_CHMOD(handle, clientFname, mode);
1573 err:
1574         TALLOC_FREE(clientFname);
1575 out:
1576         return status;
1577 }
1578
1579 /*
1580  * Success: return 0
1581  * Failure: set errno, return -1
1582  */
1583 static int mh_chown(vfs_handle_struct *handle,
1584                 const struct smb_filename *smb_fname,
1585                 uid_t uid,
1586                 gid_t gid)
1587 {
1588         int status;
1589         struct smb_filename *clientFname = NULL;
1590
1591         DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1592         if (!is_in_media_files(smb_fname->base_name))
1593         {
1594                 status = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1595                 goto out;
1596         }
1597
1598         status = alloc_get_client_smb_fname(handle,
1599                                 talloc_tos(),
1600                                 smb_fname,
1601                                 &clientFname);
1602         if (status != 0) {
1603                 goto err;
1604         }
1605
1606         status = SMB_VFS_NEXT_CHOWN(handle, clientFname, uid, gid);
1607 err:
1608         TALLOC_FREE(clientFname);
1609 out:
1610         return status;
1611 }
1612
1613 /*
1614  * Success: return 0
1615  * Failure: set errno, return -1
1616  */
1617 static int mh_lchown(vfs_handle_struct *handle,
1618                 const struct smb_filename *smb_fname,
1619                 uid_t uid,
1620                 gid_t gid)
1621 {
1622         int status;
1623         struct smb_filename *clientFname = NULL;
1624
1625         DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1626         if (!is_in_media_files(smb_fname->base_name))
1627         {
1628                 status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1629                 goto out;
1630         }
1631
1632         status = alloc_get_client_smb_fname(handle,
1633                                 talloc_tos(),
1634                                 smb_fname,
1635                                 &clientFname);
1636         if (status != 0) {
1637                 goto err;
1638         }
1639
1640         status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1641 err:
1642         TALLOC_FREE(clientFname);
1643 out:
1644         return status;
1645 }
1646
1647 /*
1648  * Success: return 0
1649  * Failure: set errno, return -1
1650  */
1651 static int mh_chdir(vfs_handle_struct *handle,
1652                 const char *path)
1653 {
1654         int status;
1655         char *clientPath;
1656         TALLOC_CTX *ctx;
1657
1658         DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1659         if (!is_in_media_files(path))
1660         {
1661                 status = SMB_VFS_NEXT_CHDIR(handle, path);
1662                 goto out;
1663         }
1664
1665         clientPath = NULL;
1666         ctx = talloc_tos();
1667
1668         if ((status = alloc_get_client_path(handle, ctx,
1669                                 path,
1670                                 &clientPath)))
1671         {
1672                 goto err;
1673         }
1674
1675         status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1676 err:
1677         TALLOC_FREE(clientPath);
1678 out:
1679         return status;
1680 }
1681
1682 /*
1683  * Success: return 0
1684  * Failure: set errno, return -1
1685  */
1686 static int mh_ntimes(vfs_handle_struct *handle,
1687                 const struct smb_filename *smb_fname,
1688                 struct smb_file_time *ft)
1689 {
1690         int status;
1691         struct smb_filename *clientFname;
1692         TALLOC_CTX *ctx;
1693
1694
1695         DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1696         if (!is_in_media_files(smb_fname->base_name))
1697         {
1698                 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1699                 goto out;
1700         }
1701
1702         clientFname = NULL;
1703         ctx = talloc_tos();
1704
1705         if ((status = alloc_get_client_smb_fname(handle, ctx,
1706                                 smb_fname,
1707                                 &clientFname)))
1708         {
1709                 goto err;
1710         }
1711
1712         status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1713 err:
1714         TALLOC_FREE(clientFname);
1715 out:
1716         return status;
1717 }
1718
1719 /*
1720  * Success: return 0
1721  * Failure: set errno, return -1
1722  */
1723 static int mh_symlink(vfs_handle_struct *handle,
1724                 const char *oldpath,
1725                 const char *newpath)
1726 {
1727         int status;
1728         char *oldClientPath;
1729         char *newClientPath;
1730         TALLOC_CTX *ctx;
1731
1732         DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1733         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1734         {
1735                 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1736                 goto out;
1737         }
1738
1739         oldClientPath = NULL;
1740         newClientPath = NULL;
1741         ctx = talloc_tos();
1742
1743         if ((status = alloc_get_client_path(handle, ctx,
1744                                 oldpath,
1745                                 &oldClientPath)))
1746         {
1747                 goto err;
1748         }
1749
1750         if ((status = alloc_get_client_path(handle, ctx,
1751                                 newpath,
1752                                 &newClientPath)))
1753         {
1754                 goto err;
1755         }
1756
1757         status = SMB_VFS_NEXT_SYMLINK(handle,
1758                         oldClientPath,
1759                         newClientPath);
1760
1761 err:
1762         TALLOC_FREE(newClientPath);
1763         TALLOC_FREE(oldClientPath);
1764 out:
1765         return status;
1766 }
1767
1768 /*
1769  * Success: return byte count
1770  * Failure: set errno, return -1
1771  */
1772 static int mh_readlink(vfs_handle_struct *handle,
1773                 const char *path,
1774                 char *buf,
1775                 size_t bufsiz)
1776 {
1777         int status;
1778         char *clientPath;
1779         TALLOC_CTX *ctx;
1780
1781         DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1782         if (!is_in_media_files(path))
1783         {
1784                 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1785                 goto out;
1786         }
1787
1788         clientPath = NULL;
1789         ctx = talloc_tos();
1790
1791         if ((status = alloc_get_client_path(handle, ctx,
1792                                 path,
1793                                 &clientPath)))
1794         {
1795                 goto err;
1796         }
1797
1798         status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1799 err:
1800         TALLOC_FREE(clientPath);
1801 out:
1802         return status;
1803 }
1804
1805 /*
1806  * Success: return 0
1807  * Failure: set errno, return -1
1808  */
1809 static int mh_link(vfs_handle_struct *handle,
1810                 const char *oldpath,
1811                 const char *newpath)
1812 {
1813         int status;
1814         char *oldClientPath;
1815         char *newClientPath;
1816         TALLOC_CTX *ctx;
1817
1818         DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1819         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1820         {
1821                 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1822                 goto out;
1823         }
1824
1825         oldClientPath = NULL;
1826         newClientPath = NULL;
1827         ctx = talloc_tos();
1828
1829         if ((status = alloc_get_client_path(handle, ctx,
1830                                 oldpath,
1831                                 &oldClientPath)))
1832         {
1833                 goto err;
1834         }
1835
1836         if ((status = alloc_get_client_path(handle, ctx,
1837                                 newpath,
1838                                 &newClientPath)))
1839         {
1840                 goto err;
1841         }
1842
1843         status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1844 err:
1845         TALLOC_FREE(newClientPath);
1846         TALLOC_FREE(oldClientPath);
1847 out:
1848         return status;
1849 }
1850
1851 /*
1852  * Success: return 0
1853  * Failure: set errno, return -1
1854  */
1855 static int mh_mknod(vfs_handle_struct *handle,
1856                 const char *pathname,
1857                 mode_t mode,
1858                 SMB_DEV_T dev)
1859 {
1860         int status;
1861         char *clientPath;
1862         TALLOC_CTX *ctx;
1863
1864         DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1865         if (!is_in_media_files(pathname))
1866         {
1867                 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1868                 goto out;
1869         }
1870
1871         clientPath = NULL;
1872         ctx = talloc_tos();
1873
1874         if ((status = alloc_get_client_path(handle, ctx,
1875                                 pathname,
1876                                 &clientPath)))
1877         {
1878                 goto err;
1879         }
1880
1881         status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1882 err:
1883         TALLOC_FREE(clientPath);
1884 out:
1885         return status;
1886 }
1887
1888 /*
1889  * Success: return path pointer
1890  * Failure: set errno, return NULL pointer
1891  */
1892 static char *mh_realpath(vfs_handle_struct *handle,
1893                 const char *path)
1894 {
1895         char *buf;
1896         char *clientPath;
1897         TALLOC_CTX *ctx;
1898
1899         DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1900         if (!is_in_media_files(path))
1901         {
1902                 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1903                 goto out;
1904         }
1905
1906         clientPath = NULL;
1907         ctx = talloc_tos();
1908
1909         if (alloc_get_client_path(handle, ctx,
1910                                 path,
1911                                 &clientPath))
1912         {
1913                 buf = NULL;
1914                 goto err;
1915         }
1916
1917         buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1918 err:
1919         TALLOC_FREE(clientPath);
1920 out:
1921         return buf;
1922 }
1923
1924 /*
1925  * Success: return 0
1926  * Failure: set errno, return -1
1927  */
1928 static int mh_chflags(vfs_handle_struct *handle,
1929                 const char *path,
1930                 unsigned int flags)
1931 {
1932         int status;
1933         char *clientPath;
1934         TALLOC_CTX *ctx;
1935
1936         DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1937         if (!is_in_media_files(path))
1938         {
1939                 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1940                 goto out;
1941         }
1942
1943         clientPath = NULL;
1944         ctx = talloc_tos();
1945
1946         if ((status = alloc_get_client_path(handle, ctx,
1947                                 path,
1948                                 &clientPath)))
1949         {
1950                 goto err;
1951         }
1952
1953         status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1954 err:
1955         TALLOC_FREE(clientPath);
1956 out:
1957         return status;
1958 }
1959
1960 /*
1961  * Success: return NT_STATUS_OK
1962  * Failure: return NT status error
1963  */
1964 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1965                 struct files_struct *fsp,
1966                 const struct smb_filename *smb_fname,
1967                 TALLOC_CTX *ctx,
1968                 unsigned int *num_streams,
1969                 struct stream_struct **streams)
1970 {
1971         NTSTATUS status;
1972         int ret;
1973         struct smb_filename *clientFname = NULL;
1974
1975         DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1976         if (!is_in_media_files(smb_fname->base_name)) {
1977                 status = SMB_VFS_NEXT_STREAMINFO(handle,
1978                                 fsp,
1979                                 smb_fname,
1980                                 ctx,
1981                                 num_streams,
1982                                 streams);
1983                 goto out;
1984         }
1985
1986         ret = alloc_get_client_smb_fname(handle,
1987                                 talloc_tos(),
1988                                 smb_fname,
1989                                 &clientFname);
1990         if (ret != 0) {
1991                 status = NT_STATUS_NO_MEMORY;
1992                 goto err;
1993         }
1994
1995         /* This only works on files, so we don't have to worry about
1996          * our fake directory stat'ing here.
1997          */
1998         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientFname,
1999                                 ctx, num_streams, streams);
2000 err:
2001         TALLOC_FREE(clientFname);
2002 out:
2003         return status;
2004 }
2005
2006 /* Ignoring get_real_filename function because the default
2007  * doesn't do anything.
2008  */
2009
2010 /*
2011  * Success: return NT_STATUS_OK
2012  * Failure: return NT status error
2013  * In this case, "name" is a path.
2014  */
2015 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2016                               const struct smb_filename *smb_fname,
2017                               uint32_t security_info,
2018                               TALLOC_CTX *mem_ctx,
2019                               struct security_descriptor **ppdesc)
2020 {
2021         NTSTATUS status;
2022         char *clientPath;
2023         struct smb_filename *client_smb_fname = NULL;
2024         TALLOC_CTX *ctx;
2025
2026         DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2027         if (!is_in_media_files(smb_fname->base_name))
2028         {
2029                 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
2030                                                  security_info,
2031                                                  mem_ctx, ppdesc);
2032                 goto out;
2033         }
2034
2035         clientPath = NULL;
2036         ctx = talloc_tos();
2037
2038         if (alloc_get_client_path(handle, ctx,
2039                                 smb_fname->base_name,
2040                                 &clientPath))
2041         {
2042                 status = map_nt_error_from_unix(errno);
2043                 goto err;
2044         }
2045
2046         client_smb_fname = synthetic_smb_fname(talloc_tos(),
2047                                         clientPath,
2048                                         NULL,
2049                                         NULL,
2050                                         smb_fname->flags);
2051         if (client_smb_fname == NULL) {
2052                 TALLOC_FREE(clientPath);
2053                 return NT_STATUS_NO_MEMORY;
2054         }
2055
2056         status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
2057                                          security_info,
2058                                          mem_ctx, ppdesc);
2059 err:
2060         TALLOC_FREE(clientPath);
2061         TALLOC_FREE(client_smb_fname);
2062 out:
2063         return status;
2064 }
2065
2066 /*
2067  * Success: return 0
2068  * Failure: set errno, return -1
2069  */
2070 static int mh_chmod_acl(vfs_handle_struct *handle,
2071                 const struct smb_filename *smb_fname,
2072                 mode_t mode)
2073 {
2074         int status;
2075         struct smb_filename *clientFname = NULL;
2076
2077         DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2078         if (!is_in_media_files(smb_fname->base_name))
2079         {
2080                 status = SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2081                 goto out;
2082         }
2083
2084         status = alloc_get_client_smb_fname(handle,
2085                                 talloc_tos(),
2086                                 smb_fname,
2087                                 &clientFname);
2088         if (status != 0) {
2089                 goto err;
2090         }
2091
2092         status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientFname, mode);
2093 err:
2094         TALLOC_FREE(clientFname);
2095 out:
2096         return status;
2097 }
2098
2099 /*
2100  * Success: return acl pointer
2101  * Failure: set errno, return NULL
2102  */
2103 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2104                                 const struct smb_filename *smb_fname,
2105                                 SMB_ACL_TYPE_T type,
2106                                 TALLOC_CTX *mem_ctx)
2107 {
2108         SMB_ACL_T ret;
2109         int status;
2110         struct smb_filename *clientFname = NULL;
2111
2112         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2113         if (!is_in_media_files(smb_fname->base_name)) {
2114                 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
2115                                 type, mem_ctx);
2116                 goto out;
2117         }
2118
2119         status = alloc_get_client_smb_fname(handle,
2120                                 talloc_tos(),
2121                                 smb_fname,
2122                                 &clientFname);
2123         if (status != 0) {
2124                 ret = (SMB_ACL_T)NULL;
2125                 goto err;
2126         }
2127
2128         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientFname, type, mem_ctx);
2129 err:
2130         TALLOC_FREE(clientFname);
2131 out:
2132         return ret;
2133 }
2134
2135 /*
2136  * Success: return 0
2137  * Failure: set errno, return -1
2138  * In this case, "name" is a path.
2139  */
2140 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2141                 const struct smb_filename *smb_fname,
2142                 SMB_ACL_TYPE_T acltype,
2143                 SMB_ACL_T theacl)
2144 {
2145         int status;
2146         struct smb_filename *clientFname = NULL;
2147
2148         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2149         if (!is_in_media_files(smb_fname->base_name)) {
2150                 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
2151                                 acltype, theacl);
2152                 goto out;
2153         }
2154
2155         status = alloc_get_client_smb_fname(handle,
2156                                 talloc_tos(),
2157                                 smb_fname,
2158                                 &clientFname);
2159         if (status != 0) {
2160                 goto err;
2161         }
2162
2163         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientFname,
2164                         acltype, theacl);
2165 err:
2166         TALLOC_FREE(clientFname);
2167 out:
2168         return status;
2169 }
2170
2171 /*
2172  * Success: return 0
2173  * Failure: set errno, return -1
2174  */
2175 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2176                         const struct smb_filename *smb_fname)
2177 {
2178         int status;
2179         struct smb_filename *clientFname = NULL;
2180
2181         DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2182         if (!is_in_media_files(smb_fname->base_name)) {
2183                 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2184                                 smb_fname);
2185                 goto out;
2186         }
2187
2188         status = alloc_get_client_smb_fname(handle,
2189                                 talloc_tos(),
2190                                 smb_fname,
2191                                 &clientFname);
2192         if (status != 0) {
2193                 goto err;
2194         }
2195         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientFname);
2196 err:
2197         TALLOC_FREE(clientFname);
2198 out:
2199         return status;
2200 }
2201
2202 /*
2203  * Success: return positive number
2204  * Failure: set errno, return -1
2205  * In this case, "name" is an attr name.
2206  */
2207 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2208                 const char *path,
2209                 const char *name,
2210                 void *value,
2211                 size_t size)
2212 {
2213         ssize_t ret;
2214         char *clientPath;
2215         TALLOC_CTX *ctx;
2216
2217         DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2218         if (!is_in_media_files(path))
2219         {
2220                 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2221                                 size);
2222                 goto out;
2223         }
2224
2225         clientPath = NULL;
2226         ctx = talloc_tos();
2227
2228         if (alloc_get_client_path(handle, ctx,
2229                                 path,
2230                                 &clientPath))
2231         {
2232                 ret = -1;
2233                 goto err;
2234         }
2235
2236         ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2237 err:
2238         TALLOC_FREE(clientPath);
2239 out:
2240         return ret;
2241 }
2242
2243 /*
2244  * Success: return positive number
2245  * Failure: set errno, return -1
2246  */
2247 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2248                 const struct smb_filename *smb_fname,
2249                 char *list,
2250                 size_t size)
2251 {
2252         ssize_t ret;
2253         struct smb_filename *clientFname = NULL;
2254         int status;
2255
2256         DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2257         if (!is_in_media_files(smb_fname->base_name)) {
2258                 ret = SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
2259                 goto out;
2260         }
2261
2262         status = alloc_get_client_smb_fname(handle,
2263                                 talloc_tos(),
2264                                 smb_fname,
2265                                 &clientFname);
2266         if (status != 0) {
2267                 ret = -1;
2268                 goto err;
2269         }
2270
2271         ret = SMB_VFS_NEXT_LISTXATTR(handle, clientFname, list, size);
2272 err:
2273         TALLOC_FREE(clientFname);
2274 out:
2275         return ret;
2276 }
2277
2278 /*
2279  * Success: return 0
2280  * Failure: set errno, return -1
2281  * In this case, "name" is an attr name.
2282  */
2283 static int mh_removexattr(struct vfs_handle_struct *handle,
2284                 const char *path,
2285                 const char *name)
2286 {
2287         int status;
2288         char *clientPath;
2289         TALLOC_CTX *ctx;
2290
2291         DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2292         if (!is_in_media_files(path))
2293         {
2294                 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2295                 goto out;
2296         }
2297
2298         clientPath = NULL;
2299         ctx = talloc_tos();
2300
2301         if ((status = alloc_get_client_path(handle, ctx,
2302                                 path,
2303                                 &clientPath)))
2304         {
2305                 goto err;
2306         }
2307
2308         status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2309 err:
2310         TALLOC_FREE(clientPath);
2311 out:
2312         return status;
2313 }
2314
2315 /*
2316  * Success: return 0
2317  * Failure: set errno, return -1
2318  * In this case, "name" is an attr name.
2319  */
2320 static int mh_setxattr(struct vfs_handle_struct *handle,
2321                 const char *path,
2322                 const char *name,
2323                 const void *value,
2324                 size_t size,
2325                 int flags)
2326 {
2327         int status;
2328         char *clientPath;
2329         TALLOC_CTX *ctx;
2330
2331         DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2332         if (!is_in_media_files(path))
2333         {
2334                 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2335                                 size, flags);
2336                 goto out;
2337         }
2338
2339         clientPath = NULL;
2340         ctx = talloc_tos();
2341
2342         if ((status = alloc_get_client_path(handle, ctx,
2343                                 path,
2344                                 &clientPath)))
2345         {
2346                 goto err;
2347         }
2348
2349         status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2350                         size, flags);
2351 err:
2352         TALLOC_FREE(clientPath);
2353 out:
2354         return status;
2355 }
2356
2357 /* VFS operations structure */
2358
2359 static struct vfs_fn_pointers vfs_mh_fns = {
2360         /* Disk operations */
2361
2362         .statvfs_fn = mh_statvfs,
2363
2364         /* Directory operations */
2365
2366         .opendir_fn = mh_opendir,
2367         .fdopendir_fn = mh_fdopendir,
2368         .readdir_fn = mh_readdir,
2369         .seekdir_fn = mh_seekdir,
2370         .telldir_fn = mh_telldir,
2371         .rewind_dir_fn = mh_rewinddir,
2372         .mkdir_fn = mh_mkdir,
2373         .rmdir_fn = mh_rmdir,
2374         .closedir_fn = mh_closedir,
2375         .init_search_op_fn = mh_init_search_op,
2376
2377         /* File operations */
2378
2379         .open_fn = mh_open,
2380         .create_file_fn = mh_create_file,
2381         .rename_fn = mh_rename,
2382         .stat_fn = mh_stat,
2383         .lstat_fn = mh_lstat,
2384         .fstat_fn = mh_fstat,
2385         .unlink_fn = mh_unlink,
2386         .chmod_fn = mh_chmod,
2387         .chown_fn = mh_chown,
2388         .lchown_fn = mh_lchown,
2389         .chdir_fn = mh_chdir,
2390         .ntimes_fn = mh_ntimes,
2391         .symlink_fn = mh_symlink,
2392         .readlink_fn = mh_readlink,
2393         .link_fn = mh_link,
2394         .mknod_fn = mh_mknod,
2395         .realpath_fn = mh_realpath,
2396         .chflags_fn = mh_chflags,
2397         .streaminfo_fn = mh_streaminfo,
2398
2399         /* NT ACL operations. */
2400
2401         .get_nt_acl_fn = mh_get_nt_acl,
2402
2403         /* POSIX ACL operations. */
2404
2405         .chmod_acl_fn = mh_chmod_acl,
2406
2407         .sys_acl_get_file_fn = mh_sys_acl_get_file,
2408         .sys_acl_set_file_fn = mh_sys_acl_set_file,
2409         .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2410
2411         /* EA operations. */
2412         .getxattr_fn = mh_getxattr,
2413         .listxattr_fn = mh_listxattr,
2414         .removexattr_fn = mh_removexattr,
2415         .setxattr_fn = mh_setxattr,
2416
2417         /* aio operations */
2418 };
2419
2420 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *);
2421 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
2422 {
2423         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2424                                 "media_harmony", &vfs_mh_fns);
2425         if (!NT_STATUS_IS_OK(ret))
2426         {
2427                 goto out;
2428         }
2429
2430         vfs_mh_debug_level = debug_add_class("media_harmony");
2431
2432         if (vfs_mh_debug_level == -1) {
2433                 vfs_mh_debug_level = DBGC_VFS;
2434                 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2435                                 "debugging class.\n"));
2436         } else {
2437                 DEBUG(3, ("media_harmony_init: Debug class number of "
2438                                 "'media_harmony': %d\n",
2439                                 vfs_mh_debug_level));
2440         }
2441
2442 out:
2443         return ret;
2444 }