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