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