replmd: check for duplicate values in MOD_REPLACE case
[Samba.git] / source3 / modules / vfs_unityed_media.c
blob34881bc50b7517c3b601ab8a09fab91deb612914
1 /*
2 * Samba VFS module supporting multiple AVID clients sharing media.
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>
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.
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.
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.
26 * Unityed Media is a Samba VFS module that allows multiple AVID
27 * clients to share media.
29 * Add this module to the vfs objects option in your Samba share
30 * configuration.
31 * eg.
33 * [avid_win]
34 * path = /video
35 * vfs objects = unityed_media
36 * ...
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 *):
42 * veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
43 * delete veto files = yes
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.
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.
57 #include "includes.h"
58 #include "system/filesys.h"
59 #include "smbd/smbd.h"
60 #include "../smbd/globals.h"
61 #include "auth.h"
62 #include "../lib/tsocket/tsocket.h"
63 #include <libgen.h>
65 #define UM_PARAM_TYPE_NAME "unityed_media"
67 static const char *AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
68 static const size_t AVID_MXF_DIRNAME_LEN = 19;
69 static const char *OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
70 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
71 static const char *APPLE_DOUBLE_PREFIX = "._";
72 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
73 static int vfs_um_debug_level = DBGC_VFS;
75 enum um_clientid {UM_CLIENTID_NAME, UM_CLIENTID_IP, UM_CLIENTID_HOSTNAME};
77 struct um_config_data {
78 enum um_clientid clientid;
81 static const struct enum_list um_clientid[] = {
82 {UM_CLIENTID_NAME, "user"},
83 {UM_CLIENTID_IP, "ip"},
84 {UM_CLIENTID_HOSTNAME, "hostname"},
85 {-1, NULL}
88 /* supplements the directory list stream */
89 typedef struct um_dirinfo_struct {
90 DIR* dirstream;
91 char *dirpath;
92 char *clientPath;
93 bool isInMediaFiles;
94 char *clientSubDirname;
95 } um_dirinfo_struct;
97 /**
98 * Returns true and first group of digits in path, false and 0 otherwise
99 **/
100 static bool get_digit_group(const char *path, uintmax_t *digit)
102 const char *p = path;
103 char *endp = NULL;
104 codepoint_t cp;
105 size_t size;
107 DEBUG(10, ("get_digit_group entering with path '%s'\n",
108 path));
111 * Delibiretly initialize to 0 because callers use this result
112 * even though the string doesn't contain any number and we
113 * returned false
115 *digit = 0;
117 while (*p) {
118 cp = next_codepoint(p, &size);
119 if (cp == -1) {
120 return false;
122 if ((size == 1) && (isdigit(cp))) {
123 *digit = (uintmax_t)strtoul(p, &endp, 10);
124 DEBUG(10, ("num_suffix = '%ju'\n",
125 *digit));
126 return true;
128 p += size;
131 return false;
134 /* Add "_<remote_name>.<number>" suffix to path or filename.
136 * Success: return 0
137 * Failure: set errno, path NULL, return -1
140 static int alloc_append_client_suffix(vfs_handle_struct *handle,
141 char **path)
143 int status = 0;
144 uintmax_t number;
145 const char *clientid;
146 struct um_config_data *config;
148 DEBUG(10, ("Entering with path '%s'\n", *path));
150 SMB_VFS_HANDLE_GET_DATA(handle, config,
151 struct um_config_data,
152 return -1);
154 (void)get_digit_group(*path, &number);
156 switch (config->clientid) {
158 case UM_CLIENTID_IP:
159 clientid = tsocket_address_inet_addr_string(
160 handle->conn->sconn->remote_address, talloc_tos());
161 if (clientid == NULL) {
162 errno = ENOMEM;
163 status = -1;
164 goto err;
166 break;
168 case UM_CLIENTID_HOSTNAME:
169 clientid = get_remote_machine_name();
170 break;
172 case UM_CLIENTID_NAME:
173 default:
174 clientid = get_current_username();
175 break;
178 *path = talloc_asprintf_append(*path, "_%s.%ju",
179 clientid, number);
180 if (*path == NULL) {
181 DEBUG(1, ("alloc_append_client_suffix "
182 "out of memory\n"));
183 errno = ENOMEM;
184 status = -1;
185 goto err;
187 DEBUG(10, ("Leaving with *path '%s'\n", *path));
188 err:
189 return status;
192 /* Returns true if the file or directory begins with the appledouble
193 * prefix.
195 static bool is_apple_double(const char* fname)
197 bool ret = false;
199 DEBUG(10, ("Entering with fname '%s'\n", fname));
201 if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
202 ret = true;
204 DEBUG(10, ("Leaving with ret '%s'\n",
205 ret == true ? "true" : "false"));
206 return ret;
209 static bool starts_with_media_dir(const char* media_dirname,
210 size_t media_dirname_len,
211 const char *path)
213 bool ret = false;
214 const char *path_start = path;
216 DEBUG(10, ("Entering with media_dirname '%s' "
217 "path '%s'\n", media_dirname, path));
219 /* Sometimes Samba gives us "./OMFI MediaFiles". */
220 if (strnequal(path, "./", 2)) {
221 path_start += 2;
224 if (strnequal(media_dirname, path_start, media_dirname_len)
226 ((path_start[media_dirname_len] == '\0') ||
227 (path_start[media_dirname_len] == '/'))) {
228 ret = true;
231 DEBUG(10, ("Leaving with ret '%s'\n",
232 ret == true ? "true" : "false"));
233 return ret;
237 * Returns true if the file or directory referenced by the path is ONE
238 * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
239 * directory
241 static bool is_in_media_dir(const char *path)
243 int transition_count = 0;
244 const char *path_start = path;
245 const char *p;
246 const char *media_dirname;
247 size_t media_dirname_len;
249 DEBUG(10, ("Entering with path'%s' ", path));
251 /* Sometimes Samba gives us "./OMFI MediaFiles". */
252 if (strnequal(path, "./", 2)) {
253 path_start += 2;
256 if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
257 media_dirname = AVID_MXF_DIRNAME;
258 media_dirname_len = AVID_MXF_DIRNAME_LEN;
259 } else if (strnequal(path_start,
260 OMFI_MEDIAFILES_DIRNAME,
261 OMFI_MEDIAFILES_DIRNAME_LEN)) {
262 media_dirname = OMFI_MEDIAFILES_DIRNAME;
263 media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
264 } else {
265 return false;
268 if (path_start[media_dirname_len] == '\0') {
269 goto out;
272 p = path_start + media_dirname_len + 1;
274 while (true) {
275 if (*p == '\0' || *p == '/') {
276 if (strnequal(p - 3, "/..", 3)) {
277 transition_count--;
278 } else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
279 transition_count++;
282 if (*p == '\0') {
283 break;
285 p++;
288 out:
289 DEBUG(10, ("Going out with transition_count '%i'\n",
290 transition_count));
291 if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
293 ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
294 return true;
296 else return false;
300 * Returns true if the file or directory referenced by the path is
301 * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
302 * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
303 * are assumed to be in the root directory, which is generally a safe
304 * assumption in the fixed-path world of Avid.
306 static bool is_in_media_files(const char *path)
308 bool ret = false;
310 DEBUG(10, ("Entering with path '%s'\n", path));
312 if (starts_with_media_dir(AVID_MXF_DIRNAME,
313 AVID_MXF_DIRNAME_LEN, path) ||
314 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
315 OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
316 ret = true;
318 DEBUG(10, ("Leaving with ret '%s'\n",
319 ret == true ? "true" : "false"));
320 return ret;
324 /* Add client suffix to "pure-number" path.
326 * Caller must free newPath.
328 * Success: return 0
329 * Failure: set errno, newPath NULL, return -1
331 static int alloc_get_client_path(vfs_handle_struct *handle,
332 TALLOC_CTX *ctx,
333 const char *path_in,
334 char **path_out)
336 int status = 0;
337 char *p;
338 char *digits;
339 size_t digits_len;
340 uintmax_t number;
342 *path_out = talloc_strdup(ctx, path_in);
343 if (*path_out == NULL) {
344 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
345 return -1;
348 (void)get_digit_group(*path_out, &number);
350 digits = talloc_asprintf(NULL, "%ju", number);
351 if (digits == NULL) {
352 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
353 return -1;
355 digits_len = strlen(digits);
357 p = strstr_m(path_in, digits);
358 if ((p)
360 ((p[digits_len] == '\0') || (p[digits_len] == '/'))
362 (((p - path_in > 0) && (p[-1] == '/'))
364 (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
366 is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
368 (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
370 (*path_out)[p - path_in + digits_len] = '\0';
372 status = alloc_append_client_suffix(handle, path_out);
373 if (status != 0) {
374 goto out;
377 *path_out = talloc_strdup_append(*path_out, p + digits_len);
378 if (*path_out == NULL) {
379 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
380 status = -1;
381 goto out;
384 out:
385 /* path_out must be freed in caller. */
386 DEBUG(10, ("Result:'%s'\n", *path_out));
387 return status;
391 * Success: return 0
392 * Failure: set errno, return -1
394 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
395 TALLOC_CTX *ctx,
396 const struct smb_filename *smb_fname,
397 struct smb_filename **client_fname)
399 int status ;
401 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
402 smb_fname->base_name));
404 *client_fname = cp_smb_filename(ctx, smb_fname);
405 if (*client_fname == NULL) {
406 DEBUG(1, ("cp_smb_filename returned NULL\n"));
407 return -1;
409 status = alloc_get_client_path(handle, ctx,
410 smb_fname->base_name,
411 &(*client_fname)->base_name);
412 if (status != 0) {
413 return -1;
416 DEBUG(10, ("Leaving with (*client_fname)->base_name "
417 "'%s'\n", (*client_fname)->base_name));
419 return 0;
424 * Success: return 0
425 * Failure: set errno, return -1
427 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
428 TALLOC_CTX *ctx,
429 char **path,
430 const char *suffix_number)
432 int status;
434 DEBUG(10, ("Entering with suffix_number '%s'\n",
435 suffix_number));
437 *path = talloc_strdup(ctx, suffix_number);
438 if (*path == NULL) {
439 DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
440 return -1;
442 status = alloc_append_client_suffix(handle, path);
443 if (status != 0) {
444 return -1;
447 DEBUG(10, ("Leaving with *path '%s'\n", *path));
449 return 0;
452 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
453 const char *fname,
454 struct um_dirinfo_struct **di_result)
456 int status = 0;
457 char *digits;
458 uintmax_t number;
459 struct um_dirinfo_struct *dip;
461 DEBUG(10, ("Entering with fname '%s'\n", fname));
463 *di_result = talloc(NULL, struct um_dirinfo_struct);
464 if (*di_result == NULL) {
465 goto err;
467 dip = *di_result;
469 dip->dirpath = talloc_strdup(dip, fname);
470 if (dip->dirpath == NULL) {
471 goto err;
474 if (!is_in_media_files(fname)) {
475 dip->isInMediaFiles = false;
476 dip->clientPath = NULL;
477 dip->clientSubDirname = NULL;
478 goto out;
481 dip->isInMediaFiles = true;
483 (void)get_digit_group(fname, &number);
484 digits = talloc_asprintf(talloc_tos(), "%ju", number);
485 if (digits == NULL) {
486 goto err;
489 status = alloc_set_client_dirinfo_path(handle, dip,
490 &dip->clientSubDirname,
491 digits);
492 if (status != 0) {
493 goto err;
496 status = alloc_get_client_path(handle, dip, fname,
497 &dip->clientPath);
498 if (status != 0 || dip->clientPath == NULL) {
499 goto err;
502 out:
503 DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
504 "(*dirInfo)->clientPath '%s'\n",
505 dip->dirpath, dip->clientPath));
506 return status;
508 err:
509 DEBUG(1, ("Failing with fname '%s'\n", fname));
510 TALLOC_FREE(*di_result);
511 status = -1;
512 errno = ENOMEM;
513 return status;
516 /**********************************************************************
517 * VFS functions
518 **********************************************************************/
521 * Success: return 0
522 * Failure: set errno, return -1
524 static int um_statvfs(struct vfs_handle_struct *handle,
525 const struct smb_filename *smb_fname,
526 struct vfs_statvfs_struct *statbuf)
528 int status;
529 struct smb_filename *client_fname = NULL;
531 DEBUG(10, ("Entering with path '%s'\n", smb_fname->base_name));
533 if (!is_in_media_files(smb_fname->base_name)) {
534 return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
537 status = alloc_get_client_smb_fname(handle,
538 talloc_tos(),
539 smb_fname,
540 &client_fname);
541 if (status != 0) {
542 goto err;
545 status = SMB_VFS_NEXT_STATVFS(handle, client_fname, statbuf);
546 err:
547 TALLOC_FREE(client_fname);
548 DEBUG(10, ("Leaving with path '%s'\n", smb_fname->base_name));
549 return status;
552 /* Success: return a um_dirinfo_struct cast as a DIR
553 * Failure: set errno, return NULL
555 static DIR *um_opendir(vfs_handle_struct *handle,
556 const struct smb_filename *smb_fname,
557 const char *mask,
558 uint32_t attr)
560 struct um_dirinfo_struct *dirInfo;
562 DEBUG(10, ("Entering with fname '%s'\n", smb_fname->base_name));
564 if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo)) {
565 goto err;
568 if (!dirInfo->isInMediaFiles) {
569 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
570 handle, smb_fname, mask, attr);
571 } else {
572 struct smb_filename *client_smb_fname =
573 synthetic_smb_fname(talloc_tos(),
574 dirInfo->clientPath,
575 NULL,
576 NULL,
577 smb_fname->flags);
578 if (client_smb_fname == NULL) {
579 goto err;
582 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
583 handle, client_smb_fname, mask, attr);
585 TALLOC_FREE(client_smb_fname);
588 if (dirInfo->dirstream == NULL) {
589 goto err;
592 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
593 "dirInfo->clientPath '%s'\n",
594 dirInfo->dirpath,
595 dirInfo->clientPath));
596 return (DIR*)dirInfo;
598 err:
599 DEBUG(1, ("Failing with fname '%s'\n", smb_fname->base_name));
600 TALLOC_FREE(dirInfo);
601 return NULL;
604 static DIR *um_fdopendir(vfs_handle_struct *handle,
605 files_struct *fsp,
606 const char *mask,
607 uint32_t attr)
609 struct um_dirinfo_struct *dirInfo = NULL;
610 DIR *dirstream;
612 DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
613 fsp->fsp_name->base_name));
615 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
616 if (!dirstream) {
617 goto err;
620 if (alloc_set_client_dirinfo(handle,
621 fsp->fsp_name->base_name,
622 &dirInfo)) {
623 goto err;
626 dirInfo->dirstream = dirstream;
628 if (!dirInfo->isInMediaFiles) {
630 * FIXME: this is the original code, something must be
631 * missing here, but what? -slow
633 goto out;
636 out:
637 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
638 "dirInfo->clientPath '%s', "
639 "fsp->fsp_name->st.st_ex_mtime %s",
640 dirInfo->dirpath,
641 dirInfo->clientPath,
642 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
643 return (DIR *) dirInfo;
645 err:
646 DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
647 fsp->fsp_name->base_name));
648 TALLOC_FREE(dirInfo);
649 return NULL;
653 * skip own suffixed directory
654 * replace own suffixed directory with non suffixed.
656 * Success: return dirent
657 * End of data: return NULL
658 * Failure: set errno, return NULL
660 static struct dirent *um_readdir(vfs_handle_struct *handle,
661 DIR *dirp,
662 SMB_STRUCT_STAT *sbuf)
664 um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
665 struct dirent *d = NULL;
666 int skip;
668 DEBUG(10, ("dirInfo->dirpath '%s', "
669 "dirInfo->clientPath '%s', "
670 "dirInfo->isInMediaFiles '%s', "
671 "dirInfo->clientSubDirname '%s'\n",
672 dirInfo->dirpath,
673 dirInfo->clientPath,
674 dirInfo->isInMediaFiles ? "true" : "false",
675 dirInfo->clientSubDirname));
677 if (!dirInfo->isInMediaFiles) {
678 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
681 do {
682 const char* dname;
683 bool isAppleDouble;
684 char *digits;
685 size_t digits_len;
686 uintmax_t number;
688 skip = false;
689 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
691 if (d == NULL) {
692 break;
695 /* ignore apple double prefix for logic below */
696 if (is_apple_double(d->d_name)) {
697 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
698 isAppleDouble = true;
699 } else {
700 dname = d->d_name;
701 isAppleDouble = false;
704 DEBUG(10, ("dname = '%s'\n", dname));
706 (void)get_digit_group(dname, &number);
707 digits = talloc_asprintf(talloc_tos(), "%ju", number);
708 if (digits == NULL) {
709 DEBUG(1, ("out of memory"));
710 goto err;
712 digits_len = strlen(digits);
714 if (alloc_set_client_dirinfo_path(handle,
715 dirInfo,
716 &((dirInfo)->clientSubDirname),
717 digits)) {
718 goto err;
722 * If set to "true", vfs shows digits-only
723 * non-suffixed subdirectories. Normally, such
724 * subdirectories can exists only in non-media
725 * directories, so we set it to "false". Otherwise,
726 * if we have such subdirectories (probably created
727 * over not "unityed" connection), it can be little
728 * bit confusing.
730 if (strequal(dname, digits)) {
731 skip = false;
732 } else if (strequal(dname, dirInfo->clientSubDirname)) {
734 * Remove suffix of this client's suffixed
735 * subdirectories
737 if (isAppleDouble) {
738 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
739 } else {
740 d->d_name[digits_len] = '\0';
742 } else if (strnequal(digits, dname, digits_len)) {
744 * Set to false to see another clients subdirectories
746 skip = false;
748 } while (skip);
750 DEBUG(10, ("Leaving um_readdir\n"));
751 return d;
752 err:
753 TALLOC_FREE(dirInfo);
754 return NULL;
757 static void um_seekdir(vfs_handle_struct *handle,
758 DIR *dirp,
759 long offset)
761 DEBUG(10, ("Entering and leaving um_seekdir\n"));
762 SMB_VFS_NEXT_SEEKDIR(handle,
763 ((um_dirinfo_struct*)dirp)->dirstream, offset);
766 static long um_telldir(vfs_handle_struct *handle,
767 DIR *dirp)
769 DEBUG(10, ("Entering and leaving um_telldir\n"));
770 return SMB_VFS_NEXT_TELLDIR(handle,
771 ((um_dirinfo_struct*)dirp)->dirstream);
774 static void um_rewinddir(vfs_handle_struct *handle,
775 DIR *dirp)
777 DEBUG(10, ("Entering and leaving um_rewinddir\n"));
778 SMB_VFS_NEXT_REWINDDIR(handle,
779 ((um_dirinfo_struct*)dirp)->dirstream);
782 static int um_mkdir(vfs_handle_struct *handle,
783 const struct smb_filename *smb_fname,
784 mode_t mode)
786 int status;
787 const char *path = smb_fname->base_name;
788 struct smb_filename *client_fname = NULL;
790 DEBUG(10, ("Entering with path '%s'\n", path));
792 if (!is_in_media_files(path) || !is_in_media_dir(path)) {
793 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
796 status = alloc_get_client_smb_fname(handle,
797 talloc_tos(),
798 smb_fname,
799 &client_fname);
800 if (status != 0) {
801 goto err;
804 status = SMB_VFS_NEXT_MKDIR(handle, client_fname, mode);
805 err:
806 TALLOC_FREE(client_fname);
807 DEBUG(10, ("Leaving with path '%s'\n", path));
808 return status;
811 static int um_rmdir(vfs_handle_struct *handle,
812 const struct smb_filename *smb_fname)
814 int status;
815 const char *path = smb_fname->base_name;
816 struct smb_filename *client_fname = NULL;
818 DEBUG(10, ("Entering with path '%s'\n", path));
820 if (!is_in_media_files(path)) {
821 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
824 status = alloc_get_client_smb_fname(handle,
825 talloc_tos(),
826 smb_fname,
827 &client_fname);
828 if (status != 0) {
829 goto err;
832 status = SMB_VFS_NEXT_RMDIR(handle, client_fname);
833 err:
834 TALLOC_FREE(client_fname);
835 DEBUG(10, ("Leaving with path '%s'\n", path));
836 return status;
839 static int um_closedir(vfs_handle_struct *handle,
840 DIR *dirp)
842 DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
844 TALLOC_FREE(dirp);
846 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
849 static void um_init_search_op(vfs_handle_struct *handle,
850 DIR *dirp)
852 DEBUG(10, ("Entering and leaving um_init_search_op\n"));
854 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
855 ((um_dirinfo_struct*)dirp)->dirstream);
858 static int um_open(vfs_handle_struct *handle,
859 struct smb_filename *smb_fname,
860 files_struct *fsp,
861 int flags,
862 mode_t mode)
864 int ret;
865 struct smb_filename *client_fname = NULL;
867 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
868 smb_fname->base_name));
870 if (!is_in_media_files(smb_fname->base_name)) {
871 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
874 if (alloc_get_client_smb_fname(handle, talloc_tos(),
875 smb_fname,
876 &client_fname)) {
877 ret = -1;
878 goto err;
882 * FIXME:
883 * What about fsp->fsp_name? We also have to get correct stat
884 * info into fsp and smb_fname for DB files, don't we?
887 DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
888 "smb_fname->st.st_ex_mtime %s"
889 "fsp->fsp_name->st.st_ex_mtime %s",
890 smb_fname->base_name,
891 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
892 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
894 ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
895 err:
896 TALLOC_FREE(client_fname);
897 DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
898 smb_fname->base_name));
899 return ret;
902 static NTSTATUS um_create_file(vfs_handle_struct *handle,
903 struct smb_request *req,
904 uint16_t root_dir_fid,
905 struct smb_filename *smb_fname,
906 uint32_t access_mask,
907 uint32_t share_access,
908 uint32_t create_disposition,
909 uint32_t create_options,
910 uint32_t file_attributes,
911 uint32_t oplock_request,
912 struct smb2_lease *lease,
913 uint64_t allocation_size,
914 uint32_t private_flags,
915 struct security_descriptor *sd,
916 struct ea_list *ea_list,
917 files_struct **result_fsp,
918 int *pinfo,
919 const struct smb2_create_blobs *in_context_blobs,
920 struct smb2_create_blobs *out_context_blobs)
922 NTSTATUS status;
923 struct smb_filename *client_fname = NULL;
925 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
926 smb_fname->base_name));
928 if (!is_in_media_files(smb_fname->base_name)) {
929 return SMB_VFS_NEXT_CREATE_FILE(
930 handle,
931 req,
932 root_dir_fid,
933 smb_fname,
934 access_mask,
935 share_access,
936 create_disposition,
937 create_options,
938 file_attributes,
939 oplock_request,
940 lease,
941 allocation_size,
942 private_flags,
944 ea_list,
945 result_fsp,
946 pinfo,
947 in_context_blobs,
948 out_context_blobs);
951 if (alloc_get_client_smb_fname(handle, talloc_tos(),
952 smb_fname,
953 &client_fname)) {
954 status = map_nt_error_from_unix(errno);
955 goto err;
959 * FIXME:
960 * This only creates files, so we don't have to worry about
961 * our fake directory stat'ing here. But we still need to
962 * route stat calls for DB files properly, right?
964 status = SMB_VFS_NEXT_CREATE_FILE(
965 handle,
966 req,
967 root_dir_fid,
968 client_fname,
969 access_mask,
970 share_access,
971 create_disposition,
972 create_options,
973 file_attributes,
974 oplock_request,
975 lease,
976 allocation_size,
977 private_flags,
979 ea_list,
980 result_fsp,
981 pinfo,
982 in_context_blobs,
983 out_context_blobs);
984 err:
985 TALLOC_FREE(client_fname);
986 DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
987 "smb_fname->st.st_ex_mtime %s"
988 " fsp->fsp_name->st.st_ex_mtime %s",
989 smb_fname->base_name,
990 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
991 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
992 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
993 "No fsp time\n"));
994 return status;
997 static int um_rename(vfs_handle_struct *handle,
998 const struct smb_filename *smb_fname_src,
999 const struct smb_filename *smb_fname_dst)
1001 int status;
1002 struct smb_filename *src_client_fname = NULL;
1003 struct smb_filename *dst_client_fname = NULL;
1005 DEBUG(10, ("Entering with "
1006 "smb_fname_src->base_name '%s', "
1007 "smb_fname_dst->base_name '%s'\n",
1008 smb_fname_src->base_name,
1009 smb_fname_dst->base_name));
1011 if (!is_in_media_files(smb_fname_src->base_name)
1013 !is_in_media_files(smb_fname_dst->base_name)) {
1014 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1015 smb_fname_dst);
1018 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1019 smb_fname_src,
1020 &src_client_fname);
1021 if (status != 0) {
1022 goto err;
1025 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1026 smb_fname_dst,
1027 &dst_client_fname);
1029 if (status != 0) {
1030 goto err;
1033 status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
1034 dst_client_fname);
1035 err:
1036 TALLOC_FREE(dst_client_fname);
1037 TALLOC_FREE(src_client_fname);
1038 DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
1039 " smb_fname_dst->base_name '%s'\n",
1040 smb_fname_src->base_name,
1041 smb_fname_dst->base_name));
1042 return status;
1046 * Success: return 0
1047 * Failure: set errno, return -1
1049 static int um_stat(vfs_handle_struct *handle,
1050 struct smb_filename *smb_fname)
1052 int status = 0;
1053 struct smb_filename *client_fname = NULL;
1055 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1056 smb_fname->base_name));
1058 if (!is_in_media_files(smb_fname->base_name)) {
1059 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1062 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1063 smb_fname,
1064 &client_fname);
1065 if (status != 0) {
1066 goto err;
1068 DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1069 client_fname->base_name));
1071 status = SMB_VFS_NEXT_STAT(handle, client_fname);
1072 if (status != 0) {
1073 goto err;
1077 * Unlike functions with const smb_filename, we have to modify
1078 * smb_fname itself to pass our info back up.
1080 DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1081 smb_fname->base_name, client_fname->base_name));
1082 smb_fname->st = client_fname->st;
1084 err:
1085 TALLOC_FREE(client_fname);
1086 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1087 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1088 return status;
1091 static int um_lstat(vfs_handle_struct *handle,
1092 struct smb_filename *smb_fname)
1094 int status = 0;
1095 struct smb_filename *client_fname = NULL;
1097 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1098 smb_fname->base_name));
1100 if (!is_in_media_files(smb_fname->base_name)) {
1101 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1104 client_fname = NULL;
1106 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1107 smb_fname,
1108 &client_fname);
1109 if (status != 0) {
1110 goto err;
1112 status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1113 if (status != 0) {
1114 goto err;
1117 smb_fname->st = client_fname->st;
1119 err:
1120 TALLOC_FREE(client_fname);
1121 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1122 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1123 return status;
1126 static int um_fstat(vfs_handle_struct *handle,
1127 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1129 int status = 0;
1131 DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1132 "'%s'\n", fsp_str_dbg(fsp)));
1134 status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1135 if (status != 0) {
1136 goto out;
1139 if ((fsp->fsp_name == NULL) ||
1140 !is_in_media_files(fsp->fsp_name->base_name)) {
1141 goto out;
1144 status = um_stat(handle, fsp->fsp_name);
1145 if (status != 0) {
1146 goto out;
1149 *sbuf = fsp->fsp_name->st;
1151 out:
1152 DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1153 fsp->fsp_name != NULL ?
1154 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1155 return status;
1158 static int um_unlink(vfs_handle_struct *handle,
1159 const struct smb_filename *smb_fname)
1161 int status;
1162 struct smb_filename *client_fname = NULL;
1164 DEBUG(10, ("Entering um_unlink\n"));
1166 if (!is_in_media_files(smb_fname->base_name)) {
1167 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1170 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1171 smb_fname,
1172 &client_fname);
1173 if (status != 0) {
1174 goto err;
1177 status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
1179 err:
1180 TALLOC_FREE(client_fname);
1181 return status;
1184 static int um_chmod(vfs_handle_struct *handle,
1185 const struct smb_filename *smb_fname,
1186 mode_t mode)
1188 int status;
1189 struct smb_filename *client_fname = NULL;
1191 DEBUG(10, ("Entering um_chmod\n"));
1193 if (!is_in_media_files(smb_fname->base_name)) {
1194 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1197 status = alloc_get_client_smb_fname(handle,
1198 talloc_tos(),
1199 smb_fname,
1200 &client_fname);
1201 if (status != 0) {
1202 goto err;
1205 status = SMB_VFS_NEXT_CHMOD(handle, client_fname, mode);
1207 err:
1208 TALLOC_FREE(client_fname);
1209 return status;
1212 static int um_chown(vfs_handle_struct *handle,
1213 const struct smb_filename *smb_fname,
1214 uid_t uid,
1215 gid_t gid)
1217 int status;
1218 struct smb_filename *client_fname = NULL;
1220 DEBUG(10, ("Entering um_chown\n"));
1222 if (!is_in_media_files(smb_fname->base_name)) {
1223 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1226 status = alloc_get_client_smb_fname(handle,
1227 talloc_tos(),
1228 smb_fname,
1229 &client_fname);
1230 if (status != 0) {
1231 goto err;
1234 status = SMB_VFS_NEXT_CHOWN(handle, client_fname, uid, gid);
1236 err:
1237 TALLOC_FREE(client_fname);
1238 return status;
1241 static int um_lchown(vfs_handle_struct *handle,
1242 const struct smb_filename *smb_fname,
1243 uid_t uid,
1244 gid_t gid)
1246 int status;
1247 struct smb_filename *client_fname = NULL;
1249 DEBUG(10, ("Entering um_lchown\n"));
1250 if (!is_in_media_files(smb_fname->base_name)) {
1251 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1254 status = alloc_get_client_smb_fname(handle,
1255 talloc_tos(),
1256 smb_fname,
1257 &client_fname);
1258 if (status != 0) {
1259 goto err;
1262 status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1264 err:
1265 TALLOC_FREE(client_fname);
1266 return status;
1269 static int um_chdir(vfs_handle_struct *handle,
1270 const struct smb_filename *smb_fname)
1272 int status;
1273 struct smb_filename *client_fname = NULL;
1275 DEBUG(10, ("Entering um_chdir\n"));
1277 if (!is_in_media_files(smb_fname->base_name)) {
1278 return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1281 status = alloc_get_client_smb_fname(handle,
1282 talloc_tos(),
1283 smb_fname,
1284 &client_fname);
1285 if (status != 0) {
1286 goto err;
1289 status = SMB_VFS_NEXT_CHDIR(handle, client_fname);
1291 err:
1292 TALLOC_FREE(client_fname);
1293 return status;
1296 static int um_ntimes(vfs_handle_struct *handle,
1297 const struct smb_filename *smb_fname,
1298 struct smb_file_time *ft)
1300 int status;
1301 struct smb_filename *client_fname = NULL;
1303 DEBUG(10, ("Entering um_ntimes\n"));
1305 if (!is_in_media_files(smb_fname->base_name)) {
1306 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1309 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1310 smb_fname, &client_fname);
1311 if (status != 0) {
1312 goto err;
1315 status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
1317 err:
1318 TALLOC_FREE(client_fname);
1319 return status;
1322 static int um_symlink(vfs_handle_struct *handle,
1323 const char *link_contents,
1324 const struct smb_filename *new_smb_fname)
1326 int status;
1327 char *client_link_contents = NULL;
1328 struct smb_filename *new_client_fname = NULL;
1330 DEBUG(10, ("Entering um_symlink\n"));
1332 if (!is_in_media_files(link_contents) &&
1333 !is_in_media_files(new_smb_fname->base_name)) {
1334 return SMB_VFS_NEXT_SYMLINK(handle,
1335 link_contents,
1336 new_smb_fname);
1339 status = alloc_get_client_path(handle, talloc_tos(),
1340 link_contents, &client_link_contents);
1341 if (status != 0) {
1342 goto err;
1344 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1345 new_smb_fname, &new_client_fname);
1346 if (status != 0) {
1347 goto err;
1350 status = SMB_VFS_NEXT_SYMLINK(handle,
1351 client_link_contents,
1352 new_client_fname);
1354 err:
1355 TALLOC_FREE(client_link_contents);
1356 TALLOC_FREE(new_client_fname);
1357 return status;
1360 static int um_readlink(vfs_handle_struct *handle,
1361 const struct smb_filename *smb_fname,
1362 char *buf,
1363 size_t bufsiz)
1365 int status;
1366 struct smb_filename *client_fname = NULL;
1368 DEBUG(10, ("Entering um_readlink\n"));
1370 if (!is_in_media_files(smb_fname->base_name)) {
1371 return SMB_VFS_NEXT_READLINK(handle, smb_fname,
1372 buf, bufsiz);
1375 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1376 smb_fname, &client_fname);
1377 if (status != 0) {
1378 goto err;
1381 status = SMB_VFS_NEXT_READLINK(handle, client_fname, buf, bufsiz);
1383 err:
1384 TALLOC_FREE(client_fname);
1385 return status;
1388 static int um_link(vfs_handle_struct *handle,
1389 const struct smb_filename *old_smb_fname,
1390 const struct smb_filename *new_smb_fname)
1392 int status;
1393 struct smb_filename *old_client_fname = NULL;
1394 struct smb_filename *new_client_fname = NULL;
1396 DEBUG(10, ("Entering um_link\n"));
1397 if (!is_in_media_files(old_smb_fname->base_name) &&
1398 !is_in_media_files(new_smb_fname->base_name)) {
1399 return SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
1402 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1403 old_smb_fname, &old_client_fname);
1404 if (status != 0) {
1405 goto err;
1407 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1408 new_smb_fname, &new_client_fname);
1409 if (status != 0) {
1410 goto err;
1413 status = SMB_VFS_NEXT_LINK(handle, old_client_fname, new_client_fname);
1415 err:
1416 TALLOC_FREE(old_client_fname);
1417 TALLOC_FREE(new_client_fname);
1418 return status;
1421 static int um_mknod(vfs_handle_struct *handle,
1422 const struct smb_filename *smb_fname,
1423 mode_t mode,
1424 SMB_DEV_T dev)
1426 int status;
1427 struct smb_filename *client_fname = NULL;
1429 DEBUG(10, ("Entering um_mknod\n"));
1430 if (!is_in_media_files(smb_fname->base_name)) {
1431 return SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
1434 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1435 smb_fname, &client_fname);
1436 if (status != 0) {
1437 goto err;
1440 status = SMB_VFS_NEXT_MKNOD(handle, client_fname, mode, dev);
1442 err:
1443 TALLOC_FREE(client_fname);
1444 return status;
1447 static struct smb_filename *um_realpath(vfs_handle_struct *handle,
1448 TALLOC_CTX *ctx,
1449 const struct smb_filename *smb_fname)
1451 struct smb_filename *client_fname = NULL;
1452 struct smb_filename *result_fname = NULL;
1453 int status;
1455 DEBUG(10, ("Entering um_realpath\n"));
1457 if (!is_in_media_files(smb_fname->base_name)) {
1458 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1461 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1462 smb_fname, &client_fname);
1463 if (status != 0) {
1464 goto err;
1467 result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, client_fname);
1469 err:
1470 TALLOC_FREE(client_fname);
1471 return result_fname;
1474 static int um_chflags(vfs_handle_struct *handle,
1475 const struct smb_filename *smb_fname,
1476 unsigned int flags)
1478 int status;
1479 struct smb_filename *client_fname = NULL;
1481 DEBUG(10, ("Entering um_mknod\n"));
1482 if (!is_in_media_files(smb_fname->base_name)) {
1483 return SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1486 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1487 smb_fname, &client_fname);
1488 if (status != 0) {
1489 goto err;
1492 status = SMB_VFS_NEXT_CHFLAGS(handle, client_fname, flags);
1494 err:
1495 TALLOC_FREE(client_fname);
1496 return status;
1499 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1500 struct files_struct *fsp,
1501 const struct smb_filename *smb_fname,
1502 TALLOC_CTX *ctx,
1503 unsigned int *num_streams,
1504 struct stream_struct **streams)
1506 NTSTATUS status;
1507 int ret;
1508 struct smb_filename *client_fname = NULL;
1510 DEBUG(10, ("Entering um_streaminfo\n"));
1512 if (!is_in_media_files(smb_fname->base_name)) {
1513 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname,
1514 ctx, num_streams, streams);
1517 ret = alloc_get_client_smb_fname(handle,
1518 talloc_tos(),
1519 smb_fname,
1520 &client_fname);
1521 if (ret != 0) {
1522 status = NT_STATUS_NO_MEMORY;
1523 goto err;
1527 * This only works on files, so we don't have to worry about
1528 * our fake directory stat'ing here. But what does this
1529 * function do, exactly? Does it need extra modifications for
1530 * the Avid stuff?
1532 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_fname,
1533 ctx, num_streams, streams);
1534 err:
1535 TALLOC_FREE(client_fname);
1536 return status;
1540 * Ignoring get_real_filename function because the default doesn't do
1541 * anything.
1544 static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
1545 const struct smb_filename *smb_fname,
1546 uint32_t security_info,
1547 TALLOC_CTX *mem_ctx,
1548 struct security_descriptor **ppdesc)
1550 NTSTATUS status;
1551 char *client_path = NULL;
1552 struct smb_filename *client_smb_fname = NULL;
1553 int ret;
1555 DEBUG(10, ("Entering um_get_nt_acl\n"));
1557 if (!is_in_media_files(smb_fname->base_name)) {
1558 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
1559 security_info,
1560 mem_ctx, ppdesc);
1563 ret = alloc_get_client_path(handle, talloc_tos(),
1564 smb_fname->base_name, &client_path);
1565 if (ret != 0) {
1566 status = map_nt_error_from_unix(errno);
1567 goto err;
1570 client_smb_fname = synthetic_smb_fname(talloc_tos(),
1571 client_path,
1572 NULL,
1573 NULL,
1574 smb_fname->flags);
1575 if (client_smb_fname == NULL) {
1576 TALLOC_FREE(client_path);
1577 return NT_STATUS_NO_MEMORY;
1580 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
1581 security_info,
1582 mem_ctx, ppdesc);
1583 err:
1584 TALLOC_FREE(client_smb_fname);
1585 TALLOC_FREE(client_path);
1586 return status;
1589 static int um_chmod_acl(vfs_handle_struct *handle,
1590 const struct smb_filename *smb_fname,
1591 mode_t mode)
1593 int status;
1594 int saved_errno;
1595 struct smb_filename *client_fname = NULL;
1597 DEBUG(10, ("Entering um_chmod_acl\n"));
1599 if (!is_in_media_files(smb_fname->base_name)) {
1600 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
1603 status = alloc_get_client_smb_fname(handle,
1604 talloc_tos(),
1605 smb_fname,
1606 &client_fname);
1607 if (status != 0) {
1608 goto err;
1610 status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_fname, mode);
1612 err:
1613 saved_errno = errno;
1614 TALLOC_FREE(client_fname);
1615 errno = saved_errno;
1616 return status;
1619 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1620 const struct smb_filename *smb_fname,
1621 SMB_ACL_TYPE_T type,
1622 TALLOC_CTX *mem_ctx)
1624 SMB_ACL_T ret;
1625 int saved_errno = 0;
1626 struct smb_filename *client_fname = NULL;
1627 int status;
1629 DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1631 if (!is_in_media_files(smb_fname->base_name)) {
1632 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
1633 type, mem_ctx);
1636 status = alloc_get_client_smb_fname(handle,
1637 talloc_tos(),
1638 smb_fname,
1639 &client_fname);
1640 if (status != 0) {
1641 ret = (SMB_ACL_T)NULL;
1642 goto err;
1645 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_fname,
1646 type, mem_ctx);
1648 err:
1649 if (ret == (SMB_ACL_T)NULL) {
1650 saved_errno = errno;
1652 TALLOC_FREE(client_fname);
1653 if (saved_errno != 0) {
1654 errno = saved_errno;
1656 return ret;
1659 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1660 const struct smb_filename *smb_fname,
1661 SMB_ACL_TYPE_T acltype,
1662 SMB_ACL_T theacl)
1664 int status;
1665 int saved_errno = 0;
1666 struct smb_filename *client_fname = NULL;
1668 DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1670 if (!is_in_media_files(smb_fname->base_name)) {
1671 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
1672 acltype, theacl);
1675 status = alloc_get_client_smb_fname(handle,
1676 talloc_tos(),
1677 smb_fname,
1678 &client_fname);
1679 if (status != 0) {
1680 goto err;
1683 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_fname,
1684 acltype, theacl);
1686 err:
1687 if (status == -1) {
1688 saved_errno = errno;
1690 TALLOC_FREE(client_fname);
1691 if (saved_errno != 0) {
1692 errno = saved_errno;
1694 return status;
1697 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1698 const struct smb_filename *smb_fname)
1700 int status;
1701 int saved_errno = 0;
1702 struct smb_filename *client_fname = NULL;
1704 DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1706 if (!is_in_media_files(smb_fname->base_name)) {
1707 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
1708 smb_fname);
1711 status = alloc_get_client_smb_fname(handle,
1712 talloc_tos(),
1713 smb_fname,
1714 &client_fname);
1715 if (status != 0) {
1716 goto err;
1719 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_fname);
1721 err:
1722 if (status == -1) {
1723 saved_errno = errno;
1725 TALLOC_FREE(client_fname);
1726 if (saved_errno != 0) {
1727 errno = saved_errno;
1729 return status;
1732 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1733 const struct smb_filename *smb_fname,
1734 const char *name,
1735 void *value,
1736 size_t size)
1738 ssize_t ret;
1739 struct smb_filename *client_fname = NULL;
1740 int status;
1742 DEBUG(10, ("Entering um_getxattr\n"));
1743 if (!is_in_media_files(smb_fname->base_name)) {
1744 return SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
1745 name, value, size);
1748 status = alloc_get_client_smb_fname(handle,
1749 talloc_tos(),
1750 smb_fname,
1751 &client_fname);
1752 if (status != 0) {
1753 ret = -1;
1754 goto err;
1757 ret = SMB_VFS_NEXT_GETXATTR(handle, client_fname, name, value, size);
1758 err:
1759 TALLOC_FREE(client_fname);
1760 return ret;
1763 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1764 const struct smb_filename *smb_fname,
1765 char *list,
1766 size_t size)
1768 ssize_t ret;
1769 struct smb_filename *client_fname = NULL;
1770 int status;
1772 DEBUG(10, ("Entering um_listxattr\n"));
1774 if (!is_in_media_files(smb_fname->base_name)) {
1775 return SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
1778 status = alloc_get_client_smb_fname(handle,
1779 talloc_tos(),
1780 smb_fname,
1781 &client_fname);
1782 if (status != 0) {
1783 ret = -1;
1784 goto err;
1787 ret = SMB_VFS_NEXT_LISTXATTR(handle, client_fname, list, size);
1789 err:
1790 TALLOC_FREE(client_fname);
1791 return ret;
1794 static int um_removexattr(struct vfs_handle_struct *handle,
1795 const struct smb_filename *smb_fname,
1796 const char *name)
1798 int status;
1799 struct smb_filename *client_fname = NULL;
1801 DEBUG(10, ("Entering um_removexattr\n"));
1803 if (!is_in_media_files(smb_fname->base_name)) {
1804 return SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
1807 status = alloc_get_client_smb_fname(handle,
1808 talloc_tos(),
1809 smb_fname,
1810 &client_fname);
1811 if (status != 0) {
1812 goto err;
1815 status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_fname, name);
1817 err:
1818 TALLOC_FREE(client_fname);
1819 return status;
1822 static int um_setxattr(struct vfs_handle_struct *handle,
1823 const struct smb_filename *smb_fname,
1824 const char *name,
1825 const void *value,
1826 size_t size,
1827 int flags)
1829 int status;
1830 struct smb_filename *client_fname = NULL;
1832 DEBUG(10, ("Entering um_setxattr\n"));
1834 if (!is_in_media_files(smb_fname->base_name)) {
1835 return SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
1836 size, flags);
1839 status = alloc_get_client_smb_fname(handle,
1840 talloc_tos(),
1841 smb_fname,
1842 &client_fname);
1843 if (status != 0) {
1844 goto err;
1847 status = SMB_VFS_NEXT_SETXATTR(handle, client_fname, name, value,
1848 size, flags);
1850 err:
1851 TALLOC_FREE(client_fname);
1852 return status;
1855 static int um_connect(vfs_handle_struct *handle,
1856 const char *service,
1857 const char *user)
1859 int rc;
1860 struct um_config_data *config;
1861 int enumval;
1863 rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1864 if (rc != 0) {
1865 return rc;
1868 config = talloc_zero(handle->conn, struct um_config_data);
1869 if (!config) {
1870 DEBUG(1, ("talloc_zero() failed\n"));
1871 errno = ENOMEM;
1872 return -1;
1875 enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1876 "clientid", um_clientid, UM_CLIENTID_NAME);
1877 if (enumval == -1) {
1878 DEBUG(1, ("value for %s: type unknown\n",
1879 UM_PARAM_TYPE_NAME));
1880 return -1;
1882 config->clientid = (enum um_clientid)enumval;
1884 SMB_VFS_HANDLE_SET_DATA(handle, config,
1885 NULL, struct um_config_data,
1886 return -1);
1888 return 0;
1891 /* VFS operations structure */
1893 static struct vfs_fn_pointers vfs_um_fns = {
1894 .connect_fn = um_connect,
1896 /* Disk operations */
1898 .statvfs_fn = um_statvfs,
1900 /* Directory operations */
1902 .opendir_fn = um_opendir,
1903 .fdopendir_fn = um_fdopendir,
1904 .readdir_fn = um_readdir,
1905 .seekdir_fn = um_seekdir,
1906 .telldir_fn = um_telldir,
1907 .rewind_dir_fn = um_rewinddir,
1908 .mkdir_fn = um_mkdir,
1909 .rmdir_fn = um_rmdir,
1910 .closedir_fn = um_closedir,
1911 .init_search_op_fn = um_init_search_op,
1913 /* File operations */
1915 .open_fn = um_open,
1916 .create_file_fn = um_create_file,
1917 .rename_fn = um_rename,
1918 .stat_fn = um_stat,
1919 .lstat_fn = um_lstat,
1920 .fstat_fn = um_fstat,
1921 .unlink_fn = um_unlink,
1922 .chmod_fn = um_chmod,
1923 .chown_fn = um_chown,
1924 .lchown_fn = um_lchown,
1925 .chdir_fn = um_chdir,
1926 .ntimes_fn = um_ntimes,
1927 .symlink_fn = um_symlink,
1928 .readlink_fn = um_readlink,
1929 .link_fn = um_link,
1930 .mknod_fn = um_mknod,
1931 .realpath_fn = um_realpath,
1932 .chflags_fn = um_chflags,
1933 .streaminfo_fn = um_streaminfo,
1935 /* NT ACL operations. */
1937 .get_nt_acl_fn = um_get_nt_acl,
1939 /* POSIX ACL operations. */
1941 .chmod_acl_fn = um_chmod_acl,
1943 .sys_acl_get_file_fn = um_sys_acl_get_file,
1944 .sys_acl_set_file_fn = um_sys_acl_set_file,
1945 .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1947 /* EA operations. */
1948 .getxattr_fn = um_getxattr,
1949 .listxattr_fn = um_listxattr,
1950 .removexattr_fn = um_removexattr,
1951 .setxattr_fn = um_setxattr,
1954 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *);
1955 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1957 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1958 "unityed_media", &vfs_um_fns);
1959 if (!NT_STATUS_IS_OK(ret)) {
1960 return ret;
1963 vfs_um_debug_level = debug_add_class("unityed_media");
1965 if (vfs_um_debug_level == -1) {
1966 vfs_um_debug_level = DBGC_VFS;
1967 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1968 "debugging class.\n"));
1971 return ret;