s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[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 #include "source3/lib/substitute.h"
66
67 #define UM_PARAM_TYPE_NAME "unityed_media"
68
69 static const char *AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
70 static const size_t AVID_MXF_DIRNAME_LEN = 19;
71 static const char *OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
72 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
73 static const char *APPLE_DOUBLE_PREFIX = "._";
74 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
75 static int vfs_um_debug_level = DBGC_VFS;
76
77 enum um_clientid {UM_CLIENTID_NAME, UM_CLIENTID_IP, UM_CLIENTID_HOSTNAME};
78
79 struct um_config_data {
80         enum um_clientid clientid;
81 };
82
83 static const struct enum_list um_clientid[] = {
84         {UM_CLIENTID_NAME, "user"},
85         {UM_CLIENTID_IP, "ip"},
86         {UM_CLIENTID_HOSTNAME, "hostname"},
87         {-1, NULL}
88 };
89
90 /* supplements the directory list stream */
91 typedef struct um_dirinfo_struct {
92         DIR* dirstream;
93         char *dirpath;
94         char *clientPath;
95         bool isInMediaFiles;
96         char *clientSubDirname;
97 } um_dirinfo_struct;
98
99 /**
100  * Returns true and first group of digits in path, false and 0 otherwise
101  **/
102 static bool get_digit_group(const char *path, uintmax_t *digit)
103 {
104         const char *p = path;
105         codepoint_t cp;
106         size_t size;
107         int error = 0;
108
109         DEBUG(10, ("get_digit_group entering with path '%s'\n",
110                    path));
111
112         /*
113          * Delibiretly initialize to 0 because callers use this result
114          * even though the string doesn't contain any number and we
115          * returned false
116          */
117         *digit = 0;
118
119         while (*p) {
120                 cp = next_codepoint(p, &size);
121                 if (cp == -1) {
122                         return false;
123                 }
124                 if ((size == 1) && (isdigit(cp))) {
125                         *digit = (uintmax_t)smb_strtoul(p,
126                                                         NULL,
127                                                         10,
128                                                         &error,
129                                                         SMB_STR_STANDARD);
130                         if (error != 0) {
131                                 return false;
132                         }
133                         DEBUG(10, ("num_suffix = '%ju'\n",
134                                    *digit));
135                         return true;
136                 }
137                 p += size;
138         }
139
140         return false;
141 }
142
143 /* Add "_<remote_name>.<number>" suffix to path or filename.
144  *
145  * Success: return 0
146  * Failure: set errno, path NULL, return -1
147  */
148
149 static int alloc_append_client_suffix(vfs_handle_struct *handle,
150                                       char **path)
151 {
152         int status = 0;
153         uintmax_t number;
154         const char *clientid;
155         struct um_config_data *config;
156
157         DEBUG(10, ("Entering with path '%s'\n", *path));
158
159         SMB_VFS_HANDLE_GET_DATA(handle, config,
160                                 struct um_config_data,
161                                 return -1);
162
163         (void)get_digit_group(*path, &number);
164
165         switch (config->clientid) {
166
167         case UM_CLIENTID_IP:
168                 clientid = tsocket_address_inet_addr_string(
169                         handle->conn->sconn->remote_address, talloc_tos());
170                 if (clientid == NULL) {
171                         errno = ENOMEM;
172                         status = -1;
173                         goto err;
174                 }
175                 break;
176
177         case UM_CLIENTID_HOSTNAME:
178                 clientid = get_remote_machine_name();
179                 break;
180
181         case UM_CLIENTID_NAME:
182         default:
183                 clientid = get_current_username();
184                 break;
185         }
186
187         *path = talloc_asprintf_append(*path, "_%s.%ju",
188                                        clientid, number);
189         if (*path == NULL) {
190                 DEBUG(1, ("alloc_append_client_suffix "
191                                      "out of memory\n"));
192                 errno = ENOMEM;
193                 status = -1;
194                 goto err;
195         }
196         DEBUG(10, ("Leaving with *path '%s'\n", *path));
197 err:
198         return status;
199 }
200
201 /* Returns true if the file or directory begins with the appledouble
202  * prefix.
203  */
204 static bool is_apple_double(const char* fname)
205 {
206         bool ret = false;
207
208         DEBUG(10, ("Entering with fname '%s'\n", fname));
209
210         if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
211                 ret = true;
212         }
213         DEBUG(10, ("Leaving with ret '%s'\n",
214                               ret == true ? "true" : "false"));
215         return ret;
216 }
217
218 static bool starts_with_media_dir(const char* media_dirname,
219                                   size_t media_dirname_len,
220                                   const char *path)
221 {
222         bool ret = false;
223         const char *path_start = path;
224
225         DEBUG(10, ("Entering with media_dirname '%s' "
226                               "path '%s'\n", media_dirname, path));
227
228         /* Sometimes Samba gives us "./OMFI MediaFiles". */
229         if (strnequal(path, "./", 2)) {
230                 path_start += 2;
231         }
232
233         if (strnequal(media_dirname, path_start, media_dirname_len)
234             &&
235             ((path_start[media_dirname_len] == '\0') ||
236              (path_start[media_dirname_len] == '/'))) {
237                 ret = true;
238         }
239
240         DEBUG(10, ("Leaving with ret '%s'\n",
241                               ret == true ? "true" : "false"));
242         return ret;
243 }
244
245 /*
246  * Returns true if the file or directory referenced by the path is ONE
247  * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
248  * directory
249  */
250 static bool is_in_media_dir(const char *path)
251 {
252         int transition_count = 0;
253         const char *path_start = path;
254         const char *p;
255         const char *media_dirname;
256         size_t media_dirname_len;
257
258         DEBUG(10, ("Entering with path '%s'\n", path));
259
260         /* Sometimes Samba gives us "./OMFI MediaFiles". */
261         if (strnequal(path, "./", 2)) {
262                 path_start += 2;
263         }
264
265         if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
266                 media_dirname = AVID_MXF_DIRNAME;
267                 media_dirname_len = AVID_MXF_DIRNAME_LEN;
268         } else if (strnequal(path_start,
269                              OMFI_MEDIAFILES_DIRNAME,
270                              OMFI_MEDIAFILES_DIRNAME_LEN)) {
271                 media_dirname = OMFI_MEDIAFILES_DIRNAME;
272                 media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
273         } else {
274                 return false;
275         }
276
277         if (path_start[media_dirname_len] == '\0') {
278                 goto out;
279         }
280
281         p = path_start + media_dirname_len + 1;
282
283         while (true) {
284                 if (*p == '\0' || *p == '/') {
285                         if (strnequal(p - 3, "/..", 3)) {
286                                 transition_count--;
287                         } else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
288                                 transition_count++;
289                         }
290                 }
291                 if (*p == '\0') {
292                         break;
293                 }
294                 p++;
295         }
296
297 out:
298         DEBUG(10, ("Going out with transition_count '%i'\n",
299                               transition_count));
300         if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
301             ||
302             ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
303                 return true;
304         }
305         else return false;
306 }
307
308 /*
309  * Returns true if the file or directory referenced by the path is
310  * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
311  * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
312  * are assumed to be in the root directory, which is generally a safe
313  * assumption in the fixed-path world of Avid.
314  */
315 static bool is_in_media_files(const char *path)
316 {
317         bool ret = false;
318
319         DEBUG(10, ("Entering with path '%s'\n", path));
320
321         if (starts_with_media_dir(AVID_MXF_DIRNAME,
322                                   AVID_MXF_DIRNAME_LEN, path) ||
323             starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
324                                   OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
325                 ret = true;
326         }
327         DEBUG(10, ("Leaving with ret '%s'\n",
328                               ret == true ? "true" : "false"));
329         return ret;
330 }
331
332
333 /* Add client suffix to "pure-number" path.
334  *
335  * Caller must free newPath.
336  *
337  * Success: return 0
338  * Failure: set errno, newPath NULL, return -1
339  */
340 static int alloc_get_client_path(vfs_handle_struct *handle,
341                                  TALLOC_CTX *ctx,
342                                  const char *path_in,
343                                  char **path_out)
344 {
345         int status = 0;
346         char *p;
347         char *digits;
348         size_t digits_len;
349         uintmax_t number;
350
351         *path_out = talloc_strdup(ctx, path_in);
352         if (*path_out == NULL) {
353                 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
354                 return -1;
355         }
356
357         (void)get_digit_group(*path_out, &number);
358
359         digits = talloc_asprintf(NULL, "%ju", number);
360         if (digits == NULL) {
361                 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
362                 return -1;
363         }
364         digits_len = strlen(digits);
365
366         p = strstr_m(path_in, digits);
367         if ((p)
368             &&
369             ((p[digits_len] == '\0') || (p[digits_len] == '/'))
370             &&
371             (((p - path_in > 0) && (p[-1] == '/'))
372              ||
373              (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
374               &&
375               is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
376               &&
377               (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
378         {
379                 (*path_out)[p - path_in + digits_len] = '\0';
380
381                 status = alloc_append_client_suffix(handle, path_out);
382                 if (status != 0) {
383                         goto out;
384                 }
385
386                 *path_out = talloc_strdup_append(*path_out, p + digits_len);
387                 if (*path_out == NULL) {
388                         DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
389                         status = -1;
390                         goto out;
391                 }
392         }
393 out:
394         /* path_out must be freed in caller. */
395         DEBUG(10, ("Result:'%s'\n", *path_out));
396         return status;
397 }
398
399 /*
400  * Success: return 0
401  * Failure: set errno, return -1
402  */
403 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
404                                       TALLOC_CTX *ctx,
405                                       const struct smb_filename *smb_fname,
406                                       struct smb_filename **client_fname)
407 {
408         int status ;
409
410         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
411                    smb_fname->base_name));
412
413         *client_fname = cp_smb_filename(ctx, smb_fname);
414         if (*client_fname == NULL) {
415                 DEBUG(1, ("cp_smb_filename returned NULL\n"));
416                 return -1;
417         }
418         status = alloc_get_client_path(handle, ctx,
419                                        smb_fname->base_name,
420                                        &(*client_fname)->base_name);
421         if (status != 0) {
422                 return -1;
423         }
424
425         DEBUG(10, ("Leaving with (*client_fname)->base_name "
426                    "'%s'\n", (*client_fname)->base_name));
427
428         return 0;
429 }
430
431
432 /*
433  * Success: return 0
434  * Failure: set errno, return -1
435  */
436 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
437                                          TALLOC_CTX *ctx,
438                                          char **path,
439                                          const char *suffix_number)
440 {
441         int status;
442
443         DEBUG(10, ("Entering with suffix_number '%s'\n",
444                    suffix_number));
445
446         *path = talloc_strdup(ctx, suffix_number);
447         if (*path == NULL) {
448                 DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
449                 return -1;
450         }
451         status = alloc_append_client_suffix(handle, path);
452         if (status != 0) {
453                 return -1;
454         }
455
456         DEBUG(10, ("Leaving with *path '%s'\n", *path));
457
458         return 0;
459 }
460
461 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
462                                     const char *fname,
463                                     struct um_dirinfo_struct **di_result)
464 {
465         int status = 0;
466         char *digits;
467         uintmax_t number;
468         struct um_dirinfo_struct *dip;
469
470         DEBUG(10, ("Entering with fname '%s'\n", fname));
471
472         *di_result = talloc(NULL, struct um_dirinfo_struct);
473         if (*di_result == NULL) {
474                 goto err;
475         }
476         dip = *di_result;
477
478         dip->dirpath = talloc_strdup(dip, fname);
479         if (dip->dirpath == NULL) {
480                 goto err;
481         }
482
483         if (!is_in_media_files(fname)) {
484                 dip->isInMediaFiles = false;
485                 dip->clientPath = NULL;
486                 dip->clientSubDirname = NULL;
487                 goto out;
488         }
489
490         dip->isInMediaFiles = true;
491
492         (void)get_digit_group(fname, &number);
493         digits = talloc_asprintf(talloc_tos(), "%ju", number);
494         if (digits == NULL) {
495                 goto err;
496         }
497
498         status = alloc_set_client_dirinfo_path(handle, dip,
499                                                &dip->clientSubDirname,
500                                                digits);
501         if (status != 0) {
502                 goto err;
503         }
504
505         status = alloc_get_client_path(handle, dip, fname,
506                                        &dip->clientPath);
507         if (status != 0 || dip->clientPath == NULL) {
508                 goto err;
509         }
510
511 out:
512         DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
513                               "(*dirInfo)->clientPath '%s'\n",
514                               dip->dirpath, dip->clientPath));
515         return status;
516
517 err:
518         DEBUG(1, ("Failing with fname '%s'\n", fname));
519         TALLOC_FREE(*di_result);
520         status = -1;
521         errno = ENOMEM;
522         return status;
523 }
524
525 /**********************************************************************
526  * VFS functions
527  **********************************************************************/
528
529 /*
530  * Success: return 0
531  * Failure: set errno, return -1
532  */
533 static int um_statvfs(struct vfs_handle_struct *handle,
534                       const struct smb_filename *smb_fname,
535                       struct vfs_statvfs_struct *statbuf)
536 {
537         int status;
538         struct smb_filename *client_fname = NULL;
539
540         DEBUG(10, ("Entering with path '%s'\n", smb_fname->base_name));
541
542         if (!is_in_media_files(smb_fname->base_name)) {
543                 return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
544         }
545
546         status = alloc_get_client_smb_fname(handle,
547                                 talloc_tos(),
548                                 smb_fname,
549                                 &client_fname);
550         if (status != 0) {
551                 goto err;
552         }
553
554         status = SMB_VFS_NEXT_STATVFS(handle, client_fname, statbuf);
555 err:
556         TALLOC_FREE(client_fname);
557         DEBUG(10, ("Leaving with path '%s'\n", smb_fname->base_name));
558         return status;
559 }
560
561 static DIR *um_fdopendir(vfs_handle_struct *handle,
562                          files_struct *fsp,
563                          const char *mask,
564                          uint32_t attr)
565 {
566         struct um_dirinfo_struct *dirInfo = NULL;
567         DIR *dirstream;
568
569         DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
570                    fsp->fsp_name->base_name));
571
572         dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
573         if (!dirstream) {
574                 goto err;
575         }
576
577         if (alloc_set_client_dirinfo(handle,
578                                      fsp->fsp_name->base_name,
579                                      &dirInfo)) {
580                 goto err;
581         }
582
583         dirInfo->dirstream = dirstream;
584
585         if (!dirInfo->isInMediaFiles) {
586                 /*
587                  * FIXME: this is the original code, something must be
588                  * missing here, but what? -slow
589                  */
590                 goto out;
591         }
592
593 out:
594         DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
595                    "dirInfo->clientPath '%s', "
596                    "fsp->fsp_name->st.st_ex_mtime %s",
597                    dirInfo->dirpath,
598                    dirInfo->clientPath,
599                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
600         return (DIR *) dirInfo;
601
602 err:
603         DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
604                   fsp->fsp_name->base_name));
605         TALLOC_FREE(dirInfo);
606         return NULL;
607 }
608
609 /*
610  * skip own suffixed directory
611  * replace own suffixed directory with non suffixed.
612  *
613  * Success: return dirent
614  * End of data: return NULL
615  * Failure: set errno, return NULL
616  */
617 static struct dirent *
618 um_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp)
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, dirfsp, dirInfo->dirstream);
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, dirfsp, dirInfo->dirstream);
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\n"));
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_rewinddir(vfs_handle_struct *handle,
714                          DIR *dirp)
715 {
716         DEBUG(10, ("Entering and leaving um_rewinddir\n"));
717         SMB_VFS_NEXT_REWINDDIR(handle,
718                                ((um_dirinfo_struct*)dirp)->dirstream);
719 }
720
721 static int um_mkdirat(vfs_handle_struct *handle,
722                         struct files_struct *dirfsp,
723                         const struct smb_filename *smb_fname,
724                         mode_t mode)
725 {
726         int status;
727         const char *path = NULL;
728         struct smb_filename *client_fname = NULL;
729         struct smb_filename *full_fname = NULL;
730
731         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
732                                                   dirfsp,
733                                                   smb_fname);
734         if (full_fname == NULL) {
735                 return -1;
736         }
737
738         path = full_fname->base_name;
739         DEBUG(10, ("Entering with path '%s'\n", path));
740
741         if (!is_in_media_files(path) || !is_in_media_dir(path)) {
742                 TALLOC_FREE(full_fname);
743                 return SMB_VFS_NEXT_MKDIRAT(handle,
744                                 dirfsp,
745                                 smb_fname,
746                                 mode);
747         }
748
749         status = alloc_get_client_smb_fname(handle,
750                                 talloc_tos(),
751                                 full_fname,
752                                 &client_fname);
753         if (status != 0) {
754                 goto err;
755         }
756
757         status = SMB_VFS_NEXT_MKDIRAT(handle,
758                                 handle->conn->cwd_fsp,
759                                 client_fname,
760                                 mode);
761 err:
762         DEBUG(10, ("Leaving with path '%s'\n", path));
763         TALLOC_FREE(client_fname);
764         TALLOC_FREE(full_fname);
765         return status;
766 }
767
768 static int um_closedir(vfs_handle_struct *handle,
769                        DIR *dirp)
770 {
771         DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
772
773         TALLOC_FREE(dirp);
774
775         return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
776 }
777
778 static int um_openat(struct vfs_handle_struct *handle,
779                      const struct files_struct *dirfsp,
780                      const struct smb_filename *smb_fname,
781                      struct files_struct *fsp,
782                      const struct vfs_open_how *how)
783 {
784         struct smb_filename *client_fname = NULL;
785         int ret;
786
787         DBG_DEBUG("Entering with smb_fname->base_name '%s'\n",
788                   smb_fname->base_name);
789
790         if (!is_in_media_files(smb_fname->base_name)) {
791                 return SMB_VFS_NEXT_OPENAT(handle,
792                                            dirfsp,
793                                            smb_fname,
794                                            fsp,
795                                            how);
796         }
797
798         if (alloc_get_client_smb_fname(handle, talloc_tos(),
799                                        smb_fname,
800                                        &client_fname)) {
801                 ret = -1;
802                 goto err;
803         }
804
805         /*
806          * FIXME:
807          * What about fsp->fsp_name?  We also have to get correct stat
808          * info into fsp and smb_fname for DB files, don't we?
809          */
810
811         DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
812                    "smb_fname->st.st_ex_mtime %s"
813                    "fsp->fsp_name->st.st_ex_mtime %s",
814                    smb_fname->base_name,
815                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
816                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
817
818         ret = SMB_VFS_NEXT_OPENAT(handle,
819                                   dirfsp,
820                                   client_fname,
821                                   fsp,
822                                   how);
823 err:
824         TALLOC_FREE(client_fname);
825         DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
826                               smb_fname->base_name));
827         return ret;
828 }
829
830 static NTSTATUS um_create_file(vfs_handle_struct *handle,
831                                struct smb_request *req,
832                                struct files_struct *dirfsp,
833                                struct smb_filename *smb_fname,
834                                uint32_t access_mask,
835                                uint32_t share_access,
836                                uint32_t create_disposition,
837                                uint32_t create_options,
838                                uint32_t file_attributes,
839                                uint32_t oplock_request,
840                                const struct smb2_lease *lease,
841                                uint64_t allocation_size,
842                                uint32_t private_flags,
843                                struct security_descriptor *sd,
844                                struct ea_list *ea_list,
845                                files_struct **result_fsp,
846                                int *pinfo,
847                                const struct smb2_create_blobs *in_context_blobs,
848                                struct smb2_create_blobs *out_context_blobs)
849 {
850         NTSTATUS status;
851         struct smb_filename *client_fname = NULL;
852
853         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
854                    smb_fname->base_name));
855
856         if (!is_in_media_files(smb_fname->base_name)) {
857                 return SMB_VFS_NEXT_CREATE_FILE(
858                         handle,
859                         req,
860                         dirfsp,
861                         smb_fname,
862                         access_mask,
863                         share_access,
864                         create_disposition,
865                         create_options,
866                         file_attributes,
867                         oplock_request,
868                         lease,
869                         allocation_size,
870                         private_flags,
871                         sd,
872                         ea_list,
873                         result_fsp,
874                         pinfo,
875                         in_context_blobs,
876                         out_context_blobs);
877         }
878
879         if (alloc_get_client_smb_fname(handle, talloc_tos(),
880                                        smb_fname,
881                                        &client_fname)) {
882                 status = map_nt_error_from_unix(errno);
883                 goto err;
884         }
885
886         /*
887          * FIXME:
888          * This only creates files, so we don't have to worry about
889          * our fake directory stat'ing here.  But we still need to
890          * route stat calls for DB files properly, right?
891          */
892         status = SMB_VFS_NEXT_CREATE_FILE(
893                 handle,
894                 req,
895                 dirfsp,
896                 client_fname,
897                 access_mask,
898                 share_access,
899                 create_disposition,
900                 create_options,
901                 file_attributes,
902                 oplock_request,
903                 lease,
904                 allocation_size,
905                 private_flags,
906                 sd,
907                 ea_list,
908                 result_fsp,
909                 pinfo,
910                 in_context_blobs,
911                 out_context_blobs);
912 err:
913         TALLOC_FREE(client_fname);
914         DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
915                    "smb_fname->st.st_ex_mtime %s"
916                    " fsp->fsp_name->st.st_ex_mtime %s",
917                    smb_fname->base_name,
918                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
919                    (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
920                    ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
921                    "No fsp time\n"));
922         return status;
923 }
924
925 static int um_renameat(vfs_handle_struct *handle,
926                 files_struct *srcfsp,
927                 const struct smb_filename *smb_fname_src,
928                 files_struct *dstfsp,
929                 const struct smb_filename *smb_fname_dst)
930 {
931         int status;
932         struct smb_filename *src_full_fname = NULL;
933         struct smb_filename *dst_full_fname = NULL;
934         struct smb_filename *src_client_fname = NULL;
935         struct smb_filename *dst_client_fname = NULL;
936
937         src_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
938                                                   srcfsp,
939                                                   smb_fname_src);
940         if (src_full_fname == NULL) {
941                 errno = ENOMEM;
942                 return -1;
943         }
944         dst_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
945                                                   dstfsp,
946                                                   smb_fname_dst);
947         if (dst_full_fname == NULL) {
948                 TALLOC_FREE(src_full_fname);
949                 errno = ENOMEM;
950                 return -1;
951         }
952
953         DBG_DEBUG( "Entering with "
954                    "smb_fname_src->base_name '%s', "
955                    "smb_fname_dst->base_name '%s'\n",
956                    smb_fname_src->base_name,
957                    smb_fname_dst->base_name);
958
959         if (!is_in_media_files(src_full_fname->base_name)
960             &&
961             !is_in_media_files(dst_full_fname->base_name)) {
962                 TALLOC_FREE(src_full_fname);
963                 TALLOC_FREE(dst_full_fname);
964                 return SMB_VFS_NEXT_RENAMEAT(handle,
965                                         srcfsp,
966                                         smb_fname_src,
967                                         dstfsp,
968                                         smb_fname_dst);
969         }
970
971         status = alloc_get_client_smb_fname(handle, talloc_tos(),
972                                             src_full_fname,
973                                             &src_client_fname);
974         if (status != 0) {
975                 goto err;
976         }
977
978         status = alloc_get_client_smb_fname(handle, talloc_tos(),
979                                             dst_full_fname,
980                                             &dst_client_fname);
981
982         if (status != 0) {
983                 goto err;
984         }
985
986         status = SMB_VFS_NEXT_RENAMEAT(handle,
987                                 handle->conn->cwd_fsp,
988                                 src_client_fname,
989                                 handle->conn->cwd_fsp,
990                                 dst_client_fname);
991
992 err:
993         TALLOC_FREE(dst_client_fname);
994         TALLOC_FREE(src_client_fname);
995         TALLOC_FREE(src_full_fname);
996         TALLOC_FREE(dst_full_fname);
997         DBG_DEBUG( "Leaving with smb_fname_src->base_name '%s',"
998                    " smb_fname_dst->base_name '%s'\n",
999                    smb_fname_src->base_name,
1000                    smb_fname_dst->base_name);
1001         return status;
1002 }
1003
1004
1005 /*
1006  * Success: return 0
1007  * Failure: set errno, return -1
1008  */
1009 static int um_stat(vfs_handle_struct *handle,
1010                    struct smb_filename *smb_fname)
1011 {
1012         int status = 0;
1013         struct smb_filename *client_fname = NULL;
1014
1015         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1016                    smb_fname->base_name));
1017
1018         if (!is_in_media_files(smb_fname->base_name)) {
1019                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1020         }
1021
1022         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1023                                             smb_fname,
1024                                             &client_fname);
1025         if (status != 0) {
1026                 goto err;
1027         }
1028         DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1029                    client_fname->base_name));
1030
1031         status = SMB_VFS_NEXT_STAT(handle, client_fname);
1032         if (status != 0) {
1033                 goto err;
1034         }
1035
1036         /*
1037          * Unlike functions with const smb_filename, we have to modify
1038          * smb_fname itself to pass our info back up.
1039          */
1040         DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1041                    smb_fname->base_name, client_fname->base_name));
1042         smb_fname->st = client_fname->st;
1043
1044 err:
1045         TALLOC_FREE(client_fname);
1046         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1047                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1048         return status;
1049 }
1050
1051 static int um_lstat(vfs_handle_struct *handle,
1052                     struct smb_filename *smb_fname)
1053 {
1054         int status = 0;
1055         struct smb_filename *client_fname = NULL;
1056
1057         DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1058                    smb_fname->base_name));
1059
1060         if (!is_in_media_files(smb_fname->base_name)) {
1061                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1062         }
1063
1064         client_fname = NULL;
1065
1066         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1067                                             smb_fname,
1068                                             &client_fname);
1069         if (status != 0) {
1070                 goto err;
1071         }
1072         status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1073         if (status != 0) {
1074                 goto err;
1075         }
1076
1077         smb_fname->st = client_fname->st;
1078
1079 err:
1080         TALLOC_FREE(client_fname);
1081         DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1082                    ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1083         return status;
1084 }
1085
1086 static int um_fstat(vfs_handle_struct *handle,
1087                     files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1088 {
1089         int status = 0;
1090
1091         DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1092                    "'%s'\n", fsp_str_dbg(fsp)));
1093
1094         status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1095         if (status != 0) {
1096                 goto out;
1097         }
1098
1099         if ((fsp->fsp_name == NULL) ||
1100             !is_in_media_files(fsp->fsp_name->base_name)) {
1101                 goto out;
1102         }
1103
1104         status = um_stat(handle, fsp->fsp_name);
1105         if (status != 0) {
1106                 goto out;
1107         }
1108
1109         *sbuf = fsp->fsp_name->st;
1110
1111 out:
1112         DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s",
1113                    fsp->fsp_name != NULL ?
1114                    ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0\n"));
1115         return status;
1116 }
1117
1118 static int um_unlinkat(vfs_handle_struct *handle,
1119                         struct files_struct *dirfsp,
1120                         const struct smb_filename *smb_fname,
1121                         int flags)
1122 {
1123         int ret;
1124         struct smb_filename *full_fname = NULL;
1125         struct smb_filename *client_fname = NULL;
1126
1127         DEBUG(10, ("Entering um_unlinkat\n"));
1128
1129         if (!is_in_media_files(smb_fname->base_name)) {
1130                 return SMB_VFS_NEXT_UNLINKAT(handle,
1131                                 dirfsp,
1132                                 smb_fname,
1133                                 flags);
1134         }
1135
1136         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1137                                                   dirfsp,
1138                                                   smb_fname);
1139         if (full_fname == NULL) {
1140                 return -1;
1141         }
1142
1143         ret = alloc_get_client_smb_fname(handle, talloc_tos(),
1144                                             full_fname,
1145                                             &client_fname);
1146         if (ret != 0) {
1147                 goto err;
1148         }
1149
1150         ret = SMB_VFS_NEXT_UNLINKAT(handle,
1151                                 dirfsp->conn->cwd_fsp,
1152                                 client_fname,
1153                                 flags);
1154
1155 err:
1156         TALLOC_FREE(full_fname);
1157         TALLOC_FREE(client_fname);
1158         return ret;
1159 }
1160
1161 static int um_lchown(vfs_handle_struct *handle,
1162                         const struct smb_filename *smb_fname,
1163                         uid_t uid,
1164                         gid_t gid)
1165 {
1166         int status;
1167         struct smb_filename *client_fname = NULL;
1168
1169         DEBUG(10, ("Entering um_lchown\n"));
1170         if (!is_in_media_files(smb_fname->base_name)) {
1171                 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1172         }
1173
1174         status = alloc_get_client_smb_fname(handle,
1175                                 talloc_tos(),
1176                                 smb_fname,
1177                                 &client_fname);
1178         if (status != 0) {
1179                 goto err;
1180         }
1181
1182         status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1183
1184 err:
1185         TALLOC_FREE(client_fname);
1186         return status;
1187 }
1188
1189 static int um_chdir(vfs_handle_struct *handle,
1190                         const struct smb_filename *smb_fname)
1191 {
1192         int status;
1193         struct smb_filename *client_fname = NULL;
1194
1195         DEBUG(10, ("Entering um_chdir\n"));
1196
1197         if (!is_in_media_files(smb_fname->base_name)) {
1198                 return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1199         }
1200
1201         status = alloc_get_client_smb_fname(handle,
1202                                 talloc_tos(),
1203                                 smb_fname,
1204                                 &client_fname);
1205         if (status != 0) {
1206                 goto err;
1207         }
1208
1209         status = SMB_VFS_NEXT_CHDIR(handle, client_fname);
1210
1211 err:
1212         TALLOC_FREE(client_fname);
1213         return status;
1214 }
1215
1216 static int um_symlinkat(vfs_handle_struct *handle,
1217                         const struct smb_filename *link_contents,
1218                         struct files_struct *dirfsp,
1219                         const struct smb_filename *new_smb_fname)
1220 {
1221         int status;
1222         struct smb_filename *new_link_target = NULL;
1223         struct smb_filename *new_client_fname = NULL;
1224         struct smb_filename *full_fname = NULL;
1225
1226         DEBUG(10, ("Entering um_symlinkat\n"));
1227
1228         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1229                                                 dirfsp,
1230                                                 new_smb_fname);
1231         if (full_fname == NULL) {
1232                 return -1;
1233         }
1234
1235         if (!is_in_media_files(link_contents->base_name) &&
1236                         !is_in_media_files(full_fname->base_name)) {
1237                 TALLOC_FREE(full_fname);
1238                 return SMB_VFS_NEXT_SYMLINKAT(handle,
1239                                 link_contents,
1240                                 dirfsp,
1241                                 new_smb_fname);
1242         }
1243
1244         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1245                                 link_contents, &new_link_target);
1246         if (status != 0) {
1247                 goto err;
1248         }
1249         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1250                                             full_fname, &new_client_fname);
1251         if (status != 0) {
1252                 goto err;
1253         }
1254
1255         status = SMB_VFS_NEXT_SYMLINKAT(handle,
1256                                         new_link_target,
1257                                         handle->conn->cwd_fsp,
1258                                         new_client_fname);
1259
1260 err:
1261         TALLOC_FREE(new_link_target);
1262         TALLOC_FREE(new_client_fname);
1263         TALLOC_FREE(full_fname);
1264         return status;
1265 }
1266
1267 static int um_readlinkat(vfs_handle_struct *handle,
1268                         const struct files_struct *dirfsp,
1269                         const struct smb_filename *smb_fname,
1270                         char *buf,
1271                         size_t bufsiz)
1272 {
1273         int status;
1274         struct smb_filename *client_fname = NULL;
1275         struct smb_filename *full_fname = NULL;
1276
1277         DEBUG(10, ("Entering um_readlinkat\n"));
1278
1279         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1280                                                 dirfsp,
1281                                                 smb_fname);
1282         if (full_fname == NULL) {
1283                 return -1;
1284         }
1285
1286         if (!is_in_media_files(full_fname->base_name)) {
1287                 TALLOC_FREE(full_fname);
1288                 return SMB_VFS_NEXT_READLINKAT(handle,
1289                                 dirfsp,
1290                                 smb_fname,
1291                                 buf,
1292                                 bufsiz);
1293         }
1294
1295         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1296                                             full_fname, &client_fname);
1297         if (status != 0) {
1298                 goto err;
1299         }
1300
1301         status = SMB_VFS_NEXT_READLINKAT(handle,
1302                                 handle->conn->cwd_fsp,
1303                                 client_fname,
1304                                 buf,
1305                                 bufsiz);
1306
1307 err:
1308         TALLOC_FREE(full_fname);
1309         TALLOC_FREE(client_fname);
1310         return status;
1311 }
1312
1313 static int um_linkat(vfs_handle_struct *handle,
1314                         files_struct *srcfsp,
1315                         const struct smb_filename *old_smb_fname,
1316                         files_struct *dstfsp,
1317                         const struct smb_filename *new_smb_fname,
1318                         int flags)
1319 {
1320         int status;
1321         struct smb_filename *old_full_fname = NULL;
1322         struct smb_filename *new_full_fname = NULL;
1323         struct smb_filename *old_client_fname = NULL;
1324         struct smb_filename *new_client_fname = NULL;
1325
1326         old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1327                                                   srcfsp,
1328                                                   old_smb_fname);
1329         if (old_full_fname == NULL) {
1330                 return -1;
1331         }
1332         new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1333                                                   dstfsp,
1334                                                   new_smb_fname);
1335         if (new_full_fname == NULL) {
1336                 TALLOC_FREE(old_full_fname);
1337                 return -1;
1338         }
1339
1340         DEBUG(10, ("Entering um_linkat\n"));
1341         if (!is_in_media_files(old_full_fname->base_name) &&
1342                                 !is_in_media_files(new_full_fname->base_name)) {
1343                 TALLOC_FREE(old_full_fname);
1344                 TALLOC_FREE(new_full_fname);
1345                 return SMB_VFS_NEXT_LINKAT(handle,
1346                                 srcfsp,
1347                                 old_smb_fname,
1348                                 dstfsp,
1349                                 new_smb_fname,
1350                                 flags);
1351         }
1352
1353         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1354                                             old_full_fname, &old_client_fname);
1355         if (status != 0) {
1356                 goto err;
1357         }
1358         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1359                                             new_full_fname, &new_client_fname);
1360         if (status != 0) {
1361                 goto err;
1362         }
1363
1364         status = SMB_VFS_NEXT_LINKAT(handle,
1365                                 handle->conn->cwd_fsp,
1366                                 old_client_fname,
1367                                 handle->conn->cwd_fsp,
1368                                 new_client_fname,
1369                                 flags);
1370
1371 err:
1372         TALLOC_FREE(old_full_fname);
1373         TALLOC_FREE(new_full_fname);
1374         TALLOC_FREE(old_client_fname);
1375         TALLOC_FREE(new_client_fname);
1376         return status;
1377 }
1378
1379 static int um_mknodat(vfs_handle_struct *handle,
1380                 files_struct *dirfsp,
1381                 const struct smb_filename *smb_fname,
1382                 mode_t mode,
1383                 SMB_DEV_T dev)
1384 {
1385         int status;
1386         struct smb_filename *client_fname = NULL;
1387         struct smb_filename *full_fname = NULL;
1388
1389         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1390                                                   dirfsp,
1391                                                   smb_fname);
1392         if (full_fname == NULL) {
1393                 return -1;
1394         }
1395
1396         DEBUG(10, ("Entering um_mknodat\n"));
1397         if (!is_in_media_files(full_fname->base_name)) {
1398                 TALLOC_FREE(full_fname);
1399                 return SMB_VFS_NEXT_MKNODAT(handle,
1400                                 dirfsp,
1401                                 smb_fname,
1402                                 mode,
1403                                 dev);
1404         }
1405
1406         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1407                                             full_fname, &client_fname);
1408         if (status != 0) {
1409                 goto err;
1410         }
1411
1412         status = SMB_VFS_NEXT_MKNODAT(handle,
1413                         handle->conn->cwd_fsp,
1414                         client_fname,
1415                         mode,
1416                         dev);
1417
1418 err:
1419         TALLOC_FREE(client_fname);
1420         TALLOC_FREE(full_fname);
1421         return status;
1422 }
1423
1424 static struct smb_filename *um_realpath(vfs_handle_struct *handle,
1425                                 TALLOC_CTX *ctx,
1426                                 const struct smb_filename *smb_fname)
1427 {
1428         struct smb_filename *client_fname = NULL;
1429         struct smb_filename *result_fname = NULL;
1430         int status;
1431
1432         DEBUG(10, ("Entering um_realpath\n"));
1433
1434         if (!is_in_media_files(smb_fname->base_name)) {
1435                 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1436         }
1437
1438         status = alloc_get_client_smb_fname(handle, talloc_tos(),
1439                                             smb_fname, &client_fname);
1440         if (status != 0) {
1441                 goto err;
1442         }
1443
1444         result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, client_fname);
1445
1446 err:
1447         TALLOC_FREE(client_fname);
1448         return result_fname;
1449 }
1450
1451 static int um_connect(vfs_handle_struct *handle,
1452                          const char *service,
1453                          const char *user)
1454 {
1455         int rc;
1456         struct um_config_data *config;
1457         int enumval;
1458
1459         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1460         if (rc != 0) {
1461                 return rc;
1462         }
1463
1464         config = talloc_zero(handle->conn, struct um_config_data);
1465         if (!config) {
1466                 DEBUG(1, ("talloc_zero() failed\n"));
1467                 errno = ENOMEM;
1468                 return -1;
1469         }
1470
1471         enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1472                                "clientid", um_clientid, UM_CLIENTID_NAME);
1473         if (enumval == -1) {
1474                 DEBUG(1, ("value for %s: type unknown\n",
1475                           UM_PARAM_TYPE_NAME));
1476                 return -1;
1477         }
1478         config->clientid = (enum um_clientid)enumval;
1479
1480         SMB_VFS_HANDLE_SET_DATA(handle, config,
1481                                 NULL, struct um_config_data,
1482                                 return -1);
1483
1484         return 0;
1485 }
1486
1487 /* VFS operations structure */
1488
1489 static struct vfs_fn_pointers vfs_um_fns = {
1490         .connect_fn = um_connect,
1491
1492         /* Disk operations */
1493
1494         .statvfs_fn = um_statvfs,
1495
1496         /* Directory operations */
1497
1498         .fdopendir_fn = um_fdopendir,
1499         .readdir_fn = um_readdir,
1500         .rewind_dir_fn = um_rewinddir,
1501         .mkdirat_fn = um_mkdirat,
1502         .closedir_fn = um_closedir,
1503
1504         /* File operations */
1505
1506         .openat_fn = um_openat,
1507         .create_file_fn = um_create_file,
1508         .renameat_fn = um_renameat,
1509         .stat_fn = um_stat,
1510         .lstat_fn = um_lstat,
1511         .fstat_fn = um_fstat,
1512         .unlinkat_fn = um_unlinkat,
1513         .lchown_fn = um_lchown,
1514         .chdir_fn = um_chdir,
1515         .symlinkat_fn = um_symlinkat,
1516         .readlinkat_fn = um_readlinkat,
1517         .linkat_fn = um_linkat,
1518         .mknodat_fn = um_mknodat,
1519         .realpath_fn = um_realpath,
1520
1521         /* EA operations. */
1522         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1523         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1524 };
1525
1526 static_decl_vfs;
1527 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1528 {
1529         NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1530                                         "unityed_media", &vfs_um_fns);
1531         if (!NT_STATUS_IS_OK(ret)) {
1532                 return ret;
1533         }
1534
1535         vfs_um_debug_level = debug_add_class("unityed_media");
1536
1537         if (vfs_um_debug_level == -1) {
1538                 vfs_um_debug_level = DBGC_VFS;
1539                 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1540                           "debugging class.\n"));
1541         }
1542
1543         return ret;
1544 }