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