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