s3: VFS: Change SMB_VFS_SYMLINK to use const struct smb_filename * instead of const...
[sfrench/samba-autobuild/.git] / source3 / modules / vfs_unityed_media.c
1 /*
2  * Samba VFS module supporting multiple AVID clients sharing media.
3  *
4  * Copyright (C) 2005  Philip de Nier <philipn@users.sourceforge.net>
5  * Copyright (C) 2012  Andrew Klaassen <clawsoon@yahoo.com>
6  * Copyright (C) 2013  Milos Lukacek
7  * Copyright (C) 2013  Ralph Boehme <slow@samba.org>
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  * Unityed Media is a Samba VFS module that allows multiple AVID
27  * clients to share media.
28  *
29  * Add this module to the vfs objects option in your Samba share
30  * configuration.
31  * eg.
32  *
33  *   [avid_win]
34  *      path = /video
35  *      vfs objects = unityed_media
36  *      ...
37  *
38  * It is recommended that you separate out Samba shares for Mac
39  * and Windows clients, and add the following options to the shares
40  * for Windows clients  (NOTE: replace @ with *):
41  *
42  *      veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
43  *      delete veto files = yes
44  *
45  * This prevents hidden files from Mac clients interfering with Windows
46  * clients. If you find any more problem hidden files then add them to
47  * the list.
48  *
49  * Notes:
50  * This module is designed to work with AVID editing applications that
51  * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
52  * It is not designed to work as expected in all circumstances for
53  * general use.
54  */
55
56
57 #include "includes.h"
58 #include "system/filesys.h"
59 #include "smbd/smbd.h"
60 #include "../smbd/globals.h"
61 #include "auth.h"
62 #include "../lib/tsocket/tsocket.h"
63 #include <libgen.h>
64
65 #define UM_PARAM_TYPE_NAME "unityed_media"
66
67 static const char *AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
68 static const size_t AVID_MXF_DIRNAME_LEN = 19;
69 static const char *OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
70 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
71 static const char *APPLE_DOUBLE_PREFIX = "._";
72 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
73 static int vfs_um_debug_level = DBGC_VFS;
74
75 enum um_clientid {UM_CLIENTID_NAME, UM_CLIENTID_IP, UM_CLIENTID_HOSTNAME};
76
77 struct um_config_data {
78         enum um_clientid clientid;
79 };
80
81 static const struct enum_list um_clientid[] = {
82         {UM_CLIENTID_NAME, "user"},
83         {UM_CLIENTID_IP, "ip"},
84         {UM_CLIENTID_HOSTNAME, "hostname"},
85         {-1, NULL}
86 };
87
88 /* supplements the directory list stream */
89 typedef struct um_dirinfo_struct {
90         DIR* dirstream;
91         char *dirpath;
92         char *clientPath;
93         bool isInMediaFiles;
94         char *clientSubDirname;
95 } um_dirinfo_struct;
96
97 /**
98  * Returns true and first group of digits in path, false and 0 otherwise
99  **/
100 static bool get_digit_group(const char *path, uintmax_t *digit)
101 {
102         const char *p = path;
103         char *endp = NULL;
104         codepoint_t cp;
105         size_t size;
106
107         DEBUG(10, ("get_digit_group entering with path '%s'\n",
108                    path));
109
110         /*
111          * Delibiretly initialize to 0 because callers use this result
112          * even though the string doesn't contain any number and we
113          * returned false
114          */
115         *digit = 0;
116
117         while (*p) {
118                 cp = next_codepoint(p, &size);
119                 if (cp == -1) {
120                         return false;
121                 }
122                 if ((size == 1) && (isdigit(cp))) {
123                         *digit = (uintmax_t)strtoul(p, &endp, 10);
124                         DEBUG(10, ("num_suffix = '%ju'\n",
125                                    *digit));
126                         return true;
127                 }
128                 p += size;
129         }
130
131         return false;
132 }
133
134 /* Add "_<remote_name>.<number>" suffix to path or filename.
135  *
136  * Success: return 0
137  * Failure: set errno, path NULL, return -1
138  */
139
140 static int alloc_append_client_suffix(vfs_handle_struct *handle,
141                                       char **path)
142 {
143         int status = 0;
144         uintmax_t number;
145         const char *clientid;
146         struct um_config_data *config;
147
148         DEBUG(10, ("Entering with path '%s'\n", *path));
149
150         SMB_VFS_HANDLE_GET_DATA(handle, config,
151                                 struct um_config_data,
152                                 return -1);
153
154         (void)get_digit_group(*path, &number);
155
156         switch (config->clientid) {
157
158         case UM_CLIENTID_IP:
159                 clientid = tsocket_address_inet_addr_string(
160                         handle->conn->sconn->remote_address, talloc_tos());
161                 if (clientid == NULL) {
162                         errno = ENOMEM;
163                         status = -1;
164                         goto err;
165                 }
166                 break;
167
168         case UM_CLIENTID_HOSTNAME:
169                 clientid = get_remote_machine_name();
170                 break;
171
172         case UM_CLIENTID_NAME:
173         default:
174                 clientid = get_current_username();
175                 break;
176         }
177
178         *path = talloc_asprintf_append(*path, "_%s.%ju",
179                                        clientid, number);
180         if (*path == NULL) {
181                 DEBUG(1, ("alloc_append_client_suffix "
182                                      "out of memory\n"));
183                 errno = ENOMEM;
184                 status = -1;
185                 goto err;
186         }
187         DEBUG(10, ("Leaving with *path '%s'\n", *path));
188 err:
189         return status;
190 }
191
192 /* Returns true if the file or directory begins with the appledouble
193  * prefix.
194  */
195 static bool is_apple_double(const char* fname)
196 {
197         bool ret = false;
198
199         DEBUG(10, ("Entering with fname '%s'\n", fname));
200
201         if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
202                 ret = true;
203         }
204         DEBUG(10, ("Leaving with ret '%s'\n",
205                               ret == true ? "true" : "false"));
206         return ret;
207 }
208
209 static bool starts_with_media_dir(const char* media_dirname,
210                                   size_t media_dirname_len,
211                                   const char *path)
212 {
213         bool ret = false;
214         const char *path_start = path;
215
216         DEBUG(10, ("Entering with media_dirname '%s' "
217                               "path '%s'\n", media_dirname, path));
218
219         /* Sometimes Samba gives us "./OMFI MediaFiles". */
220         if (strnequal(path, "./", 2)) {
221                 path_start += 2;
222         }
223
224         if (strnequal(media_dirname, path_start, media_dirname_len)
225             &&
226             ((path_start[media_dirname_len] == '\0') ||
227              (path_start[media_dirname_len] == '/'))) {
228                 ret = true;
229         }
230
231         DEBUG(10, ("Leaving with ret '%s'\n",
232                               ret == true ? "true" : "false"));
233         return ret;
234 }
235
236 /*
237  * Returns true if the file or directory referenced by the path is ONE
238  * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
239  * directory
240  */
241 static bool is_in_media_dir(const char *path)
242 {
243         int transition_count = 0;
244         const char *path_start = path;
245         const char *p;
246         const char *media_dirname;
247         size_t media_dirname_len;
248
249         DEBUG(10, ("Entering with path'%s' ", path));
250
251         /* Sometimes Samba gives us "./OMFI MediaFiles". */
252         if (strnequal(path, "./", 2)) {
253                 path_start += 2;
254         }
255
256         if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
257                 media_dirname = AVID_MXF_DIRNAME;
258                 media_dirname_len = AVID_MXF_DIRNAME_LEN;
259         } else if (strnequal(path_start,
260                              OMFI_MEDIAFILES_DIRNAME,
261                              OMFI_MEDIAFILES_DIRNAME_LEN)) {
262                 media_dirname = OMFI_MEDIAFILES_DIRNAME;
263                 media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
264         } else {
265                 return false;
266         }
267
268         if (path_start[media_dirname_len] == '\0') {
269                 goto out;
270         }
271
272         p = path_start + media_dirname_len + 1;
273
274         while (true) {
275                 if (*p == '\0' || *p == '/') {
276                         if (strnequal(p - 3, "/..", 3)) {
277                                 transition_count--;
278                         } else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
279                                 transition_count++;
280                         }
281                 }
282                 if (*p == '\0') {
283                         break;
284                 }
285                 p++;
286         }
287
288 out:
289         DEBUG(10, ("Going out with transition_count '%i'\n",
290                               transition_count));
291         if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
292             ||
293             ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
294                 return true;
295         }
296         else return false;
297 }
298
299 /*
300  * Returns true if the file or directory referenced by the path is
301  * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
302  * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
303  * are assumed to be in the root directory, which is generally a safe
304  * assumption in the fixed-path world of Avid.
305  */
306 static bool is_in_media_files(const char *path)
307 {
308         bool ret = false;
309
310         DEBUG(10, ("Entering with path '%s'\n", path));
311
312         if (starts_with_media_dir(AVID_MXF_DIRNAME,
313                                   AVID_MXF_DIRNAME_LEN, path) ||
314             starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
315                                   OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
316                 ret = true;
317         }
318         DEBUG(10, ("Leaving with ret '%s'\n",
319                               ret == true ? "true" : "false"));
320         return ret;
321 }
322
323
324 /* Add client suffix to "pure-number" path.
325  *
326  * Caller must free newPath.
327  *
328  * Success: return 0
329  * Failure: set errno, newPath NULL, return -1
330  */
331 static int alloc_get_client_path(vfs_handle_struct *handle,
332                                  TALLOC_CTX *ctx,
333                                  const char *path_in,
334                                  char **path_out)
335 {
336         int status = 0;
337         char *p;
338         char *digits;
339         size_t digits_len;
340         uintmax_t number;
341
342         *path_out = talloc_strdup(ctx, path_in);
343         if (*path_out == NULL) {
344                 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
345                 return -1;
346         }
347
348         (void)get_digit_group(*path_out, &number);
349
350         digits = talloc_asprintf(NULL, "%ju", number);
351         if (digits == NULL) {
352                 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
353                 return -1;
354         }
355         digits_len = strlen(digits);
356
357         p = strstr_m(path_in, digits);
358         if ((p)
359             &&
360             ((p[digits_len] == '\0') || (p[digits_len] == '/'))
361             &&
362             (((p - path_in > 0) && (p[-1] == '/'))
363              ||
364              (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
365               &&
366               is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
367               &&
368               (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
369         {
370                 (*path_out)[p - path_in + digits_len] = '\0';
371
372                 status = alloc_append_client_suffix(handle, path_out);
373                 if (status != 0) {
374                         goto out;
375                 }
376
377                 *path_out = talloc_strdup_append(*path_out, p + digits_len);
378                 if (*path_out == NULL) {
379                         DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
380                         status = -1;
381                         goto out;
382                 }
383         }
384 out:
385         /* path_out must be freed in caller. */
386         DEBUG(10, ("Result:'%s'\n", *path_out));
387         return status;
388 }
389
390 /*
391  * Success: return 0
392  * Failure: set errno, return -1
393  */
394 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
395                                       TALLOC_CTX *ctx,
396                                       const struct smb_filename *smb_fname,
397                                       struct smb_filename **client_fname)
398 {
399         int status ;
400
401         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
402                    smb_fname->base_name));
403
404         *client_fname = cp_smb_filename(ctx, smb_fname);
405         if (*client_fname == NULL) {
406                 DEBUG(1, ("cp_smb_filename returned NULL\n"));
407                 return -1;
408         }
409         status = alloc_get_client_path(handle, ctx,
410                                        smb_fname->base_name,
411                                        &(*client_fname)->base_name);
412         if (status != 0) {
413                 return -1;
414         }
415
416         DEBUG(10, ("Leaving with (*client_fname)->base_name "
417                    "'%s'\n", (*client_fname)->base_name));
418
419         return 0;
420 }
421
422
423 /*
424  * Success: return 0
425  * Failure: set errno, return -1
426  */
427 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
428                                          TALLOC_CTX *ctx,
429                                          char **path,
430                                          const char *suffix_number)
431 {
432         int status;
433
434         DEBUG(10, ("Entering with suffix_number '%s'\n",
435                    suffix_number));
436
437         *path = talloc_strdup(ctx, suffix_number);
438         if (*path == NULL) {
439                 DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
440                 return -1;
441         }
442         status = alloc_append_client_suffix(handle, path);
443         if (status != 0) {
444                 return -1;
445         }
446
447         DEBUG(10, ("Leaving with *path '%s'\n", *path));
448
449         return 0;
450 }
451
452 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
453                                     const char *fname,
454                                     struct um_dirinfo_struct **di_result)
455 {
456         int status = 0;
457         char *digits;
458         uintmax_t number;
459         struct um_dirinfo_struct *dip;
460
461         DEBUG(10, ("Entering with fname '%s'\n", fname));
462
463         *di_result = talloc(NULL, struct um_dirinfo_struct);
464         if (*di_result == NULL) {
465                 goto err;
466         }
467         dip = *di_result;
468
469         dip->dirpath = talloc_strdup(dip, fname);
470         if (dip->dirpath == NULL) {
471                 goto err;
472         }
473
474         if (!is_in_media_files(fname)) {
475                 dip->isInMediaFiles = false;
476                 dip->clientPath = NULL;
477                 dip->clientSubDirname = NULL;
478                 goto out;
479         }
480
481         dip->isInMediaFiles = true;
482
483         (void)get_digit_group(fname, &number);
484         digits = talloc_asprintf(talloc_tos(), "%ju", number);
485         if (digits == NULL) {
486                 goto err;
487         }
488
489         status = alloc_set_client_dirinfo_path(handle, dip,
490                                                &dip->clientSubDirname,
491                                                digits);
492         if (status != 0) {
493                 goto err;
494         }
495
496         status = alloc_get_client_path(handle, dip, fname,
497                                        &dip->clientPath);
498         if (status != 0 || dip->clientPath == NULL) {
499                 goto err;
500         }
501
502 out:
503         DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
504                               "(*dirInfo)->clientPath '%s'\n",
505                               dip->dirpath, dip->clientPath));
506         return status;
507
508 err:
509         DEBUG(1, ("Failing with fname '%s'\n", fname));
510         TALLOC_FREE(*di_result);
511         status = -1;
512         errno = ENOMEM;
513         return status;
514 }
515
516 /**********************************************************************
517  * VFS functions
518  **********************************************************************/
519
520 /*
521  * Success: return 0
522  * Failure: set errno, return -1
523  */
524 static int um_statvfs(struct vfs_handle_struct *handle,
525                       const struct smb_filename *smb_fname,
526                       struct vfs_statvfs_struct *statbuf)
527 {
528         int status;
529         struct smb_filename *client_fname = NULL;
530
531         DEBUG(10, ("Entering with path '%s'\n", smb_fname->base_name));
532
533         if (!is_in_media_files(smb_fname->base_name)) {
534                 return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
535         }
536
537         status = alloc_get_client_smb_fname(handle,
538                                 talloc_tos(),
539                                 smb_fname,
540                                 &client_fname);
541         if (status != 0) {
542                 goto err;
543         }
544
545         status = SMB_VFS_NEXT_STATVFS(handle, client_fname, statbuf);
546 err:
547         TALLOC_FREE(client_fname);
548         DEBUG(10, ("Leaving with path '%s'\n", smb_fname->base_name));
549         return status;
550 }
551
552 /* Success: return a um_dirinfo_struct cast as a DIR
553  * Failure: set errno, return NULL
554  */
555 static DIR *um_opendir(vfs_handle_struct *handle,
556                        const struct smb_filename *smb_fname,
557                        const char *mask,
558                        uint32_t attr)
559 {
560         struct um_dirinfo_struct *dirInfo;
561
562         DEBUG(10, ("Entering with fname '%s'\n", smb_fname->base_name));
563
564         if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo)) {
565                 goto err;
566         }
567
568         if (!dirInfo->isInMediaFiles) {
569                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
570                         handle, smb_fname, mask, attr);
571         } else {
572                 struct smb_filename *client_smb_fname =
573                         synthetic_smb_fname(talloc_tos(),
574                                         dirInfo->clientPath,
575                                         NULL,
576                                         NULL,
577                                         smb_fname->flags);
578                 if (client_smb_fname == NULL) {
579                         goto err;
580                 }
581
582                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
583                         handle, client_smb_fname, mask, attr);
584
585                 TALLOC_FREE(client_smb_fname);
586         }
587
588         if (dirInfo->dirstream == NULL) {
589                 goto err;
590         }
591
592         DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
593                               "dirInfo->clientPath '%s'\n",
594                               dirInfo->dirpath,
595                               dirInfo->clientPath));
596         return (DIR*)dirInfo;
597
598 err:
599         DEBUG(1, ("Failing with fname '%s'\n", smb_fname->base_name));
600         TALLOC_FREE(dirInfo);
601         return NULL;
602 }
603
604 static DIR *um_fdopendir(vfs_handle_struct *handle,
605                          files_struct *fsp,
606                          const char *mask,
607                          uint32_t attr)
608 {
609         struct um_dirinfo_struct *dirInfo = NULL;
610         DIR *dirstream;
611
612         DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
613                    fsp->fsp_name->base_name));
614
615         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
616         if (!dirstream) {
617                 goto err;
618         }
619
620         if (alloc_set_client_dirinfo(handle,
621                                      fsp->fsp_name->base_name,
622                                      &dirInfo)) {
623                 goto err;
624         }
625
626         dirInfo->dirstream = dirstream;
627
628         if (!dirInfo->isInMediaFiles) {
629                 /*
630                  * FIXME: this is the original code, something must be
631                  * missing here, but what? -slow
632                  */
633                 goto out;
634         }
635
636 out:
637         DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
638                    "dirInfo->clientPath '%s', "
639                    "fsp->fsp_name->st.st_ex_mtime %s",
640                    dirInfo->dirpath,
641                    dirInfo->clientPath,
642                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
643         return (DIR *) dirInfo;
644
645 err:
646         DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
647                   fsp->fsp_name->base_name));
648         TALLOC_FREE(dirInfo);
649         return NULL;
650 }
651
652 /*
653  * skip own suffixed directory
654  * replace own suffixed directory with non suffixed.
655  *
656  * Success: return dirent
657  * End of data: return NULL
658  * Failure: set errno, return NULL
659  */
660 static struct dirent *um_readdir(vfs_handle_struct *handle,
661                                  DIR *dirp,
662                                  SMB_STRUCT_STAT *sbuf)
663 {
664         um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
665         struct dirent *d = NULL;
666         int skip;
667
668         DEBUG(10, ("dirInfo->dirpath '%s', "
669                    "dirInfo->clientPath '%s', "
670                    "dirInfo->isInMediaFiles '%s', "
671                    "dirInfo->clientSubDirname '%s'\n",
672                    dirInfo->dirpath,
673                    dirInfo->clientPath,
674                    dirInfo->isInMediaFiles ? "true" : "false",
675                    dirInfo->clientSubDirname));
676
677         if (!dirInfo->isInMediaFiles) {
678                 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
679         }
680
681         do {
682                 const char* dname;
683                 bool isAppleDouble;
684                 char *digits;
685                 size_t digits_len;
686                 uintmax_t number;
687
688                 skip = false;
689                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
690
691                 if (d == NULL) {
692                         break;
693                 }
694
695                 /* ignore apple double prefix for logic below */
696                 if (is_apple_double(d->d_name)) {
697                         dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
698                         isAppleDouble = true;
699                 } else {
700                         dname = d->d_name;
701                         isAppleDouble = false;
702                 }
703
704                 DEBUG(10, ("dname = '%s'\n", dname));
705
706                 (void)get_digit_group(dname, &number);
707                 digits = talloc_asprintf(talloc_tos(), "%ju", number);
708                 if (digits == NULL) {
709                         DEBUG(1, ("out of memory"));
710                         goto err;
711                 }
712                 digits_len = strlen(digits);
713
714                 if (alloc_set_client_dirinfo_path(handle,
715                                                   dirInfo,
716                                                   &((dirInfo)->clientSubDirname),
717                                                   digits)) {
718                         goto err;
719                 }
720
721                 /*
722                  * If set to "true", vfs shows digits-only
723                  * non-suffixed subdirectories.  Normally, such
724                  * subdirectories can exists only in non-media
725                  * directories, so we set it to "false".  Otherwise,
726                  * if we have such subdirectories (probably created
727                  * over not "unityed" connection), it can be little
728                  * bit confusing.
729                  */
730                 if (strequal(dname, digits)) {
731                         skip = false;
732                 } else if (strequal(dname, dirInfo->clientSubDirname)) {
733                         /*
734                          * Remove suffix of this client's suffixed
735                          * subdirectories
736                          */
737                         if (isAppleDouble) {
738                                 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
739                         } else {
740                                 d->d_name[digits_len] = '\0';
741                         }
742                 } else if (strnequal(digits, dname, digits_len)) {
743                         /*
744                          * Set to false to see another clients subdirectories
745                          */
746                         skip = false;
747                 }
748         } while (skip);
749
750         DEBUG(10, ("Leaving um_readdir\n"));
751         return d;
752 err:
753         TALLOC_FREE(dirInfo);
754         return NULL;
755 }
756
757 static void um_seekdir(vfs_handle_struct *handle,
758                        DIR *dirp,
759                        long offset)
760 {
761         DEBUG(10, ("Entering and leaving um_seekdir\n"));
762         SMB_VFS_NEXT_SEEKDIR(handle,
763                              ((um_dirinfo_struct*)dirp)->dirstream, offset);
764 }
765
766 static long um_telldir(vfs_handle_struct *handle,
767                        DIR *dirp)
768 {
769         DEBUG(10, ("Entering and leaving um_telldir\n"));
770         return SMB_VFS_NEXT_TELLDIR(handle,
771                                     ((um_dirinfo_struct*)dirp)->dirstream);
772 }
773
774 static void um_rewinddir(vfs_handle_struct *handle,
775                          DIR *dirp)
776 {
777         DEBUG(10, ("Entering and leaving um_rewinddir\n"));
778         SMB_VFS_NEXT_REWINDDIR(handle,
779                                ((um_dirinfo_struct*)dirp)->dirstream);
780 }
781
782 static int um_mkdir(vfs_handle_struct *handle,
783                     const struct smb_filename *smb_fname,
784                     mode_t mode)
785 {
786         int status;
787         const char *path = smb_fname->base_name;
788         struct smb_filename *client_fname = NULL;
789
790         DEBUG(10, ("Entering with path '%s'\n", path));
791
792         if (!is_in_media_files(path) || !is_in_media_dir(path)) {
793                 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
794         }
795
796         status = alloc_get_client_smb_fname(handle,
797                                 talloc_tos(),
798                                 smb_fname,
799                                 &client_fname);
800         if (status != 0) {
801                 goto err;
802         }
803
804         status = SMB_VFS_NEXT_MKDIR(handle, client_fname, mode);
805 err:
806         TALLOC_FREE(client_fname);
807         DEBUG(10, ("Leaving with path '%s'\n", path));
808         return status;
809 }
810
811 static int um_rmdir(vfs_handle_struct *handle,
812                     const struct smb_filename *smb_fname)
813 {
814         int status;
815         const char *path = smb_fname->base_name;
816         struct smb_filename *client_fname = NULL;
817
818         DEBUG(10, ("Entering with path '%s'\n", path));
819
820         if (!is_in_media_files(path)) {
821                 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
822         }
823
824         status = alloc_get_client_smb_fname(handle,
825                                 talloc_tos(),
826                                 smb_fname,
827                                 &client_fname);
828         if (status != 0) {
829                 goto err;
830         }
831
832         status = SMB_VFS_NEXT_RMDIR(handle, client_fname);
833 err:
834         TALLOC_FREE(client_fname);
835         DEBUG(10, ("Leaving with path '%s'\n", path));
836         return status;
837 }
838
839 static int um_closedir(vfs_handle_struct *handle,
840                        DIR *dirp)
841 {
842         DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
843
844         TALLOC_FREE(dirp);
845
846         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
847 }
848
849 static void um_init_search_op(vfs_handle_struct *handle,
850                               DIR *dirp)
851 {
852         DEBUG(10, ("Entering and leaving um_init_search_op\n"));
853
854         SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
855                                     ((um_dirinfo_struct*)dirp)->dirstream);
856 }
857
858 static int um_open(vfs_handle_struct *handle,
859                    struct smb_filename *smb_fname,
860                    files_struct *fsp,
861                    int flags,
862                    mode_t mode)
863 {
864         int ret;
865         struct smb_filename *client_fname = NULL;
866
867         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
868                               smb_fname->base_name));
869
870         if (!is_in_media_files(smb_fname->base_name)) {
871                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
872         }
873
874         if (alloc_get_client_smb_fname(handle, talloc_tos(),
875                                        smb_fname,
876                                        &client_fname)) {
877                 ret = -1;
878                 goto err;
879         }
880
881         /*
882          * FIXME:
883          * What about fsp->fsp_name?  We also have to get correct stat
884          * info into fsp and smb_fname for DB files, don't we?
885          */
886
887         DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
888                    "smb_fname->st.st_ex_mtime %s"
889                    "fsp->fsp_name->st.st_ex_mtime %s",
890                               smb_fname->base_name,
891                               ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
892                               ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
893
894         ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
895 err:
896         TALLOC_FREE(client_fname);
897         DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
898                               smb_fname->base_name));
899         return ret;
900 }
901
902 static NTSTATUS um_create_file(vfs_handle_struct *handle,
903                                struct smb_request *req,
904                                uint16_t root_dir_fid,
905                                struct smb_filename *smb_fname,
906                                uint32_t access_mask,
907                                uint32_t share_access,
908                                uint32_t create_disposition,
909                                uint32_t create_options,
910                                uint32_t file_attributes,
911                                uint32_t oplock_request,
912                                struct smb2_lease *lease,
913                                uint64_t allocation_size,
914                                uint32_t private_flags,
915                                struct security_descriptor *sd,
916                                struct ea_list *ea_list,
917                                files_struct **result_fsp,
918                                int *pinfo,
919                                const struct smb2_create_blobs *in_context_blobs,
920                                struct smb2_create_blobs *out_context_blobs)
921 {
922         NTSTATUS status;
923         struct smb_filename *client_fname = NULL;
924
925         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
926                    smb_fname->base_name));
927
928         if (!is_in_media_files(smb_fname->base_name)) {
929                 return SMB_VFS_NEXT_CREATE_FILE(
930                         handle,
931                         req,
932                         root_dir_fid,
933                         smb_fname,
934                         access_mask,
935                         share_access,
936                         create_disposition,
937                         create_options,
938                         file_attributes,
939                         oplock_request,
940                         lease,
941                         allocation_size,
942                         private_flags,
943                         sd,
944                         ea_list,
945                         result_fsp,
946                         pinfo,
947                         in_context_blobs,
948                         out_context_blobs);
949         }
950
951         if (alloc_get_client_smb_fname(handle, talloc_tos(),
952                                        smb_fname,
953                                        &client_fname)) {
954                 status = map_nt_error_from_unix(errno);
955                 goto err;
956         }
957
958         /*
959          * FIXME:
960          * This only creates files, so we don't have to worry about
961          * our fake directory stat'ing here.  But we still need to
962          * route stat calls for DB files properly, right?
963          */
964         status = SMB_VFS_NEXT_CREATE_FILE(
965                 handle,
966                 req,
967                 root_dir_fid,
968                 client_fname,
969                 access_mask,
970                 share_access,
971                 create_disposition,
972                 create_options,
973                 file_attributes,
974                 oplock_request,
975                 lease,
976                 allocation_size,
977                 private_flags,
978                 sd,
979                 ea_list,
980                 result_fsp,
981                 pinfo,
982                 in_context_blobs,
983                 out_context_blobs);
984 err:
985         TALLOC_FREE(client_fname);
986         DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
987                    "smb_fname->st.st_ex_mtime %s"
988                    " fsp->fsp_name->st.st_ex_mtime %s",
989                    smb_fname->base_name,
990                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
991                    (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
992                    ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
993                    "No fsp time\n"));
994         return status;
995 }
996
997 static int um_rename(vfs_handle_struct *handle,
998                      const struct smb_filename *smb_fname_src,
999                      const struct smb_filename *smb_fname_dst)
1000 {
1001         int status;
1002         struct smb_filename *src_client_fname = NULL;
1003         struct smb_filename *dst_client_fname = NULL;
1004
1005         DEBUG(10, ("Entering with "
1006                    "smb_fname_src->base_name '%s', "
1007                    "smb_fname_dst->base_name '%s'\n",
1008                    smb_fname_src->base_name,
1009                    smb_fname_dst->base_name));
1010
1011         if (!is_in_media_files(smb_fname_src->base_name)
1012             &&
1013             !is_in_media_files(smb_fname_dst->base_name)) {
1014                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1015                                            smb_fname_dst);
1016         }
1017
1018         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1019                                             smb_fname_src,
1020                                             &src_client_fname);
1021         if (status != 0) {
1022                 goto err;
1023         }
1024
1025         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1026                                             smb_fname_dst,
1027                                             &dst_client_fname);
1028
1029         if (status != 0) {
1030                 goto err;
1031         }
1032
1033         status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
1034                                      dst_client_fname);
1035 err:
1036         TALLOC_FREE(dst_client_fname);
1037         TALLOC_FREE(src_client_fname);
1038         DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
1039                    " smb_fname_dst->base_name '%s'\n",
1040                    smb_fname_src->base_name,
1041                    smb_fname_dst->base_name));
1042         return status;
1043 }
1044
1045 /*
1046  * Success: return 0
1047  * Failure: set errno, return -1
1048  */
1049 static int um_stat(vfs_handle_struct *handle,
1050                    struct smb_filename *smb_fname)
1051 {
1052         int status = 0;
1053         struct smb_filename *client_fname = NULL;
1054
1055         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1056                    smb_fname->base_name));
1057
1058         if (!is_in_media_files(smb_fname->base_name)) {
1059                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1060         }
1061
1062         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1063                                             smb_fname,
1064                                             &client_fname);
1065         if (status != 0) {
1066                 goto err;
1067         }
1068         DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1069                    client_fname->base_name));
1070
1071         status = SMB_VFS_NEXT_STAT(handle, client_fname);
1072         if (status != 0) {
1073                 goto err;
1074         }
1075
1076         /*
1077          * Unlike functions with const smb_filename, we have to modify
1078          * smb_fname itself to pass our info back up.
1079          */
1080         DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1081                    smb_fname->base_name, client_fname->base_name));
1082         smb_fname->st = client_fname->st;
1083
1084 err:
1085         TALLOC_FREE(client_fname);
1086         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1087                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1088         return status;
1089 }
1090
1091 static int um_lstat(vfs_handle_struct *handle,
1092                     struct smb_filename *smb_fname)
1093 {
1094         int status = 0;
1095         struct smb_filename *client_fname = NULL;
1096
1097         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1098                    smb_fname->base_name));
1099
1100         if (!is_in_media_files(smb_fname->base_name)) {
1101                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1102         }
1103
1104         client_fname = NULL;
1105
1106         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1107                                             smb_fname,
1108                                             &client_fname);
1109         if (status != 0) {
1110                 goto err;
1111         }
1112         status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1113         if (status != 0) {
1114                 goto err;
1115         }
1116
1117         smb_fname->st = client_fname->st;
1118
1119 err:
1120         TALLOC_FREE(client_fname);
1121         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1122                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1123         return status;
1124 }
1125
1126 static int um_fstat(vfs_handle_struct *handle,
1127                     files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1128 {
1129         int status = 0;
1130
1131         DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1132                    "'%s'\n", fsp_str_dbg(fsp)));
1133
1134         status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1135         if (status != 0) {
1136                 goto out;
1137         }
1138
1139         if ((fsp->fsp_name == NULL) ||
1140             !is_in_media_files(fsp->fsp_name->base_name)) {
1141                 goto out;
1142         }
1143
1144         status = um_stat(handle, fsp->fsp_name);
1145         if (status != 0) {
1146                 goto out;
1147         }
1148
1149         *sbuf = fsp->fsp_name->st;
1150
1151 out:
1152         DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1153                    fsp->fsp_name != NULL ?
1154                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1155         return status;
1156 }
1157
1158 static int um_unlink(vfs_handle_struct *handle,
1159                      const struct smb_filename *smb_fname)
1160 {
1161         int status;
1162         struct smb_filename *client_fname = NULL;
1163
1164         DEBUG(10, ("Entering um_unlink\n"));
1165
1166         if (!is_in_media_files(smb_fname->base_name)) {
1167                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1168         }
1169
1170         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1171                                             smb_fname,
1172                                             &client_fname);
1173         if (status != 0) {
1174                 goto err;
1175         }
1176
1177         status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
1178
1179 err:
1180         TALLOC_FREE(client_fname);
1181         return status;
1182 }
1183
1184 static int um_chmod(vfs_handle_struct *handle,
1185                         const struct smb_filename *smb_fname,
1186                         mode_t mode)
1187 {
1188         int status;
1189         struct smb_filename *client_fname = NULL;
1190
1191         DEBUG(10, ("Entering um_chmod\n"));
1192
1193         if (!is_in_media_files(smb_fname->base_name)) {
1194                 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1195         }
1196
1197         status = alloc_get_client_smb_fname(handle,
1198                                 talloc_tos(),
1199                                 smb_fname,
1200                                 &client_fname);
1201         if (status != 0) {
1202                 goto err;
1203         }
1204
1205         status = SMB_VFS_NEXT_CHMOD(handle, client_fname, mode);
1206
1207 err:
1208         TALLOC_FREE(client_fname);
1209         return status;
1210 }
1211
1212 static int um_chown(vfs_handle_struct *handle,
1213                         const struct smb_filename *smb_fname,
1214                         uid_t uid,
1215                         gid_t gid)
1216 {
1217         int status;
1218         struct smb_filename *client_fname = NULL;
1219
1220         DEBUG(10, ("Entering um_chown\n"));
1221
1222         if (!is_in_media_files(smb_fname->base_name)) {
1223                 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1224         }
1225
1226         status = alloc_get_client_smb_fname(handle,
1227                                 talloc_tos(),
1228                                 smb_fname,
1229                                 &client_fname);
1230         if (status != 0) {
1231                 goto err;
1232         }
1233
1234         status = SMB_VFS_NEXT_CHOWN(handle, client_fname, uid, gid);
1235
1236 err:
1237         TALLOC_FREE(client_fname);
1238         return status;
1239 }
1240
1241 static int um_lchown(vfs_handle_struct *handle,
1242                         const struct smb_filename *smb_fname,
1243                         uid_t uid,
1244                         gid_t gid)
1245 {
1246         int status;
1247         struct smb_filename *client_fname = NULL;
1248
1249         DEBUG(10, ("Entering um_lchown\n"));
1250         if (!is_in_media_files(smb_fname->base_name)) {
1251                 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1252         }
1253
1254         status = alloc_get_client_smb_fname(handle,
1255                                 talloc_tos(),
1256                                 smb_fname,
1257                                 &client_fname);
1258         if (status != 0) {
1259                 goto err;
1260         }
1261
1262         status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1263
1264 err:
1265         TALLOC_FREE(client_fname);
1266         return status;
1267 }
1268
1269 static int um_chdir(vfs_handle_struct *handle,
1270                     const char *path)
1271 {
1272         int status;
1273         char *client_path = NULL;
1274
1275         DEBUG(10, ("Entering um_chdir\n"));
1276
1277         if (!is_in_media_files(path)) {
1278                 return SMB_VFS_NEXT_CHDIR(handle, path);
1279         }
1280
1281         status = alloc_get_client_path(handle, talloc_tos(),
1282                                        path, &client_path);
1283         if (status != 0) {
1284                 goto err;
1285         }
1286
1287         status = SMB_VFS_NEXT_CHDIR(handle, client_path);
1288
1289 err:
1290         TALLOC_FREE(client_path);
1291         return status;
1292 }
1293
1294 static int um_ntimes(vfs_handle_struct *handle,
1295                      const struct smb_filename *smb_fname,
1296                      struct smb_file_time *ft)
1297 {
1298         int status;
1299         struct smb_filename *client_fname = NULL;
1300
1301         DEBUG(10, ("Entering um_ntimes\n"));
1302
1303         if (!is_in_media_files(smb_fname->base_name)) {
1304                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1305         }
1306
1307         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1308                                             smb_fname, &client_fname);
1309         if (status != 0) {
1310                 goto err;
1311         }
1312
1313         status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
1314
1315 err:
1316         TALLOC_FREE(client_fname);
1317         return status;
1318 }
1319
1320 static int um_symlink(vfs_handle_struct *handle,
1321                         const char *link_contents,
1322                         const struct smb_filename *new_smb_fname)
1323 {
1324         int status;
1325         char *client_link_contents = NULL;
1326         struct smb_filename *new_client_fname = NULL;
1327
1328         DEBUG(10, ("Entering um_symlink\n"));
1329
1330         if (!is_in_media_files(link_contents) &&
1331                         !is_in_media_files(new_smb_fname->base_name)) {
1332                 return SMB_VFS_NEXT_SYMLINK(handle,
1333                                 link_contents,
1334                                 new_smb_fname);
1335         }
1336
1337         status = alloc_get_client_path(handle, talloc_tos(),
1338                                 link_contents, &client_link_contents);
1339         if (status != 0) {
1340                 goto err;
1341         }
1342         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1343                                             new_smb_fname, &new_client_fname);
1344         if (status != 0) {
1345                 goto err;
1346         }
1347
1348         status = SMB_VFS_NEXT_SYMLINK(handle,
1349                                         client_link_contents,
1350                                         new_client_fname);
1351
1352 err:
1353         TALLOC_FREE(client_link_contents);
1354         TALLOC_FREE(new_client_fname);
1355         return status;
1356 }
1357
1358 static int um_readlink(vfs_handle_struct *handle,
1359                         const struct smb_filename *smb_fname,
1360                         char *buf,
1361                         size_t bufsiz)
1362 {
1363         int status;
1364         struct smb_filename *client_fname = NULL;
1365
1366         DEBUG(10, ("Entering um_readlink\n"));
1367
1368         if (!is_in_media_files(smb_fname->base_name)) {
1369                 return SMB_VFS_NEXT_READLINK(handle, smb_fname,
1370                                 buf, bufsiz);
1371         }
1372
1373         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1374                                             smb_fname, &client_fname);
1375         if (status != 0) {
1376                 goto err;
1377         }
1378
1379         status = SMB_VFS_NEXT_READLINK(handle, client_fname, buf, bufsiz);
1380
1381 err:
1382         TALLOC_FREE(client_fname);
1383         return status;
1384 }
1385
1386 static int um_link(vfs_handle_struct *handle,
1387                     const struct smb_filename *old_smb_fname,
1388                     const struct smb_filename *new_smb_fname)
1389 {
1390         int status;
1391         struct smb_filename *old_client_fname = NULL;
1392         struct smb_filename *new_client_fname = NULL;
1393
1394         DEBUG(10, ("Entering um_link\n"));
1395         if (!is_in_media_files(old_smb_fname->base_name) &&
1396                                 !is_in_media_files(new_smb_fname->base_name)) {
1397                 return SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
1398         }
1399
1400         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1401                                             old_smb_fname, &old_client_fname);
1402         if (status != 0) {
1403                 goto err;
1404         }
1405         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1406                                             new_smb_fname, &new_client_fname);
1407         if (status != 0) {
1408                 goto err;
1409         }
1410
1411         status = SMB_VFS_NEXT_LINK(handle, old_client_fname, new_client_fname);
1412
1413 err:
1414         TALLOC_FREE(old_client_fname);
1415         TALLOC_FREE(new_client_fname);
1416         return status;
1417 }
1418
1419 static int um_mknod(vfs_handle_struct *handle,
1420                     const struct smb_filename *smb_fname,
1421                     mode_t mode,
1422                     SMB_DEV_T dev)
1423 {
1424         int status;
1425         struct smb_filename *client_fname = NULL;
1426
1427         DEBUG(10, ("Entering um_mknod\n"));
1428         if (!is_in_media_files(smb_fname->base_name)) {
1429                 return SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
1430         }
1431
1432         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1433                                             smb_fname, &client_fname);
1434         if (status != 0) {
1435                 goto err;
1436         }
1437
1438         status = SMB_VFS_NEXT_MKNOD(handle, client_fname, mode, dev);
1439
1440 err:
1441         TALLOC_FREE(client_fname);
1442         return status;
1443 }
1444
1445 static char *um_realpath(vfs_handle_struct *handle,
1446                          const char *path)
1447 {
1448         char *buf = NULL;
1449         char *client_path = NULL;
1450         int status;
1451
1452         DEBUG(10, ("Entering um_realpath\n"));
1453
1454         if (!is_in_media_files(path)) {
1455                 return SMB_VFS_NEXT_REALPATH(handle, path);
1456         }
1457
1458         status = alloc_get_client_path(handle, talloc_tos(),
1459                                        path, &client_path);
1460         if (status != 0) {
1461                 goto err;
1462         }
1463
1464         buf = SMB_VFS_NEXT_REALPATH(handle, client_path);
1465
1466 err:
1467         TALLOC_FREE(client_path);
1468         return buf;
1469 }
1470
1471 static int um_chflags(vfs_handle_struct *handle,
1472                         const struct smb_filename *smb_fname,
1473                         unsigned int flags)
1474 {
1475         int status;
1476         struct smb_filename *client_fname = NULL;
1477
1478         DEBUG(10, ("Entering um_mknod\n"));
1479         if (!is_in_media_files(smb_fname->base_name)) {
1480                 return SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1481         }
1482
1483         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1484                                             smb_fname, &client_fname);
1485         if (status != 0) {
1486                 goto err;
1487         }
1488
1489         status = SMB_VFS_NEXT_CHFLAGS(handle, client_fname, flags);
1490
1491 err:
1492         TALLOC_FREE(client_fname);
1493         return status;
1494 }
1495
1496 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1497                               struct files_struct *fsp,
1498                               const struct smb_filename *smb_fname,
1499                               TALLOC_CTX *ctx,
1500                               unsigned int *num_streams,
1501                               struct stream_struct **streams)
1502 {
1503         NTSTATUS status;
1504         int ret;
1505         struct smb_filename *client_fname = NULL;
1506
1507         DEBUG(10, ("Entering um_streaminfo\n"));
1508
1509         if (!is_in_media_files(smb_fname->base_name)) {
1510                 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname,
1511                                                ctx, num_streams, streams);
1512         }
1513
1514         ret = alloc_get_client_smb_fname(handle,
1515                                 talloc_tos(),
1516                                 smb_fname,
1517                                 &client_fname);
1518         if (ret != 0) {
1519                 status = NT_STATUS_NO_MEMORY;
1520                 goto err;
1521         }
1522
1523         /*
1524          * This only works on files, so we don't have to worry about
1525          * our fake directory stat'ing here.  But what does this
1526          * function do, exactly?  Does it need extra modifications for
1527          * the Avid stuff?
1528          */
1529         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_fname,
1530                                          ctx, num_streams, streams);
1531 err:
1532         TALLOC_FREE(client_fname);
1533         return status;
1534 }
1535
1536 /*
1537  * Ignoring get_real_filename function because the default doesn't do
1538  * anything.
1539  */
1540
1541 static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
1542                               const struct smb_filename *smb_fname,
1543                               uint32_t security_info,
1544                               TALLOC_CTX *mem_ctx,
1545                               struct security_descriptor **ppdesc)
1546 {
1547         NTSTATUS status;
1548         char *client_path = NULL;
1549         struct smb_filename *client_smb_fname = NULL;
1550         int ret;
1551
1552         DEBUG(10, ("Entering um_get_nt_acl\n"));
1553
1554         if (!is_in_media_files(smb_fname->base_name)) {
1555                 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
1556                                                security_info,
1557                                                mem_ctx, ppdesc);
1558         }
1559
1560         ret = alloc_get_client_path(handle, talloc_tos(),
1561                                     smb_fname->base_name, &client_path);
1562         if (ret != 0) {
1563                 status = map_nt_error_from_unix(errno);
1564                 goto err;
1565         }
1566
1567         client_smb_fname = synthetic_smb_fname(talloc_tos(),
1568                                         client_path,
1569                                         NULL,
1570                                         NULL,
1571                                         smb_fname->flags);
1572         if (client_smb_fname == NULL) {
1573                 TALLOC_FREE(client_path);
1574                 return NT_STATUS_NO_MEMORY;
1575         }
1576
1577         status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
1578                                          security_info,
1579                                          mem_ctx, ppdesc);
1580 err:
1581         TALLOC_FREE(client_smb_fname);
1582         TALLOC_FREE(client_path);
1583         return status;
1584 }
1585
1586 static int um_chmod_acl(vfs_handle_struct *handle,
1587                         const struct smb_filename *smb_fname,
1588                         mode_t mode)
1589 {
1590         int status;
1591         int saved_errno;
1592         struct smb_filename *client_fname = NULL;
1593
1594         DEBUG(10, ("Entering um_chmod_acl\n"));
1595
1596         if (!is_in_media_files(smb_fname->base_name)) {
1597                 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
1598         }
1599
1600         status = alloc_get_client_smb_fname(handle,
1601                                 talloc_tos(),
1602                                 smb_fname,
1603                                 &client_fname);
1604         if (status != 0) {
1605                 goto err;
1606         }
1607         status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_fname, mode);
1608
1609 err:
1610         saved_errno = errno;
1611         TALLOC_FREE(client_fname);
1612         errno = saved_errno;
1613         return status;
1614 }
1615
1616 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1617                                 const struct smb_filename *smb_fname,
1618                                 SMB_ACL_TYPE_T type,
1619                                 TALLOC_CTX *mem_ctx)
1620 {
1621         SMB_ACL_T ret;
1622         int saved_errno = 0;
1623         struct smb_filename *client_fname = NULL;
1624         int status;
1625
1626         DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1627
1628         if (!is_in_media_files(smb_fname->base_name)) {
1629                 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
1630                                                      type, mem_ctx);
1631         }
1632
1633         status = alloc_get_client_smb_fname(handle,
1634                                 talloc_tos(),
1635                                 smb_fname,
1636                                 &client_fname);
1637         if (status != 0) {
1638                 ret = (SMB_ACL_T)NULL;
1639                 goto err;
1640         }
1641
1642         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_fname,
1643                                 type, mem_ctx);
1644
1645 err:
1646         if (ret == (SMB_ACL_T)NULL) {
1647                 saved_errno = errno;
1648         }
1649         TALLOC_FREE(client_fname);
1650         if (saved_errno != 0) {
1651                 errno = saved_errno;
1652         }
1653         return ret;
1654 }
1655
1656 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1657                                const struct smb_filename *smb_fname,
1658                                SMB_ACL_TYPE_T acltype,
1659                                SMB_ACL_T theacl)
1660 {
1661         int status;
1662         int saved_errno = 0;
1663         struct smb_filename *client_fname = NULL;
1664
1665         DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1666
1667         if (!is_in_media_files(smb_fname->base_name)) {
1668                 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
1669                                                      acltype, theacl);
1670         }
1671
1672         status = alloc_get_client_smb_fname(handle,
1673                                 talloc_tos(),
1674                                 smb_fname,
1675                                 &client_fname);
1676         if (status != 0) {
1677                 goto err;
1678         }
1679
1680         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_fname,
1681                                                acltype, theacl);
1682
1683 err:
1684         if (status == -1) {
1685                 saved_errno = errno;
1686         }
1687         TALLOC_FREE(client_fname);
1688         if (saved_errno != 0) {
1689                 errno = saved_errno;
1690         }
1691         return status;
1692 }
1693
1694 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1695                                 const struct smb_filename *smb_fname)
1696 {
1697         int status;
1698         int saved_errno = 0;
1699         struct smb_filename *client_fname = NULL;
1700
1701         DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1702
1703         if (!is_in_media_files(smb_fname->base_name)) {
1704                 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
1705                                 smb_fname);
1706         }
1707
1708         status = alloc_get_client_smb_fname(handle,
1709                                 talloc_tos(),
1710                                 smb_fname,
1711                                 &client_fname);
1712         if (status != 0) {
1713                 goto err;
1714         }
1715
1716         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_fname);
1717
1718 err:
1719         if (status == -1) {
1720                 saved_errno = errno;
1721         }
1722         TALLOC_FREE(client_fname);
1723         if (saved_errno != 0) {
1724                 errno = saved_errno;
1725         }
1726         return status;
1727 }
1728
1729 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1730                            const struct smb_filename *smb_fname,
1731                            const char *name,
1732                            void *value,
1733                            size_t size)
1734 {
1735         ssize_t ret;
1736         struct smb_filename *client_fname = NULL;
1737         int status;
1738
1739         DEBUG(10, ("Entering um_getxattr\n"));
1740         if (!is_in_media_files(smb_fname->base_name)) {
1741                 return SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
1742                                 name, value, size);
1743         }
1744
1745         status = alloc_get_client_smb_fname(handle,
1746                                 talloc_tos(),
1747                                 smb_fname,
1748                                 &client_fname);
1749         if (status != 0) {
1750                 ret = -1;
1751                 goto err;
1752         }
1753
1754         ret = SMB_VFS_NEXT_GETXATTR(handle, client_fname, name, value, size);
1755 err:
1756         TALLOC_FREE(client_fname);
1757         return ret;
1758 }
1759
1760 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1761                             const struct smb_filename *smb_fname,
1762                             char *list,
1763                             size_t size)
1764 {
1765         ssize_t ret;
1766         struct smb_filename *client_fname = NULL;
1767         int status;
1768
1769         DEBUG(10, ("Entering um_listxattr\n"));
1770
1771         if (!is_in_media_files(smb_fname->base_name)) {
1772                 return SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
1773         }
1774
1775         status = alloc_get_client_smb_fname(handle,
1776                                 talloc_tos(),
1777                                 smb_fname,
1778                                 &client_fname);
1779         if (status != 0) {
1780                 ret = -1;
1781                 goto err;
1782         }
1783
1784         ret = SMB_VFS_NEXT_LISTXATTR(handle, client_fname, list, size);
1785
1786 err:
1787         TALLOC_FREE(client_fname);
1788         return ret;
1789 }
1790
1791 static int um_removexattr(struct vfs_handle_struct *handle,
1792                           const struct smb_filename *smb_fname,
1793                           const char *name)
1794 {
1795         int status;
1796         struct smb_filename *client_fname = NULL;
1797
1798         DEBUG(10, ("Entering um_removexattr\n"));
1799
1800         if (!is_in_media_files(smb_fname->base_name)) {
1801                 return SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
1802         }
1803
1804         status = alloc_get_client_smb_fname(handle,
1805                                 talloc_tos(),
1806                                 smb_fname,
1807                                 &client_fname);
1808         if (status != 0) {
1809                 goto err;
1810         }
1811
1812         status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_fname, name);
1813
1814 err:
1815         TALLOC_FREE(client_fname);
1816         return status;
1817 }
1818
1819 static int um_setxattr(struct vfs_handle_struct *handle,
1820                        const struct smb_filename *smb_fname,
1821                        const char *name,
1822                        const void *value,
1823                        size_t size,
1824                        int flags)
1825 {
1826         int status;
1827         struct smb_filename *client_fname = NULL;
1828
1829         DEBUG(10, ("Entering um_setxattr\n"));
1830
1831         if (!is_in_media_files(smb_fname->base_name)) {
1832                 return SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
1833                                              size, flags);
1834         }
1835
1836         status = alloc_get_client_smb_fname(handle,
1837                                 talloc_tos(),
1838                                 smb_fname,
1839                                 &client_fname);
1840         if (status != 0) {
1841                 goto err;
1842         }
1843
1844         status = SMB_VFS_NEXT_SETXATTR(handle, client_fname, name, value,
1845                                        size, flags);
1846
1847 err:
1848         TALLOC_FREE(client_fname);
1849         return status;
1850 }
1851
1852 static int um_connect(vfs_handle_struct *handle,
1853                          const char *service,
1854                          const char *user)
1855 {
1856         int rc;
1857         struct um_config_data *config;
1858         int enumval;
1859
1860         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1861         if (rc != 0) {
1862                 return rc;
1863         }
1864
1865         config = talloc_zero(handle->conn, struct um_config_data);
1866         if (!config) {
1867                 DEBUG(1, ("talloc_zero() failed\n"));
1868                 errno = ENOMEM;
1869                 return -1;
1870         }
1871
1872         enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1873                                "clientid", um_clientid, UM_CLIENTID_NAME);
1874         if (enumval == -1) {
1875                 DEBUG(1, ("value for %s: type unknown\n",
1876                           UM_PARAM_TYPE_NAME));
1877                 return -1;
1878         }
1879         config->clientid = (enum um_clientid)enumval;
1880
1881         SMB_VFS_HANDLE_SET_DATA(handle, config,
1882                                 NULL, struct um_config_data,
1883                                 return -1);
1884
1885         return 0;
1886 }
1887
1888 /* VFS operations structure */
1889
1890 static struct vfs_fn_pointers vfs_um_fns = {
1891         .connect_fn = um_connect,
1892
1893         /* Disk operations */
1894
1895         .statvfs_fn = um_statvfs,
1896
1897         /* Directory operations */
1898
1899         .opendir_fn = um_opendir,
1900         .fdopendir_fn = um_fdopendir,
1901         .readdir_fn = um_readdir,
1902         .seekdir_fn = um_seekdir,
1903         .telldir_fn = um_telldir,
1904         .rewind_dir_fn = um_rewinddir,
1905         .mkdir_fn = um_mkdir,
1906         .rmdir_fn = um_rmdir,
1907         .closedir_fn = um_closedir,
1908         .init_search_op_fn = um_init_search_op,
1909
1910         /* File operations */
1911
1912         .open_fn = um_open,
1913         .create_file_fn = um_create_file,
1914         .rename_fn = um_rename,
1915         .stat_fn = um_stat,
1916         .lstat_fn = um_lstat,
1917         .fstat_fn = um_fstat,
1918         .unlink_fn = um_unlink,
1919         .chmod_fn = um_chmod,
1920         .chown_fn = um_chown,
1921         .lchown_fn = um_lchown,
1922         .chdir_fn = um_chdir,
1923         .ntimes_fn = um_ntimes,
1924         .symlink_fn = um_symlink,
1925         .readlink_fn = um_readlink,
1926         .link_fn = um_link,
1927         .mknod_fn = um_mknod,
1928         .realpath_fn = um_realpath,
1929         .chflags_fn = um_chflags,
1930         .streaminfo_fn = um_streaminfo,
1931
1932         /* NT ACL operations. */
1933
1934         .get_nt_acl_fn = um_get_nt_acl,
1935
1936         /* POSIX ACL operations. */
1937
1938         .chmod_acl_fn = um_chmod_acl,
1939
1940         .sys_acl_get_file_fn = um_sys_acl_get_file,
1941         .sys_acl_set_file_fn = um_sys_acl_set_file,
1942         .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1943
1944         /* EA operations. */
1945         .getxattr_fn = um_getxattr,
1946         .listxattr_fn = um_listxattr,
1947         .removexattr_fn = um_removexattr,
1948         .setxattr_fn = um_setxattr,
1949 };
1950
1951 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *);
1952 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1953 {
1954         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1955                                         "unityed_media", &vfs_um_fns);
1956         if (!NT_STATUS_IS_OK(ret)) {
1957                 return ret;
1958         }
1959
1960         vfs_um_debug_level = debug_add_class("unityed_media");
1961
1962         if (vfs_um_debug_level == -1) {
1963                 vfs_um_debug_level = DBGC_VFS;
1964                 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1965                           "debugging class.\n"));
1966         }
1967
1968         return ret;
1969 }