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