4bbb8fb3a23f3081053cf7fa41c032c4df8dbdc0
[kai/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 char *path,
526                       struct vfs_statvfs_struct *statbuf)
527 {
528         int status;
529         char *clientPath = NULL;
530
531         DEBUG(10, ("Entering with path '%s'\n", path));
532
533         if (!is_in_media_files(path)) {
534                 return SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
535         }
536
537         status = alloc_get_client_path(handle, talloc_tos(),
538                                        path, &clientPath);
539         if (status != 0) {
540                 goto err;
541         }
542
543         status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
544 err:
545         TALLOC_FREE(clientPath);
546         DEBUG(10, ("Leaving with path '%s'\n", path));
547         return status;
548 }
549
550 /* Success: return a um_dirinfo_struct cast as a DIR
551  * Failure: set errno, return NULL
552  */
553 static DIR *um_opendir(vfs_handle_struct *handle,
554                        const struct smb_filename *smb_fname,
555                        const char *mask,
556                        uint32_t attr)
557 {
558         struct um_dirinfo_struct *dirInfo;
559
560         DEBUG(10, ("Entering with fname '%s'\n", smb_fname->base_name));
561
562         if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo)) {
563                 goto err;
564         }
565
566         if (!dirInfo->isInMediaFiles) {
567                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
568                         handle, smb_fname, mask, attr);
569         } else {
570                 struct smb_filename *client_smb_fname =
571                         synthetic_smb_fname(talloc_tos(),
572                                         dirInfo->clientPath,
573                                         NULL,
574                                         NULL);
575                 if (client_smb_fname == NULL) {
576                         goto err;
577                 }
578
579                 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
580                         handle, client_smb_fname, mask, attr);
581
582                 TALLOC_FREE(client_smb_fname);
583         }
584
585         if (dirInfo->dirstream == NULL) {
586                 goto err;
587         }
588
589         DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
590                               "dirInfo->clientPath '%s'\n",
591                               dirInfo->dirpath,
592                               dirInfo->clientPath));
593         return (DIR*)dirInfo;
594
595 err:
596         DEBUG(1, ("Failing with fname '%s'\n", smb_fname->base_name));
597         TALLOC_FREE(dirInfo);
598         return NULL;
599 }
600
601 static DIR *um_fdopendir(vfs_handle_struct *handle,
602                          files_struct *fsp,
603                          const char *mask,
604                          uint32_t attr)
605 {
606         struct um_dirinfo_struct *dirInfo = NULL;
607         DIR *dirstream;
608
609         DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
610                    fsp->fsp_name->base_name));
611
612         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
613         if (!dirstream) {
614                 goto err;
615         }
616
617         if (alloc_set_client_dirinfo(handle,
618                                      fsp->fsp_name->base_name,
619                                      &dirInfo)) {
620                 goto err;
621         }
622
623         dirInfo->dirstream = dirstream;
624
625         if (!dirInfo->isInMediaFiles) {
626                 /*
627                  * FIXME: this is the original code, something must be
628                  * missing here, but what? -slow
629                  */
630                 goto out;
631         }
632
633 out:
634         DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
635                    "dirInfo->clientPath '%s', "
636                    "fsp->fsp_name->st.st_ex_mtime %s",
637                    dirInfo->dirpath,
638                    dirInfo->clientPath,
639                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
640         return (DIR *) dirInfo;
641
642 err:
643         DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
644                   fsp->fsp_name->base_name));
645         TALLOC_FREE(dirInfo);
646         return NULL;
647 }
648
649 /*
650  * skip own suffixed directory
651  * replace own suffixed directory with non suffixed.
652  *
653  * Success: return dirent
654  * End of data: return NULL
655  * Failure: set errno, return NULL
656  */
657 static struct dirent *um_readdir(vfs_handle_struct *handle,
658                                  DIR *dirp,
659                                  SMB_STRUCT_STAT *sbuf)
660 {
661         um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
662         struct dirent *d = NULL;
663         int skip;
664
665         DEBUG(10, ("dirInfo->dirpath '%s', "
666                    "dirInfo->clientPath '%s', "
667                    "dirInfo->isInMediaFiles '%s', "
668                    "dirInfo->clientSubDirname '%s'\n",
669                    dirInfo->dirpath,
670                    dirInfo->clientPath,
671                    dirInfo->isInMediaFiles ? "true" : "false",
672                    dirInfo->clientSubDirname));
673
674         if (!dirInfo->isInMediaFiles) {
675                 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
676         }
677
678         do {
679                 const char* dname;
680                 bool isAppleDouble;
681                 char *digits;
682                 size_t digits_len;
683                 uintmax_t number;
684
685                 skip = false;
686                 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
687
688                 if (d == NULL) {
689                         break;
690                 }
691
692                 /* ignore apple double prefix for logic below */
693                 if (is_apple_double(d->d_name)) {
694                         dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
695                         isAppleDouble = true;
696                 } else {
697                         dname = d->d_name;
698                         isAppleDouble = false;
699                 }
700
701                 DEBUG(10, ("dname = '%s'\n", dname));
702
703                 (void)get_digit_group(dname, &number);
704                 digits = talloc_asprintf(talloc_tos(), "%ju", number);
705                 if (digits == NULL) {
706                         DEBUG(1, ("out of memory"));
707                         goto err;
708                 }
709                 digits_len = strlen(digits);
710
711                 if (alloc_set_client_dirinfo_path(handle,
712                                                   dirInfo,
713                                                   &((dirInfo)->clientSubDirname),
714                                                   digits)) {
715                         goto err;
716                 }
717
718                 /*
719                  * If set to "true", vfs shows digits-only
720                  * non-suffixed subdirectories.  Normally, such
721                  * subdirectories can exists only in non-media
722                  * directories, so we set it to "false".  Otherwise,
723                  * if we have such subdirectories (probably created
724                  * over not "unityed" connection), it can be little
725                  * bit confusing.
726                  */
727                 if (strequal(dname, digits)) {
728                         skip = false;
729                 } else if (strequal(dname, dirInfo->clientSubDirname)) {
730                         /*
731                          * Remove suffix of this client's suffixed
732                          * subdirectories
733                          */
734                         if (isAppleDouble) {
735                                 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
736                         } else {
737                                 d->d_name[digits_len] = '\0';
738                         }
739                 } else if (strnequal(digits, dname, digits_len)) {
740                         /*
741                          * Set to false to see another clients subdirectories
742                          */
743                         skip = false;
744                 }
745         } while (skip);
746
747         DEBUG(10, ("Leaving um_readdir\n"));
748         return d;
749 err:
750         TALLOC_FREE(dirInfo);
751         return NULL;
752 }
753
754 static void um_seekdir(vfs_handle_struct *handle,
755                        DIR *dirp,
756                        long offset)
757 {
758         DEBUG(10, ("Entering and leaving um_seekdir\n"));
759         SMB_VFS_NEXT_SEEKDIR(handle,
760                              ((um_dirinfo_struct*)dirp)->dirstream, offset);
761 }
762
763 static long um_telldir(vfs_handle_struct *handle,
764                        DIR *dirp)
765 {
766         DEBUG(10, ("Entering and leaving um_telldir\n"));
767         return SMB_VFS_NEXT_TELLDIR(handle,
768                                     ((um_dirinfo_struct*)dirp)->dirstream);
769 }
770
771 static void um_rewinddir(vfs_handle_struct *handle,
772                          DIR *dirp)
773 {
774         DEBUG(10, ("Entering and leaving um_rewinddir\n"));
775         SMB_VFS_NEXT_REWINDDIR(handle,
776                                ((um_dirinfo_struct*)dirp)->dirstream);
777 }
778
779 static int um_mkdir(vfs_handle_struct *handle,
780                     const struct smb_filename *smb_fname,
781                     mode_t mode)
782 {
783         int status;
784         const char *path = smb_fname->base_name;
785         struct smb_filename *client_fname = NULL;
786
787         DEBUG(10, ("Entering with path '%s'\n", path));
788
789         if (!is_in_media_files(path) || !is_in_media_dir(path)) {
790                 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
791         }
792
793         status = alloc_get_client_smb_fname(handle,
794                                 talloc_tos(),
795                                 smb_fname,
796                                 &client_fname);
797         if (status != 0) {
798                 goto err;
799         }
800
801         status = SMB_VFS_NEXT_MKDIR(handle, client_fname, mode);
802 err:
803         TALLOC_FREE(client_fname);
804         DEBUG(10, ("Leaving with path '%s'\n", path));
805         return status;
806 }
807
808 static int um_rmdir(vfs_handle_struct *handle,
809                     const struct smb_filename *smb_fname)
810 {
811         int status;
812         const char *path = smb_fname->base_name;
813         struct smb_filename *client_fname = NULL;
814
815         DEBUG(10, ("Entering with path '%s'\n", path));
816
817         if (!is_in_media_files(path)) {
818                 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
819         }
820
821         status = alloc_get_client_smb_fname(handle,
822                                 talloc_tos(),
823                                 smb_fname,
824                                 &client_fname);
825         if (status != 0) {
826                 goto err;
827         }
828
829         status = SMB_VFS_NEXT_RMDIR(handle, client_fname);
830 err:
831         TALLOC_FREE(client_fname);
832         DEBUG(10, ("Leaving with path '%s'\n", path));
833         return status;
834 }
835
836 static int um_closedir(vfs_handle_struct *handle,
837                        DIR *dirp)
838 {
839         DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
840
841         TALLOC_FREE(dirp);
842
843         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
844 }
845
846 static void um_init_search_op(vfs_handle_struct *handle,
847                               DIR *dirp)
848 {
849         DEBUG(10, ("Entering and leaving um_init_search_op\n"));
850
851         SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
852                                     ((um_dirinfo_struct*)dirp)->dirstream);
853 }
854
855 static int um_open(vfs_handle_struct *handle,
856                    struct smb_filename *smb_fname,
857                    files_struct *fsp,
858                    int flags,
859                    mode_t mode)
860 {
861         int ret;
862         struct smb_filename *client_fname = NULL;
863
864         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
865                               smb_fname->base_name));
866
867         if (!is_in_media_files(smb_fname->base_name)) {
868                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
869         }
870
871         if (alloc_get_client_smb_fname(handle, talloc_tos(),
872                                        smb_fname,
873                                        &client_fname)) {
874                 ret = -1;
875                 goto err;
876         }
877
878         /*
879          * FIXME:
880          * What about fsp->fsp_name?  We also have to get correct stat
881          * info into fsp and smb_fname for DB files, don't we?
882          */
883
884         DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
885                    "smb_fname->st.st_ex_mtime %s"
886                    "fsp->fsp_name->st.st_ex_mtime %s",
887                               smb_fname->base_name,
888                               ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
889                               ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
890
891         ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
892 err:
893         TALLOC_FREE(client_fname);
894         DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
895                               smb_fname->base_name));
896         return ret;
897 }
898
899 static NTSTATUS um_create_file(vfs_handle_struct *handle,
900                                struct smb_request *req,
901                                uint16_t root_dir_fid,
902                                struct smb_filename *smb_fname,
903                                uint32_t access_mask,
904                                uint32_t share_access,
905                                uint32_t create_disposition,
906                                uint32_t create_options,
907                                uint32_t file_attributes,
908                                uint32_t oplock_request,
909                                struct smb2_lease *lease,
910                                uint64_t allocation_size,
911                                uint32_t private_flags,
912                                struct security_descriptor *sd,
913                                struct ea_list *ea_list,
914                                files_struct **result_fsp,
915                                int *pinfo,
916                                const struct smb2_create_blobs *in_context_blobs,
917                                struct smb2_create_blobs *out_context_blobs)
918 {
919         NTSTATUS status;
920         struct smb_filename *client_fname = NULL;
921
922         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
923                    smb_fname->base_name));
924
925         if (!is_in_media_files(smb_fname->base_name)) {
926                 return SMB_VFS_NEXT_CREATE_FILE(
927                         handle,
928                         req,
929                         root_dir_fid,
930                         smb_fname,
931                         access_mask,
932                         share_access,
933                         create_disposition,
934                         create_options,
935                         file_attributes,
936                         oplock_request,
937                         lease,
938                         allocation_size,
939                         private_flags,
940                         sd,
941                         ea_list,
942                         result_fsp,
943                         pinfo,
944                         in_context_blobs,
945                         out_context_blobs);
946         }
947
948         if (alloc_get_client_smb_fname(handle, talloc_tos(),
949                                        smb_fname,
950                                        &client_fname)) {
951                 status = map_nt_error_from_unix(errno);
952                 goto err;
953         }
954
955         /*
956          * FIXME:
957          * This only creates files, so we don't have to worry about
958          * our fake directory stat'ing here.  But we still need to
959          * route stat calls for DB files properly, right?
960          */
961         status = SMB_VFS_NEXT_CREATE_FILE(
962                 handle,
963                 req,
964                 root_dir_fid,
965                 client_fname,
966                 access_mask,
967                 share_access,
968                 create_disposition,
969                 create_options,
970                 file_attributes,
971                 oplock_request,
972                 lease,
973                 allocation_size,
974                 private_flags,
975                 sd,
976                 ea_list,
977                 result_fsp,
978                 pinfo,
979                 in_context_blobs,
980                 out_context_blobs);
981 err:
982         TALLOC_FREE(client_fname);
983         DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
984                    "smb_fname->st.st_ex_mtime %s"
985                    " fsp->fsp_name->st.st_ex_mtime %s",
986                    smb_fname->base_name,
987                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
988                    (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
989                    ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
990                    "No fsp time\n"));
991         return status;
992 }
993
994 static int um_rename(vfs_handle_struct *handle,
995                      const struct smb_filename *smb_fname_src,
996                      const struct smb_filename *smb_fname_dst)
997 {
998         int status;
999         struct smb_filename *src_client_fname = NULL;
1000         struct smb_filename *dst_client_fname = NULL;
1001
1002         DEBUG(10, ("Entering with "
1003                    "smb_fname_src->base_name '%s', "
1004                    "smb_fname_dst->base_name '%s'\n",
1005                    smb_fname_src->base_name,
1006                    smb_fname_dst->base_name));
1007
1008         if (!is_in_media_files(smb_fname_src->base_name)
1009             &&
1010             !is_in_media_files(smb_fname_dst->base_name)) {
1011                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1012                                            smb_fname_dst);
1013         }
1014
1015         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1016                                             smb_fname_src,
1017                                             &src_client_fname);
1018         if (status != 0) {
1019                 goto err;
1020         }
1021
1022         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1023                                             smb_fname_dst,
1024                                             &dst_client_fname);
1025
1026         if (status != 0) {
1027                 goto err;
1028         }
1029
1030         status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
1031                                      dst_client_fname);
1032 err:
1033         TALLOC_FREE(dst_client_fname);
1034         TALLOC_FREE(src_client_fname);
1035         DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
1036                    " smb_fname_dst->base_name '%s'\n",
1037                    smb_fname_src->base_name,
1038                    smb_fname_dst->base_name));
1039         return status;
1040 }
1041
1042 /*
1043  * Success: return 0
1044  * Failure: set errno, return -1
1045  */
1046 static int um_stat(vfs_handle_struct *handle,
1047                    struct smb_filename *smb_fname)
1048 {
1049         int status = 0;
1050         struct smb_filename *client_fname = NULL;
1051
1052         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1053                    smb_fname->base_name));
1054
1055         if (!is_in_media_files(smb_fname->base_name)) {
1056                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1057         }
1058
1059         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1060                                             smb_fname,
1061                                             &client_fname);
1062         if (status != 0) {
1063                 goto err;
1064         }
1065         DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1066                    client_fname->base_name));
1067
1068         status = SMB_VFS_NEXT_STAT(handle, client_fname);
1069         if (status != 0) {
1070                 goto err;
1071         }
1072
1073         /*
1074          * Unlike functions with const smb_filename, we have to modify
1075          * smb_fname itself to pass our info back up.
1076          */
1077         DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1078                    smb_fname->base_name, client_fname->base_name));
1079         smb_fname->st = client_fname->st;
1080
1081 err:
1082         TALLOC_FREE(client_fname);
1083         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1084                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1085         return status;
1086 }
1087
1088 static int um_lstat(vfs_handle_struct *handle,
1089                     struct smb_filename *smb_fname)
1090 {
1091         int status = 0;
1092         struct smb_filename *client_fname = NULL;
1093
1094         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1095                    smb_fname->base_name));
1096
1097         if (!is_in_media_files(smb_fname->base_name)) {
1098                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1099         }
1100
1101         client_fname = NULL;
1102
1103         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1104                                             smb_fname,
1105                                             &client_fname);
1106         if (status != 0) {
1107                 goto err;
1108         }
1109         status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1110         if (status != 0) {
1111                 goto err;
1112         }
1113
1114         smb_fname->st = client_fname->st;
1115
1116 err:
1117         TALLOC_FREE(client_fname);
1118         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1119                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1120         return status;
1121 }
1122
1123 static int um_fstat(vfs_handle_struct *handle,
1124                     files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1125 {
1126         int status = 0;
1127
1128         DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1129                    "'%s'\n", fsp_str_dbg(fsp)));
1130
1131         status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1132         if (status != 0) {
1133                 goto out;
1134         }
1135
1136         if ((fsp->fsp_name == NULL) ||
1137             !is_in_media_files(fsp->fsp_name->base_name)) {
1138                 goto out;
1139         }
1140
1141         status = um_stat(handle, fsp->fsp_name);
1142         if (status != 0) {
1143                 goto out;
1144         }
1145
1146         *sbuf = fsp->fsp_name->st;
1147
1148 out:
1149         DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1150                    fsp->fsp_name != NULL ?
1151                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1152         return status;
1153 }
1154
1155 static int um_unlink(vfs_handle_struct *handle,
1156                      const struct smb_filename *smb_fname)
1157 {
1158         int status;
1159         struct smb_filename *client_fname = NULL;
1160
1161         DEBUG(10, ("Entering um_unlink\n"));
1162
1163         if (!is_in_media_files(smb_fname->base_name)) {
1164                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1165         }
1166
1167         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1168                                             smb_fname,
1169                                             &client_fname);
1170         if (status != 0) {
1171                 goto err;
1172         }
1173
1174         status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
1175
1176 err:
1177         TALLOC_FREE(client_fname);
1178         return status;
1179 }
1180
1181 static int um_chmod(vfs_handle_struct *handle,
1182                         const struct smb_filename *smb_fname,
1183                         mode_t mode)
1184 {
1185         int status;
1186         struct smb_filename *client_fname = NULL;
1187
1188         DEBUG(10, ("Entering um_chmod\n"));
1189
1190         if (!is_in_media_files(smb_fname->base_name)) {
1191                 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1192         }
1193
1194         status = alloc_get_client_smb_fname(handle,
1195                                 talloc_tos(),
1196                                 smb_fname,
1197                                 &client_fname);
1198         if (status != 0) {
1199                 goto err;
1200         }
1201
1202         status = SMB_VFS_NEXT_CHMOD(handle, client_fname, mode);
1203
1204 err:
1205         TALLOC_FREE(client_fname);
1206         return status;
1207 }
1208
1209 static int um_chown(vfs_handle_struct *handle,
1210                         const struct smb_filename *smb_fname,
1211                         uid_t uid,
1212                         gid_t gid)
1213 {
1214         int status;
1215         struct smb_filename *client_fname = NULL;
1216
1217         DEBUG(10, ("Entering um_chown\n"));
1218
1219         if (!is_in_media_files(smb_fname->base_name)) {
1220                 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1221         }
1222
1223         status = alloc_get_client_smb_fname(handle,
1224                                 talloc_tos(),
1225                                 smb_fname,
1226                                 &client_fname);
1227         if (status != 0) {
1228                 goto err;
1229         }
1230
1231         status = SMB_VFS_NEXT_CHOWN(handle, client_fname, uid, gid);
1232
1233 err:
1234         TALLOC_FREE(client_fname);
1235         return status;
1236 }
1237
1238 static int um_lchown(vfs_handle_struct *handle,
1239                         const struct smb_filename *smb_fname,
1240                         uid_t uid,
1241                         gid_t gid)
1242 {
1243         int status;
1244         struct smb_filename *client_fname = NULL;
1245
1246         DEBUG(10, ("Entering um_lchown\n"));
1247         if (!is_in_media_files(smb_fname->base_name)) {
1248                 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1249         }
1250
1251         status = alloc_get_client_smb_fname(handle,
1252                                 talloc_tos(),
1253                                 smb_fname,
1254                                 &client_fname);
1255         if (status != 0) {
1256                 goto err;
1257         }
1258
1259         status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1260
1261 err:
1262         TALLOC_FREE(client_fname);
1263         return status;
1264 }
1265
1266 static int um_chdir(vfs_handle_struct *handle,
1267                     const char *path)
1268 {
1269         int status;
1270         char *client_path = NULL;
1271
1272         DEBUG(10, ("Entering um_chdir\n"));
1273
1274         if (!is_in_media_files(path)) {
1275                 return SMB_VFS_NEXT_CHDIR(handle, path);
1276         }
1277
1278         status = alloc_get_client_path(handle, talloc_tos(),
1279                                        path, &client_path);
1280         if (status != 0) {
1281                 goto err;
1282         }
1283
1284         status = SMB_VFS_NEXT_CHDIR(handle, client_path);
1285
1286 err:
1287         TALLOC_FREE(client_path);
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 *oldpath,
1319                       const char *newpath)
1320 {
1321         int status;
1322         char *old_client_path = NULL;
1323         char *new_client_path = NULL;
1324
1325         DEBUG(10, ("Entering um_symlink\n"));
1326
1327         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1328                 return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1329         }
1330
1331         status = alloc_get_client_path(handle, talloc_tos(),
1332                                        oldpath, &old_client_path);
1333         if (status != 0) {
1334                 goto err;
1335         }
1336
1337         status = alloc_get_client_path(handle, talloc_tos(),
1338                                        newpath, &new_client_path);
1339         if (status != 0) {
1340                 goto err;
1341         }
1342
1343         status = SMB_VFS_NEXT_SYMLINK(handle,
1344                                       old_client_path,
1345                                       new_client_path);
1346
1347 err:
1348         TALLOC_FREE(new_client_path);
1349         TALLOC_FREE(old_client_path);
1350         return status;
1351 }
1352
1353 static int um_readlink(vfs_handle_struct *handle,
1354                        const char *path,
1355                        char *buf,
1356                        size_t bufsiz)
1357 {
1358         int status;
1359         char *client_path = NULL;
1360
1361         DEBUG(10, ("Entering um_readlink\n"));
1362
1363         if (!is_in_media_files(path)) {
1364                 return SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1365         }
1366
1367         status = alloc_get_client_path(handle, talloc_tos(),
1368                                        path, &client_path);
1369         if (status != 0) {
1370                 goto err;
1371         }
1372
1373         status = SMB_VFS_NEXT_READLINK(handle, client_path, buf, bufsiz);
1374
1375 err:
1376         TALLOC_FREE(client_path);
1377         return status;
1378 }
1379
1380 static int um_link(vfs_handle_struct *handle,
1381                    const char *oldpath,
1382                    const char *newpath)
1383 {
1384         int status;
1385         char *old_client_path = NULL;
1386         char *new_client_path = NULL;
1387
1388         DEBUG(10, ("Entering um_link\n"));
1389         if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1390                 return SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1391         }
1392
1393         status = alloc_get_client_path(handle, talloc_tos(),
1394                                        oldpath, &old_client_path);
1395         if (status != 0) {
1396                 goto err;
1397         }
1398
1399         status = alloc_get_client_path(handle, talloc_tos(),
1400                                        newpath, &new_client_path);
1401         if (status != 0) {
1402                 goto err;
1403         }
1404
1405         status = SMB_VFS_NEXT_LINK(handle, old_client_path, new_client_path);
1406
1407 err:
1408         TALLOC_FREE(new_client_path);
1409         TALLOC_FREE(old_client_path);
1410         return status;
1411 }
1412
1413 static int um_mknod(vfs_handle_struct *handle,
1414                     const char *pathname,
1415                     mode_t mode,
1416                     SMB_DEV_T dev)
1417 {
1418         int status;
1419         char *client_path = NULL;
1420
1421         DEBUG(10, ("Entering um_mknod\n"));
1422         if (!is_in_media_files(pathname)) {
1423                 return SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1424         }
1425
1426         status = alloc_get_client_path(handle, talloc_tos(),
1427                                        pathname, &client_path);
1428         if (status != 0) {
1429                 goto err;
1430         }
1431
1432         status = SMB_VFS_NEXT_MKNOD(handle, client_path, mode, dev);
1433
1434 err:
1435         TALLOC_FREE(client_path);
1436         return status;
1437 }
1438
1439 static char *um_realpath(vfs_handle_struct *handle,
1440                          const char *path)
1441 {
1442         char *buf = NULL;
1443         char *client_path = NULL;
1444         int status;
1445
1446         DEBUG(10, ("Entering um_realpath\n"));
1447
1448         if (!is_in_media_files(path)) {
1449                 return SMB_VFS_NEXT_REALPATH(handle, path);
1450         }
1451
1452         status = alloc_get_client_path(handle, talloc_tos(),
1453                                        path, &client_path);
1454         if (status != 0) {
1455                 goto err;
1456         }
1457
1458         buf = SMB_VFS_NEXT_REALPATH(handle, client_path);
1459
1460 err:
1461         TALLOC_FREE(client_path);
1462         return buf;
1463 }
1464
1465 static int um_chflags(vfs_handle_struct *handle,
1466                       const char *path,
1467                       unsigned int flags)
1468 {
1469         int status;
1470         char *client_path = NULL;
1471
1472         DEBUG(10, ("Entering um_chflags\n"));
1473
1474         if (!is_in_media_files(path)) {
1475                 return SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1476         }
1477
1478         status = alloc_get_client_path(handle, talloc_tos(),
1479                                        path, &client_path);
1480         if (status != 0) {
1481                 goto err;
1482         }
1483
1484         status = SMB_VFS_NEXT_CHFLAGS(handle, client_path, flags);
1485 err:
1486         TALLOC_FREE(client_path);
1487         return status;
1488 }
1489
1490 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1491                               struct files_struct *fsp,
1492                               const struct smb_filename *smb_fname,
1493                               TALLOC_CTX *ctx,
1494                               unsigned int *num_streams,
1495                               struct stream_struct **streams)
1496 {
1497         NTSTATUS status;
1498         int ret;
1499         struct smb_filename *client_fname = NULL;
1500
1501         DEBUG(10, ("Entering um_streaminfo\n"));
1502
1503         if (!is_in_media_files(smb_fname->base_name)) {
1504                 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname,
1505                                                ctx, num_streams, streams);
1506         }
1507
1508         ret = alloc_get_client_smb_fname(handle,
1509                                 talloc_tos(),
1510                                 smb_fname,
1511                                 &client_fname);
1512         if (ret != 0) {
1513                 status = NT_STATUS_NO_MEMORY;
1514                 goto err;
1515         }
1516
1517         /*
1518          * This only works on files, so we don't have to worry about
1519          * our fake directory stat'ing here.  But what does this
1520          * function do, exactly?  Does it need extra modifications for
1521          * the Avid stuff?
1522          */
1523         status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_fname,
1524                                          ctx, num_streams, streams);
1525 err:
1526         TALLOC_FREE(client_fname);
1527         return status;
1528 }
1529
1530 /*
1531  * Ignoring get_real_filename function because the default doesn't do
1532  * anything.
1533  */
1534
1535 static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
1536                               const struct smb_filename *smb_fname,
1537                               uint32_t security_info,
1538                               TALLOC_CTX *mem_ctx,
1539                               struct security_descriptor **ppdesc)
1540 {
1541         NTSTATUS status;
1542         char *client_path = NULL;
1543         struct smb_filename *client_smb_fname = NULL;
1544         int ret;
1545
1546         DEBUG(10, ("Entering um_get_nt_acl\n"));
1547
1548         if (!is_in_media_files(smb_fname->base_name)) {
1549                 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
1550                                                security_info,
1551                                                mem_ctx, ppdesc);
1552         }
1553
1554         ret = alloc_get_client_path(handle, talloc_tos(),
1555                                     smb_fname->base_name, &client_path);
1556         if (ret != 0) {
1557                 status = map_nt_error_from_unix(errno);
1558                 goto err;
1559         }
1560
1561         client_smb_fname = synthetic_smb_fname(talloc_tos(),
1562                                         client_path,
1563                                         NULL,
1564                                         NULL);
1565         if (client_smb_fname == NULL) {
1566                 TALLOC_FREE(client_path);
1567                 return NT_STATUS_NO_MEMORY;
1568         }
1569
1570         status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
1571                                          security_info,
1572                                          mem_ctx, ppdesc);
1573 err:
1574         TALLOC_FREE(client_smb_fname);
1575         TALLOC_FREE(client_path);
1576         return status;
1577 }
1578
1579 static int um_chmod_acl(vfs_handle_struct *handle,
1580                         const struct smb_filename *smb_fname,
1581                         mode_t mode)
1582 {
1583         int status;
1584         int saved_errno;
1585         struct smb_filename *client_fname = NULL;
1586
1587         DEBUG(10, ("Entering um_chmod_acl\n"));
1588
1589         if (!is_in_media_files(smb_fname->base_name)) {
1590                 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
1591         }
1592
1593         status = alloc_get_client_smb_fname(handle,
1594                                 talloc_tos(),
1595                                 smb_fname,
1596                                 &client_fname);
1597         if (status != 0) {
1598                 goto err;
1599         }
1600         status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_fname, mode);
1601
1602 err:
1603         saved_errno = errno;
1604         TALLOC_FREE(client_fname);
1605         errno = saved_errno;
1606         return status;
1607 }
1608
1609 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1610                                      const char *path_p,
1611                                      SMB_ACL_TYPE_T type,
1612                                      TALLOC_CTX *mem_ctx)
1613 {
1614         SMB_ACL_T ret;
1615         char *client_path = NULL;
1616         int status;
1617
1618         DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1619
1620         if (!is_in_media_files(path_p)) {
1621                 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p,
1622                                                      type, mem_ctx);
1623         }
1624
1625         status = alloc_get_client_path(handle, talloc_tos(),
1626                                        path_p, &client_path);
1627         if (status != 0) {
1628                 ret = NULL;
1629                 goto err;
1630         }
1631
1632         ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_path, type, mem_ctx);
1633
1634 err:
1635         TALLOC_FREE(client_path);
1636         return ret;
1637 }
1638
1639 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1640                                const char *name,
1641                                SMB_ACL_TYPE_T acltype,
1642                                SMB_ACL_T theacl)
1643 {
1644         int status;
1645         char *client_path = NULL;
1646
1647         DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1648
1649         if (!is_in_media_files(name)) {
1650                 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
1651                                                      acltype, theacl);
1652         }
1653
1654         status = alloc_get_client_path(handle, talloc_tos(),
1655                                        name, &client_path);
1656         if (status != 0) {
1657                 goto err;
1658         }
1659
1660         status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_path,
1661                                                acltype, theacl);
1662
1663 err:
1664         TALLOC_FREE(client_path);
1665         return status;
1666 }
1667
1668 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1669                                       const char *path)
1670 {
1671         int status;
1672         char *client_path = NULL;
1673
1674         DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1675
1676         if (!is_in_media_files(path)) {
1677                 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
1678         }
1679
1680         status = alloc_get_client_path(handle, talloc_tos(),
1681                                             path, &client_path);
1682         if (status != 0) {
1683                 goto err;
1684         }
1685
1686         status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_path);
1687
1688 err:
1689         TALLOC_FREE(client_path);
1690         return status;
1691 }
1692
1693 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1694                            const char *path,
1695                            const char *name,
1696                            void *value,
1697                            size_t size)
1698 {
1699         ssize_t ret;
1700         char *client_path = NULL;
1701         int status;
1702
1703         DEBUG(10, ("Entering um_getxattr\n"));
1704         if (!is_in_media_files(path)) {
1705                 return SMB_VFS_NEXT_GETXATTR(handle, path, name, value, size);
1706         }
1707
1708         status = alloc_get_client_path(handle, talloc_tos(),
1709                                        path, &client_path);
1710         if (status != 0) {
1711                 ret = -1;
1712                 goto err;
1713         }
1714
1715         ret = SMB_VFS_NEXT_GETXATTR(handle, client_path, name, value, size);
1716 err:
1717         TALLOC_FREE(client_path);
1718         return ret;
1719 }
1720
1721 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1722                             const char *path,
1723                             char *list,
1724                             size_t size)
1725 {
1726         ssize_t ret;
1727         char *client_path = NULL;
1728         int status;
1729
1730         DEBUG(10, ("Entering um_listxattr\n"));
1731
1732         if (!is_in_media_files(path)) {
1733                 return SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
1734         }
1735
1736         status = alloc_get_client_path(handle, talloc_tos(),
1737                                        path, &client_path);
1738         if (status != 0) {
1739                 ret = -1;
1740                 goto err;
1741         }
1742
1743         ret = SMB_VFS_NEXT_LISTXATTR(handle, client_path, list, size);
1744
1745 err:
1746         TALLOC_FREE(client_path);
1747         return ret;
1748 }
1749
1750 static int um_removexattr(struct vfs_handle_struct *handle,
1751                           const char *path,
1752                           const char *name)
1753 {
1754         int status;
1755         char *client_path = NULL;
1756
1757         DEBUG(10, ("Entering um_removexattr\n"));
1758
1759         if (!is_in_media_files(path)) {
1760                 return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
1761         }
1762
1763         status = alloc_get_client_path(handle, talloc_tos(),
1764                                        path, &client_path);
1765         if (status != 0) {
1766                 goto err;
1767         }
1768
1769         status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_path, name);
1770
1771 err:
1772         TALLOC_FREE(client_path);
1773         return status;
1774 }
1775
1776 static int um_setxattr(struct vfs_handle_struct *handle,
1777                        const char *path,
1778                        const char *name,
1779                        const void *value,
1780                        size_t size,
1781                        int flags)
1782 {
1783         int status;
1784         char *client_path = NULL;
1785
1786         DEBUG(10, ("Entering um_setxattr\n"));
1787
1788         if (!is_in_media_files(path)) {
1789                 return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
1790                                              size, flags);
1791         }
1792
1793         status = alloc_get_client_path(handle, talloc_tos(),
1794                                        path, &client_path);
1795         if (status != 0) {
1796                 goto err;
1797         }
1798
1799         status = SMB_VFS_NEXT_SETXATTR(handle, client_path, name, value,
1800                                        size, flags);
1801
1802 err:
1803         TALLOC_FREE(client_path);
1804         return status;
1805 }
1806
1807 static bool um_is_offline(struct vfs_handle_struct *handle,
1808                           const struct smb_filename *fname,
1809                           SMB_STRUCT_STAT *sbuf)
1810 {
1811         bool ret;
1812         struct smb_filename *client_fname = NULL;
1813         int status;
1814
1815         DEBUG(10, ("Entering um_is_offline\n"));
1816
1817         if (!is_in_media_files(fname->base_name)) {
1818                 return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1819         }
1820
1821         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1822                                             fname, &client_fname);
1823         if (status != 0) {
1824                 ret = false;
1825                 goto err;
1826         }
1827
1828         ret = SMB_VFS_NEXT_IS_OFFLINE(handle, client_fname, sbuf);
1829
1830 err:
1831         TALLOC_FREE(client_fname);
1832         return ret;
1833 }
1834
1835 static int um_set_offline(struct vfs_handle_struct *handle,
1836                           const struct smb_filename *fname)
1837 {
1838         int status;
1839         struct smb_filename *client_fname = NULL;
1840
1841         DEBUG(10, ("Entering um_set_offline\n"));
1842
1843         if (!is_in_media_files(fname->base_name)) {
1844                 return SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
1845         }
1846
1847         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1848                                             fname, &client_fname);
1849         if (status != 0) {
1850                 goto err;
1851         }
1852
1853         status = SMB_VFS_NEXT_SET_OFFLINE(handle, client_fname);
1854
1855 err:
1856         TALLOC_FREE(client_fname);
1857         return status;
1858 }
1859
1860 static int um_connect(vfs_handle_struct *handle,
1861                          const char *service,
1862                          const char *user)
1863 {
1864         int rc;
1865         struct um_config_data *config;
1866         int enumval;
1867
1868         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1869         if (rc != 0) {
1870                 return rc;
1871         }
1872
1873         config = talloc_zero(handle->conn, struct um_config_data);
1874         if (!config) {
1875                 DEBUG(1, ("talloc_zero() failed\n"));
1876                 errno = ENOMEM;
1877                 return -1;
1878         }
1879
1880         enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1881                                "clientid", um_clientid, UM_CLIENTID_NAME);
1882         if (enumval == -1) {
1883                 DEBUG(1, ("value for %s: type unknown\n",
1884                           UM_PARAM_TYPE_NAME));
1885                 return -1;
1886         }
1887         config->clientid = (enum um_clientid)enumval;
1888
1889         SMB_VFS_HANDLE_SET_DATA(handle, config,
1890                                 NULL, struct um_config_data,
1891                                 return -1);
1892
1893         return 0;
1894 }
1895
1896 /* VFS operations structure */
1897
1898 static struct vfs_fn_pointers vfs_um_fns = {
1899         .connect_fn = um_connect,
1900
1901         /* Disk operations */
1902
1903         .statvfs_fn = um_statvfs,
1904
1905         /* Directory operations */
1906
1907         .opendir_fn = um_opendir,
1908         .fdopendir_fn = um_fdopendir,
1909         .readdir_fn = um_readdir,
1910         .seekdir_fn = um_seekdir,
1911         .telldir_fn = um_telldir,
1912         .rewind_dir_fn = um_rewinddir,
1913         .mkdir_fn = um_mkdir,
1914         .rmdir_fn = um_rmdir,
1915         .closedir_fn = um_closedir,
1916         .init_search_op_fn = um_init_search_op,
1917
1918         /* File operations */
1919
1920         .open_fn = um_open,
1921         .create_file_fn = um_create_file,
1922         .rename_fn = um_rename,
1923         .stat_fn = um_stat,
1924         .lstat_fn = um_lstat,
1925         .fstat_fn = um_fstat,
1926         .unlink_fn = um_unlink,
1927         .chmod_fn = um_chmod,
1928         .chown_fn = um_chown,
1929         .lchown_fn = um_lchown,
1930         .chdir_fn = um_chdir,
1931         .ntimes_fn = um_ntimes,
1932         .symlink_fn = um_symlink,
1933         .readlink_fn = um_readlink,
1934         .link_fn = um_link,
1935         .mknod_fn = um_mknod,
1936         .realpath_fn = um_realpath,
1937         .chflags_fn = um_chflags,
1938         .streaminfo_fn = um_streaminfo,
1939
1940         /* NT ACL operations. */
1941
1942         .get_nt_acl_fn = um_get_nt_acl,
1943
1944         /* POSIX ACL operations. */
1945
1946         .chmod_acl_fn = um_chmod_acl,
1947
1948         .sys_acl_get_file_fn = um_sys_acl_get_file,
1949         .sys_acl_set_file_fn = um_sys_acl_set_file,
1950         .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1951
1952         /* EA operations. */
1953         .getxattr_fn = um_getxattr,
1954         .listxattr_fn = um_listxattr,
1955         .removexattr_fn = um_removexattr,
1956         .setxattr_fn = um_setxattr,
1957
1958         /* aio operations */
1959
1960         /* offline operations */
1961         .is_offline_fn = um_is_offline,
1962         .set_offline_fn = um_set_offline
1963 };
1964
1965 NTSTATUS vfs_unityed_media_init(void);
1966 NTSTATUS vfs_unityed_media_init(void)
1967 {
1968         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1969                                         "unityed_media", &vfs_um_fns);
1970         if (!NT_STATUS_IS_OK(ret)) {
1971                 return ret;
1972         }
1973
1974         vfs_um_debug_level = debug_add_class("unityed_media");
1975
1976         if (vfs_um_debug_level == -1) {
1977                 vfs_um_debug_level = DBGC_VFS;
1978                 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1979                           "debugging class.\n"));
1980         }
1981
1982         return ret;
1983 }