s3: VFS: Change SMB_VFS_MKNOD to use const struct smb_filename * instead of const...
[Samba.git] / source3 / modules / vfs_unityed_media.c
blobcda6ad635a8ac8f5a5810ea20246b959126bfb79
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 char *path,
526 struct vfs_statvfs_struct *statbuf)
528 int status;
529 char *clientPath = NULL;
531 DEBUG(10, ("Entering with path '%s'\n", path));
533 if (!is_in_media_files(path)) {
534 return SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
537 status = alloc_get_client_path(handle, talloc_tos(),
538 path, &clientPath);
539 if (status != 0) {
540 goto err;
543 status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
544 err:
545 TALLOC_FREE(clientPath);
546 DEBUG(10, ("Leaving with path '%s'\n", path));
547 return status;
550 /* Success: return a um_dirinfo_struct cast as a DIR
551 * Failure: set errno, return NULL
553 static DIR *um_opendir(vfs_handle_struct *handle,
554 const struct smb_filename *smb_fname,
555 const char *mask,
556 uint32_t attr)
558 struct um_dirinfo_struct *dirInfo;
560 DEBUG(10, ("Entering with fname '%s'\n", smb_fname->base_name));
562 if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo)) {
563 goto err;
566 if (!dirInfo->isInMediaFiles) {
567 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
568 handle, smb_fname, mask, attr);
569 } else {
570 struct smb_filename *client_smb_fname =
571 synthetic_smb_fname(talloc_tos(),
572 dirInfo->clientPath,
573 NULL,
574 NULL,
575 smb_fname->flags);
576 if (client_smb_fname == NULL) {
577 goto err;
580 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
581 handle, client_smb_fname, mask, attr);
583 TALLOC_FREE(client_smb_fname);
586 if (dirInfo->dirstream == NULL) {
587 goto err;
590 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
591 "dirInfo->clientPath '%s'\n",
592 dirInfo->dirpath,
593 dirInfo->clientPath));
594 return (DIR*)dirInfo;
596 err:
597 DEBUG(1, ("Failing with fname '%s'\n", smb_fname->base_name));
598 TALLOC_FREE(dirInfo);
599 return NULL;
602 static DIR *um_fdopendir(vfs_handle_struct *handle,
603 files_struct *fsp,
604 const char *mask,
605 uint32_t attr)
607 struct um_dirinfo_struct *dirInfo = NULL;
608 DIR *dirstream;
610 DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
611 fsp->fsp_name->base_name));
613 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
614 if (!dirstream) {
615 goto err;
618 if (alloc_set_client_dirinfo(handle,
619 fsp->fsp_name->base_name,
620 &dirInfo)) {
621 goto err;
624 dirInfo->dirstream = dirstream;
626 if (!dirInfo->isInMediaFiles) {
628 * FIXME: this is the original code, something must be
629 * missing here, but what? -slow
631 goto out;
634 out:
635 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
636 "dirInfo->clientPath '%s', "
637 "fsp->fsp_name->st.st_ex_mtime %s",
638 dirInfo->dirpath,
639 dirInfo->clientPath,
640 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
641 return (DIR *) dirInfo;
643 err:
644 DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
645 fsp->fsp_name->base_name));
646 TALLOC_FREE(dirInfo);
647 return NULL;
651 * skip own suffixed directory
652 * replace own suffixed directory with non suffixed.
654 * Success: return dirent
655 * End of data: return NULL
656 * Failure: set errno, return NULL
658 static struct dirent *um_readdir(vfs_handle_struct *handle,
659 DIR *dirp,
660 SMB_STRUCT_STAT *sbuf)
662 um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
663 struct dirent *d = NULL;
664 int skip;
666 DEBUG(10, ("dirInfo->dirpath '%s', "
667 "dirInfo->clientPath '%s', "
668 "dirInfo->isInMediaFiles '%s', "
669 "dirInfo->clientSubDirname '%s'\n",
670 dirInfo->dirpath,
671 dirInfo->clientPath,
672 dirInfo->isInMediaFiles ? "true" : "false",
673 dirInfo->clientSubDirname));
675 if (!dirInfo->isInMediaFiles) {
676 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
679 do {
680 const char* dname;
681 bool isAppleDouble;
682 char *digits;
683 size_t digits_len;
684 uintmax_t number;
686 skip = false;
687 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
689 if (d == NULL) {
690 break;
693 /* ignore apple double prefix for logic below */
694 if (is_apple_double(d->d_name)) {
695 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
696 isAppleDouble = true;
697 } else {
698 dname = d->d_name;
699 isAppleDouble = false;
702 DEBUG(10, ("dname = '%s'\n", dname));
704 (void)get_digit_group(dname, &number);
705 digits = talloc_asprintf(talloc_tos(), "%ju", number);
706 if (digits == NULL) {
707 DEBUG(1, ("out of memory"));
708 goto err;
710 digits_len = strlen(digits);
712 if (alloc_set_client_dirinfo_path(handle,
713 dirInfo,
714 &((dirInfo)->clientSubDirname),
715 digits)) {
716 goto err;
720 * If set to "true", vfs shows digits-only
721 * non-suffixed subdirectories. Normally, such
722 * subdirectories can exists only in non-media
723 * directories, so we set it to "false". Otherwise,
724 * if we have such subdirectories (probably created
725 * over not "unityed" connection), it can be little
726 * bit confusing.
728 if (strequal(dname, digits)) {
729 skip = false;
730 } else if (strequal(dname, dirInfo->clientSubDirname)) {
732 * Remove suffix of this client's suffixed
733 * subdirectories
735 if (isAppleDouble) {
736 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
737 } else {
738 d->d_name[digits_len] = '\0';
740 } else if (strnequal(digits, dname, digits_len)) {
742 * Set to false to see another clients subdirectories
744 skip = false;
746 } while (skip);
748 DEBUG(10, ("Leaving um_readdir\n"));
749 return d;
750 err:
751 TALLOC_FREE(dirInfo);
752 return NULL;
755 static void um_seekdir(vfs_handle_struct *handle,
756 DIR *dirp,
757 long offset)
759 DEBUG(10, ("Entering and leaving um_seekdir\n"));
760 SMB_VFS_NEXT_SEEKDIR(handle,
761 ((um_dirinfo_struct*)dirp)->dirstream, offset);
764 static long um_telldir(vfs_handle_struct *handle,
765 DIR *dirp)
767 DEBUG(10, ("Entering and leaving um_telldir\n"));
768 return SMB_VFS_NEXT_TELLDIR(handle,
769 ((um_dirinfo_struct*)dirp)->dirstream);
772 static void um_rewinddir(vfs_handle_struct *handle,
773 DIR *dirp)
775 DEBUG(10, ("Entering and leaving um_rewinddir\n"));
776 SMB_VFS_NEXT_REWINDDIR(handle,
777 ((um_dirinfo_struct*)dirp)->dirstream);
780 static int um_mkdir(vfs_handle_struct *handle,
781 const struct smb_filename *smb_fname,
782 mode_t mode)
784 int status;
785 const char *path = smb_fname->base_name;
786 struct smb_filename *client_fname = NULL;
788 DEBUG(10, ("Entering with path '%s'\n", path));
790 if (!is_in_media_files(path) || !is_in_media_dir(path)) {
791 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
794 status = alloc_get_client_smb_fname(handle,
795 talloc_tos(),
796 smb_fname,
797 &client_fname);
798 if (status != 0) {
799 goto err;
802 status = SMB_VFS_NEXT_MKDIR(handle, client_fname, mode);
803 err:
804 TALLOC_FREE(client_fname);
805 DEBUG(10, ("Leaving with path '%s'\n", path));
806 return status;
809 static int um_rmdir(vfs_handle_struct *handle,
810 const struct smb_filename *smb_fname)
812 int status;
813 const char *path = smb_fname->base_name;
814 struct smb_filename *client_fname = NULL;
816 DEBUG(10, ("Entering with path '%s'\n", path));
818 if (!is_in_media_files(path)) {
819 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
822 status = alloc_get_client_smb_fname(handle,
823 talloc_tos(),
824 smb_fname,
825 &client_fname);
826 if (status != 0) {
827 goto err;
830 status = SMB_VFS_NEXT_RMDIR(handle, client_fname);
831 err:
832 TALLOC_FREE(client_fname);
833 DEBUG(10, ("Leaving with path '%s'\n", path));
834 return status;
837 static int um_closedir(vfs_handle_struct *handle,
838 DIR *dirp)
840 DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
842 TALLOC_FREE(dirp);
844 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
847 static void um_init_search_op(vfs_handle_struct *handle,
848 DIR *dirp)
850 DEBUG(10, ("Entering and leaving um_init_search_op\n"));
852 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
853 ((um_dirinfo_struct*)dirp)->dirstream);
856 static int um_open(vfs_handle_struct *handle,
857 struct smb_filename *smb_fname,
858 files_struct *fsp,
859 int flags,
860 mode_t mode)
862 int ret;
863 struct smb_filename *client_fname = NULL;
865 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
866 smb_fname->base_name));
868 if (!is_in_media_files(smb_fname->base_name)) {
869 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
872 if (alloc_get_client_smb_fname(handle, talloc_tos(),
873 smb_fname,
874 &client_fname)) {
875 ret = -1;
876 goto err;
880 * FIXME:
881 * What about fsp->fsp_name? We also have to get correct stat
882 * info into fsp and smb_fname for DB files, don't we?
885 DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
886 "smb_fname->st.st_ex_mtime %s"
887 "fsp->fsp_name->st.st_ex_mtime %s",
888 smb_fname->base_name,
889 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
890 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
892 ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
893 err:
894 TALLOC_FREE(client_fname);
895 DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
896 smb_fname->base_name));
897 return ret;
900 static NTSTATUS um_create_file(vfs_handle_struct *handle,
901 struct smb_request *req,
902 uint16_t root_dir_fid,
903 struct smb_filename *smb_fname,
904 uint32_t access_mask,
905 uint32_t share_access,
906 uint32_t create_disposition,
907 uint32_t create_options,
908 uint32_t file_attributes,
909 uint32_t oplock_request,
910 struct smb2_lease *lease,
911 uint64_t allocation_size,
912 uint32_t private_flags,
913 struct security_descriptor *sd,
914 struct ea_list *ea_list,
915 files_struct **result_fsp,
916 int *pinfo,
917 const struct smb2_create_blobs *in_context_blobs,
918 struct smb2_create_blobs *out_context_blobs)
920 NTSTATUS status;
921 struct smb_filename *client_fname = NULL;
923 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
924 smb_fname->base_name));
926 if (!is_in_media_files(smb_fname->base_name)) {
927 return SMB_VFS_NEXT_CREATE_FILE(
928 handle,
929 req,
930 root_dir_fid,
931 smb_fname,
932 access_mask,
933 share_access,
934 create_disposition,
935 create_options,
936 file_attributes,
937 oplock_request,
938 lease,
939 allocation_size,
940 private_flags,
942 ea_list,
943 result_fsp,
944 pinfo,
945 in_context_blobs,
946 out_context_blobs);
949 if (alloc_get_client_smb_fname(handle, talloc_tos(),
950 smb_fname,
951 &client_fname)) {
952 status = map_nt_error_from_unix(errno);
953 goto err;
957 * FIXME:
958 * This only creates files, so we don't have to worry about
959 * our fake directory stat'ing here. But we still need to
960 * route stat calls for DB files properly, right?
962 status = SMB_VFS_NEXT_CREATE_FILE(
963 handle,
964 req,
965 root_dir_fid,
966 client_fname,
967 access_mask,
968 share_access,
969 create_disposition,
970 create_options,
971 file_attributes,
972 oplock_request,
973 lease,
974 allocation_size,
975 private_flags,
977 ea_list,
978 result_fsp,
979 pinfo,
980 in_context_blobs,
981 out_context_blobs);
982 err:
983 TALLOC_FREE(client_fname);
984 DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
985 "smb_fname->st.st_ex_mtime %s"
986 " fsp->fsp_name->st.st_ex_mtime %s",
987 smb_fname->base_name,
988 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
989 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
990 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
991 "No fsp time\n"));
992 return status;
995 static int um_rename(vfs_handle_struct *handle,
996 const struct smb_filename *smb_fname_src,
997 const struct smb_filename *smb_fname_dst)
999 int status;
1000 struct smb_filename *src_client_fname = NULL;
1001 struct smb_filename *dst_client_fname = NULL;
1003 DEBUG(10, ("Entering with "
1004 "smb_fname_src->base_name '%s', "
1005 "smb_fname_dst->base_name '%s'\n",
1006 smb_fname_src->base_name,
1007 smb_fname_dst->base_name));
1009 if (!is_in_media_files(smb_fname_src->base_name)
1011 !is_in_media_files(smb_fname_dst->base_name)) {
1012 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1013 smb_fname_dst);
1016 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1017 smb_fname_src,
1018 &src_client_fname);
1019 if (status != 0) {
1020 goto err;
1023 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1024 smb_fname_dst,
1025 &dst_client_fname);
1027 if (status != 0) {
1028 goto err;
1031 status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
1032 dst_client_fname);
1033 err:
1034 TALLOC_FREE(dst_client_fname);
1035 TALLOC_FREE(src_client_fname);
1036 DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
1037 " smb_fname_dst->base_name '%s'\n",
1038 smb_fname_src->base_name,
1039 smb_fname_dst->base_name));
1040 return status;
1044 * Success: return 0
1045 * Failure: set errno, return -1
1047 static int um_stat(vfs_handle_struct *handle,
1048 struct smb_filename *smb_fname)
1050 int status = 0;
1051 struct smb_filename *client_fname = NULL;
1053 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1054 smb_fname->base_name));
1056 if (!is_in_media_files(smb_fname->base_name)) {
1057 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1060 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1061 smb_fname,
1062 &client_fname);
1063 if (status != 0) {
1064 goto err;
1066 DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1067 client_fname->base_name));
1069 status = SMB_VFS_NEXT_STAT(handle, client_fname);
1070 if (status != 0) {
1071 goto err;
1075 * Unlike functions with const smb_filename, we have to modify
1076 * smb_fname itself to pass our info back up.
1078 DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1079 smb_fname->base_name, client_fname->base_name));
1080 smb_fname->st = client_fname->st;
1082 err:
1083 TALLOC_FREE(client_fname);
1084 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1085 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1086 return status;
1089 static int um_lstat(vfs_handle_struct *handle,
1090 struct smb_filename *smb_fname)
1092 int status = 0;
1093 struct smb_filename *client_fname = NULL;
1095 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1096 smb_fname->base_name));
1098 if (!is_in_media_files(smb_fname->base_name)) {
1099 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1102 client_fname = NULL;
1104 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1105 smb_fname,
1106 &client_fname);
1107 if (status != 0) {
1108 goto err;
1110 status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1111 if (status != 0) {
1112 goto err;
1115 smb_fname->st = client_fname->st;
1117 err:
1118 TALLOC_FREE(client_fname);
1119 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1120 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1121 return status;
1124 static int um_fstat(vfs_handle_struct *handle,
1125 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1127 int status = 0;
1129 DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1130 "'%s'\n", fsp_str_dbg(fsp)));
1132 status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1133 if (status != 0) {
1134 goto out;
1137 if ((fsp->fsp_name == NULL) ||
1138 !is_in_media_files(fsp->fsp_name->base_name)) {
1139 goto out;
1142 status = um_stat(handle, fsp->fsp_name);
1143 if (status != 0) {
1144 goto out;
1147 *sbuf = fsp->fsp_name->st;
1149 out:
1150 DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1151 fsp->fsp_name != NULL ?
1152 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1153 return status;
1156 static int um_unlink(vfs_handle_struct *handle,
1157 const struct smb_filename *smb_fname)
1159 int status;
1160 struct smb_filename *client_fname = NULL;
1162 DEBUG(10, ("Entering um_unlink\n"));
1164 if (!is_in_media_files(smb_fname->base_name)) {
1165 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1168 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1169 smb_fname,
1170 &client_fname);
1171 if (status != 0) {
1172 goto err;
1175 status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
1177 err:
1178 TALLOC_FREE(client_fname);
1179 return status;
1182 static int um_chmod(vfs_handle_struct *handle,
1183 const struct smb_filename *smb_fname,
1184 mode_t mode)
1186 int status;
1187 struct smb_filename *client_fname = NULL;
1189 DEBUG(10, ("Entering um_chmod\n"));
1191 if (!is_in_media_files(smb_fname->base_name)) {
1192 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1195 status = alloc_get_client_smb_fname(handle,
1196 talloc_tos(),
1197 smb_fname,
1198 &client_fname);
1199 if (status != 0) {
1200 goto err;
1203 status = SMB_VFS_NEXT_CHMOD(handle, client_fname, mode);
1205 err:
1206 TALLOC_FREE(client_fname);
1207 return status;
1210 static int um_chown(vfs_handle_struct *handle,
1211 const struct smb_filename *smb_fname,
1212 uid_t uid,
1213 gid_t gid)
1215 int status;
1216 struct smb_filename *client_fname = NULL;
1218 DEBUG(10, ("Entering um_chown\n"));
1220 if (!is_in_media_files(smb_fname->base_name)) {
1221 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1224 status = alloc_get_client_smb_fname(handle,
1225 talloc_tos(),
1226 smb_fname,
1227 &client_fname);
1228 if (status != 0) {
1229 goto err;
1232 status = SMB_VFS_NEXT_CHOWN(handle, client_fname, uid, gid);
1234 err:
1235 TALLOC_FREE(client_fname);
1236 return status;
1239 static int um_lchown(vfs_handle_struct *handle,
1240 const struct smb_filename *smb_fname,
1241 uid_t uid,
1242 gid_t gid)
1244 int status;
1245 struct smb_filename *client_fname = NULL;
1247 DEBUG(10, ("Entering um_lchown\n"));
1248 if (!is_in_media_files(smb_fname->base_name)) {
1249 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1252 status = alloc_get_client_smb_fname(handle,
1253 talloc_tos(),
1254 smb_fname,
1255 &client_fname);
1256 if (status != 0) {
1257 goto err;
1260 status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1262 err:
1263 TALLOC_FREE(client_fname);
1264 return status;
1267 static int um_chdir(vfs_handle_struct *handle,
1268 const char *path)
1270 int status;
1271 char *client_path = NULL;
1273 DEBUG(10, ("Entering um_chdir\n"));
1275 if (!is_in_media_files(path)) {
1276 return SMB_VFS_NEXT_CHDIR(handle, path);
1279 status = alloc_get_client_path(handle, talloc_tos(),
1280 path, &client_path);
1281 if (status != 0) {
1282 goto err;
1285 status = SMB_VFS_NEXT_CHDIR(handle, client_path);
1287 err:
1288 TALLOC_FREE(client_path);
1289 return status;
1292 static int um_ntimes(vfs_handle_struct *handle,
1293 const struct smb_filename *smb_fname,
1294 struct smb_file_time *ft)
1296 int status;
1297 struct smb_filename *client_fname = NULL;
1299 DEBUG(10, ("Entering um_ntimes\n"));
1301 if (!is_in_media_files(smb_fname->base_name)) {
1302 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1305 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1306 smb_fname, &client_fname);
1307 if (status != 0) {
1308 goto err;
1311 status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
1313 err:
1314 TALLOC_FREE(client_fname);
1315 return status;
1318 static int um_symlink(vfs_handle_struct *handle,
1319 const char *oldpath,
1320 const char *newpath)
1322 int status;
1323 char *old_client_path = NULL;
1324 char *new_client_path = NULL;
1326 DEBUG(10, ("Entering um_symlink\n"));
1328 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1329 return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1332 status = alloc_get_client_path(handle, talloc_tos(),
1333 oldpath, &old_client_path);
1334 if (status != 0) {
1335 goto err;
1338 status = alloc_get_client_path(handle, talloc_tos(),
1339 newpath, &new_client_path);
1340 if (status != 0) {
1341 goto err;
1344 status = SMB_VFS_NEXT_SYMLINK(handle,
1345 old_client_path,
1346 new_client_path);
1348 err:
1349 TALLOC_FREE(new_client_path);
1350 TALLOC_FREE(old_client_path);
1351 return status;
1354 static int um_readlink(vfs_handle_struct *handle,
1355 const char *path,
1356 char *buf,
1357 size_t bufsiz)
1359 int status;
1360 char *client_path = NULL;
1362 DEBUG(10, ("Entering um_readlink\n"));
1364 if (!is_in_media_files(path)) {
1365 return SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1368 status = alloc_get_client_path(handle, talloc_tos(),
1369 path, &client_path);
1370 if (status != 0) {
1371 goto err;
1374 status = SMB_VFS_NEXT_READLINK(handle, client_path, buf, bufsiz);
1376 err:
1377 TALLOC_FREE(client_path);
1378 return status;
1381 static int um_link(vfs_handle_struct *handle,
1382 const char *oldpath,
1383 const char *newpath)
1385 int status;
1386 char *old_client_path = NULL;
1387 char *new_client_path = NULL;
1389 DEBUG(10, ("Entering um_link\n"));
1390 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1391 return SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1394 status = alloc_get_client_path(handle, talloc_tos(),
1395 oldpath, &old_client_path);
1396 if (status != 0) {
1397 goto err;
1400 status = alloc_get_client_path(handle, talloc_tos(),
1401 newpath, &new_client_path);
1402 if (status != 0) {
1403 goto err;
1406 status = SMB_VFS_NEXT_LINK(handle, old_client_path, new_client_path);
1408 err:
1409 TALLOC_FREE(new_client_path);
1410 TALLOC_FREE(old_client_path);
1411 return status;
1414 static int um_mknod(vfs_handle_struct *handle,
1415 const struct smb_filename *smb_fname,
1416 mode_t mode,
1417 SMB_DEV_T dev)
1419 int status;
1420 struct smb_filename *client_fname = NULL;
1422 DEBUG(10, ("Entering um_mknod\n"));
1423 if (!is_in_media_files(smb_fname->base_name)) {
1424 return SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
1427 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1428 smb_fname, &client_fname);
1429 if (status != 0) {
1430 goto err;
1433 status = SMB_VFS_NEXT_MKNOD(handle, client_fname, mode, dev);
1435 err:
1436 TALLOC_FREE(client_fname);
1437 return status;
1440 static char *um_realpath(vfs_handle_struct *handle,
1441 const char *path)
1443 char *buf = NULL;
1444 char *client_path = NULL;
1445 int status;
1447 DEBUG(10, ("Entering um_realpath\n"));
1449 if (!is_in_media_files(path)) {
1450 return SMB_VFS_NEXT_REALPATH(handle, path);
1453 status = alloc_get_client_path(handle, talloc_tos(),
1454 path, &client_path);
1455 if (status != 0) {
1456 goto err;
1459 buf = SMB_VFS_NEXT_REALPATH(handle, client_path);
1461 err:
1462 TALLOC_FREE(client_path);
1463 return buf;
1466 static int um_chflags(vfs_handle_struct *handle,
1467 const char *path,
1468 unsigned int flags)
1470 int status;
1471 char *client_path = NULL;
1473 DEBUG(10, ("Entering um_chflags\n"));
1475 if (!is_in_media_files(path)) {
1476 return SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1479 status = alloc_get_client_path(handle, talloc_tos(),
1480 path, &client_path);
1481 if (status != 0) {
1482 goto err;
1485 status = SMB_VFS_NEXT_CHFLAGS(handle, client_path, flags);
1486 err:
1487 TALLOC_FREE(client_path);
1488 return status;
1491 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1492 struct files_struct *fsp,
1493 const struct smb_filename *smb_fname,
1494 TALLOC_CTX *ctx,
1495 unsigned int *num_streams,
1496 struct stream_struct **streams)
1498 NTSTATUS status;
1499 int ret;
1500 struct smb_filename *client_fname = NULL;
1502 DEBUG(10, ("Entering um_streaminfo\n"));
1504 if (!is_in_media_files(smb_fname->base_name)) {
1505 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname,
1506 ctx, num_streams, streams);
1509 ret = alloc_get_client_smb_fname(handle,
1510 talloc_tos(),
1511 smb_fname,
1512 &client_fname);
1513 if (ret != 0) {
1514 status = NT_STATUS_NO_MEMORY;
1515 goto err;
1519 * This only works on files, so we don't have to worry about
1520 * our fake directory stat'ing here. But what does this
1521 * function do, exactly? Does it need extra modifications for
1522 * the Avid stuff?
1524 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_fname,
1525 ctx, num_streams, streams);
1526 err:
1527 TALLOC_FREE(client_fname);
1528 return status;
1532 * Ignoring get_real_filename function because the default doesn't do
1533 * anything.
1536 static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
1537 const struct smb_filename *smb_fname,
1538 uint32_t security_info,
1539 TALLOC_CTX *mem_ctx,
1540 struct security_descriptor **ppdesc)
1542 NTSTATUS status;
1543 char *client_path = NULL;
1544 struct smb_filename *client_smb_fname = NULL;
1545 int ret;
1547 DEBUG(10, ("Entering um_get_nt_acl\n"));
1549 if (!is_in_media_files(smb_fname->base_name)) {
1550 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
1551 security_info,
1552 mem_ctx, ppdesc);
1555 ret = alloc_get_client_path(handle, talloc_tos(),
1556 smb_fname->base_name, &client_path);
1557 if (ret != 0) {
1558 status = map_nt_error_from_unix(errno);
1559 goto err;
1562 client_smb_fname = synthetic_smb_fname(talloc_tos(),
1563 client_path,
1564 NULL,
1565 NULL,
1566 smb_fname->flags);
1567 if (client_smb_fname == NULL) {
1568 TALLOC_FREE(client_path);
1569 return NT_STATUS_NO_MEMORY;
1572 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
1573 security_info,
1574 mem_ctx, ppdesc);
1575 err:
1576 TALLOC_FREE(client_smb_fname);
1577 TALLOC_FREE(client_path);
1578 return status;
1581 static int um_chmod_acl(vfs_handle_struct *handle,
1582 const struct smb_filename *smb_fname,
1583 mode_t mode)
1585 int status;
1586 int saved_errno;
1587 struct smb_filename *client_fname = NULL;
1589 DEBUG(10, ("Entering um_chmod_acl\n"));
1591 if (!is_in_media_files(smb_fname->base_name)) {
1592 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
1595 status = alloc_get_client_smb_fname(handle,
1596 talloc_tos(),
1597 smb_fname,
1598 &client_fname);
1599 if (status != 0) {
1600 goto err;
1602 status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_fname, mode);
1604 err:
1605 saved_errno = errno;
1606 TALLOC_FREE(client_fname);
1607 errno = saved_errno;
1608 return status;
1611 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1612 const struct smb_filename *smb_fname,
1613 SMB_ACL_TYPE_T type,
1614 TALLOC_CTX *mem_ctx)
1616 SMB_ACL_T ret;
1617 int saved_errno = 0;
1618 struct smb_filename *client_fname = NULL;
1619 int status;
1621 DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1623 if (!is_in_media_files(smb_fname->base_name)) {
1624 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
1625 type, mem_ctx);
1628 status = alloc_get_client_smb_fname(handle,
1629 talloc_tos(),
1630 smb_fname,
1631 &client_fname);
1632 if (status != 0) {
1633 ret = (SMB_ACL_T)NULL;
1634 goto err;
1637 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_fname,
1638 type, mem_ctx);
1640 err:
1641 if (ret == (SMB_ACL_T)NULL) {
1642 saved_errno = errno;
1644 TALLOC_FREE(client_fname);
1645 if (saved_errno != 0) {
1646 errno = saved_errno;
1648 return ret;
1651 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1652 const struct smb_filename *smb_fname,
1653 SMB_ACL_TYPE_T acltype,
1654 SMB_ACL_T theacl)
1656 int status;
1657 int saved_errno = 0;
1658 struct smb_filename *client_fname = NULL;
1660 DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1662 if (!is_in_media_files(smb_fname->base_name)) {
1663 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
1664 acltype, theacl);
1667 status = alloc_get_client_smb_fname(handle,
1668 talloc_tos(),
1669 smb_fname,
1670 &client_fname);
1671 if (status != 0) {
1672 goto err;
1675 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_fname,
1676 acltype, theacl);
1678 err:
1679 if (status == -1) {
1680 saved_errno = errno;
1682 TALLOC_FREE(client_fname);
1683 if (saved_errno != 0) {
1684 errno = saved_errno;
1686 return status;
1689 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1690 const struct smb_filename *smb_fname)
1692 int status;
1693 int saved_errno = 0;
1694 struct smb_filename *client_fname = NULL;
1696 DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1698 if (!is_in_media_files(smb_fname->base_name)) {
1699 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
1700 smb_fname);
1703 status = alloc_get_client_smb_fname(handle,
1704 talloc_tos(),
1705 smb_fname,
1706 &client_fname);
1707 if (status != 0) {
1708 goto err;
1711 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_fname);
1713 err:
1714 if (status == -1) {
1715 saved_errno = errno;
1717 TALLOC_FREE(client_fname);
1718 if (saved_errno != 0) {
1719 errno = saved_errno;
1721 return status;
1724 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1725 const struct smb_filename *smb_fname,
1726 const char *name,
1727 void *value,
1728 size_t size)
1730 ssize_t ret;
1731 struct smb_filename *client_fname = NULL;
1732 int status;
1734 DEBUG(10, ("Entering um_getxattr\n"));
1735 if (!is_in_media_files(smb_fname->base_name)) {
1736 return SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
1737 name, value, size);
1740 status = alloc_get_client_smb_fname(handle,
1741 talloc_tos(),
1742 smb_fname,
1743 &client_fname);
1744 if (status != 0) {
1745 ret = -1;
1746 goto err;
1749 ret = SMB_VFS_NEXT_GETXATTR(handle, client_fname, name, value, size);
1750 err:
1751 TALLOC_FREE(client_fname);
1752 return ret;
1755 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1756 const struct smb_filename *smb_fname,
1757 char *list,
1758 size_t size)
1760 ssize_t ret;
1761 struct smb_filename *client_fname = NULL;
1762 int status;
1764 DEBUG(10, ("Entering um_listxattr\n"));
1766 if (!is_in_media_files(smb_fname->base_name)) {
1767 return SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
1770 status = alloc_get_client_smb_fname(handle,
1771 talloc_tos(),
1772 smb_fname,
1773 &client_fname);
1774 if (status != 0) {
1775 ret = -1;
1776 goto err;
1779 ret = SMB_VFS_NEXT_LISTXATTR(handle, client_fname, list, size);
1781 err:
1782 TALLOC_FREE(client_fname);
1783 return ret;
1786 static int um_removexattr(struct vfs_handle_struct *handle,
1787 const struct smb_filename *smb_fname,
1788 const char *name)
1790 int status;
1791 struct smb_filename *client_fname = NULL;
1793 DEBUG(10, ("Entering um_removexattr\n"));
1795 if (!is_in_media_files(smb_fname->base_name)) {
1796 return SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
1799 status = alloc_get_client_smb_fname(handle,
1800 talloc_tos(),
1801 smb_fname,
1802 &client_fname);
1803 if (status != 0) {
1804 goto err;
1807 status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_fname, name);
1809 err:
1810 TALLOC_FREE(client_fname);
1811 return status;
1814 static int um_setxattr(struct vfs_handle_struct *handle,
1815 const struct smb_filename *smb_fname,
1816 const char *name,
1817 const void *value,
1818 size_t size,
1819 int flags)
1821 int status;
1822 struct smb_filename *client_fname = NULL;
1824 DEBUG(10, ("Entering um_setxattr\n"));
1826 if (!is_in_media_files(smb_fname->base_name)) {
1827 return SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
1828 size, flags);
1831 status = alloc_get_client_smb_fname(handle,
1832 talloc_tos(),
1833 smb_fname,
1834 &client_fname);
1835 if (status != 0) {
1836 goto err;
1839 status = SMB_VFS_NEXT_SETXATTR(handle, client_fname, name, value,
1840 size, flags);
1842 err:
1843 TALLOC_FREE(client_fname);
1844 return status;
1847 static int um_connect(vfs_handle_struct *handle,
1848 const char *service,
1849 const char *user)
1851 int rc;
1852 struct um_config_data *config;
1853 int enumval;
1855 rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1856 if (rc != 0) {
1857 return rc;
1860 config = talloc_zero(handle->conn, struct um_config_data);
1861 if (!config) {
1862 DEBUG(1, ("talloc_zero() failed\n"));
1863 errno = ENOMEM;
1864 return -1;
1867 enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1868 "clientid", um_clientid, UM_CLIENTID_NAME);
1869 if (enumval == -1) {
1870 DEBUG(1, ("value for %s: type unknown\n",
1871 UM_PARAM_TYPE_NAME));
1872 return -1;
1874 config->clientid = (enum um_clientid)enumval;
1876 SMB_VFS_HANDLE_SET_DATA(handle, config,
1877 NULL, struct um_config_data,
1878 return -1);
1880 return 0;
1883 /* VFS operations structure */
1885 static struct vfs_fn_pointers vfs_um_fns = {
1886 .connect_fn = um_connect,
1888 /* Disk operations */
1890 .statvfs_fn = um_statvfs,
1892 /* Directory operations */
1894 .opendir_fn = um_opendir,
1895 .fdopendir_fn = um_fdopendir,
1896 .readdir_fn = um_readdir,
1897 .seekdir_fn = um_seekdir,
1898 .telldir_fn = um_telldir,
1899 .rewind_dir_fn = um_rewinddir,
1900 .mkdir_fn = um_mkdir,
1901 .rmdir_fn = um_rmdir,
1902 .closedir_fn = um_closedir,
1903 .init_search_op_fn = um_init_search_op,
1905 /* File operations */
1907 .open_fn = um_open,
1908 .create_file_fn = um_create_file,
1909 .rename_fn = um_rename,
1910 .stat_fn = um_stat,
1911 .lstat_fn = um_lstat,
1912 .fstat_fn = um_fstat,
1913 .unlink_fn = um_unlink,
1914 .chmod_fn = um_chmod,
1915 .chown_fn = um_chown,
1916 .lchown_fn = um_lchown,
1917 .chdir_fn = um_chdir,
1918 .ntimes_fn = um_ntimes,
1919 .symlink_fn = um_symlink,
1920 .readlink_fn = um_readlink,
1921 .link_fn = um_link,
1922 .mknod_fn = um_mknod,
1923 .realpath_fn = um_realpath,
1924 .chflags_fn = um_chflags,
1925 .streaminfo_fn = um_streaminfo,
1927 /* NT ACL operations. */
1929 .get_nt_acl_fn = um_get_nt_acl,
1931 /* POSIX ACL operations. */
1933 .chmod_acl_fn = um_chmod_acl,
1935 .sys_acl_get_file_fn = um_sys_acl_get_file,
1936 .sys_acl_set_file_fn = um_sys_acl_set_file,
1937 .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1939 /* EA operations. */
1940 .getxattr_fn = um_getxattr,
1941 .listxattr_fn = um_listxattr,
1942 .removexattr_fn = um_removexattr,
1943 .setxattr_fn = um_setxattr,
1946 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *);
1947 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1949 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1950 "unityed_media", &vfs_um_fns);
1951 if (!NT_STATUS_IS_OK(ret)) {
1952 return ret;
1955 vfs_um_debug_level = debug_add_class("unityed_media");
1957 if (vfs_um_debug_level == -1) {
1958 vfs_um_debug_level = DBGC_VFS;
1959 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1960 "debugging class.\n"));
1963 return ret;