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