vfs: remove SMB_VFS_OPEN()
[Samba.git] / source3 / modules / vfs_unityed_media.c
blobb755621208b442c5661f6417181384b6fd7ca5df
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 codepoint_t cp;
104 size_t size;
105 int error = 0;
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)smb_strtoul(p,
124 NULL,
126 &error,
127 SMB_STR_STANDARD);
128 if (error != 0) {
129 return false;
131 DEBUG(10, ("num_suffix = '%ju'\n",
132 *digit));
133 return true;
135 p += size;
138 return false;
141 /* Add "_<remote_name>.<number>" suffix to path or filename.
143 * Success: return 0
144 * Failure: set errno, path NULL, return -1
147 static int alloc_append_client_suffix(vfs_handle_struct *handle,
148 char **path)
150 int status = 0;
151 uintmax_t number;
152 const char *clientid;
153 struct um_config_data *config;
155 DEBUG(10, ("Entering with path '%s'\n", *path));
157 SMB_VFS_HANDLE_GET_DATA(handle, config,
158 struct um_config_data,
159 return -1);
161 (void)get_digit_group(*path, &number);
163 switch (config->clientid) {
165 case UM_CLIENTID_IP:
166 clientid = tsocket_address_inet_addr_string(
167 handle->conn->sconn->remote_address, talloc_tos());
168 if (clientid == NULL) {
169 errno = ENOMEM;
170 status = -1;
171 goto err;
173 break;
175 case UM_CLIENTID_HOSTNAME:
176 clientid = get_remote_machine_name();
177 break;
179 case UM_CLIENTID_NAME:
180 default:
181 clientid = get_current_username();
182 break;
185 *path = talloc_asprintf_append(*path, "_%s.%ju",
186 clientid, number);
187 if (*path == NULL) {
188 DEBUG(1, ("alloc_append_client_suffix "
189 "out of memory\n"));
190 errno = ENOMEM;
191 status = -1;
192 goto err;
194 DEBUG(10, ("Leaving with *path '%s'\n", *path));
195 err:
196 return status;
199 /* Returns true if the file or directory begins with the appledouble
200 * prefix.
202 static bool is_apple_double(const char* fname)
204 bool ret = false;
206 DEBUG(10, ("Entering with fname '%s'\n", fname));
208 if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
209 ret = true;
211 DEBUG(10, ("Leaving with ret '%s'\n",
212 ret == true ? "true" : "false"));
213 return ret;
216 static bool starts_with_media_dir(const char* media_dirname,
217 size_t media_dirname_len,
218 const char *path)
220 bool ret = false;
221 const char *path_start = path;
223 DEBUG(10, ("Entering with media_dirname '%s' "
224 "path '%s'\n", media_dirname, path));
226 /* Sometimes Samba gives us "./OMFI MediaFiles". */
227 if (strnequal(path, "./", 2)) {
228 path_start += 2;
231 if (strnequal(media_dirname, path_start, media_dirname_len)
233 ((path_start[media_dirname_len] == '\0') ||
234 (path_start[media_dirname_len] == '/'))) {
235 ret = true;
238 DEBUG(10, ("Leaving with ret '%s'\n",
239 ret == true ? "true" : "false"));
240 return ret;
244 * Returns true if the file or directory referenced by the path is ONE
245 * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
246 * directory
248 static bool is_in_media_dir(const char *path)
250 int transition_count = 0;
251 const char *path_start = path;
252 const char *p;
253 const char *media_dirname;
254 size_t media_dirname_len;
256 DEBUG(10, ("Entering with path'%s' ", path));
258 /* Sometimes Samba gives us "./OMFI MediaFiles". */
259 if (strnequal(path, "./", 2)) {
260 path_start += 2;
263 if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
264 media_dirname = AVID_MXF_DIRNAME;
265 media_dirname_len = AVID_MXF_DIRNAME_LEN;
266 } else if (strnequal(path_start,
267 OMFI_MEDIAFILES_DIRNAME,
268 OMFI_MEDIAFILES_DIRNAME_LEN)) {
269 media_dirname = OMFI_MEDIAFILES_DIRNAME;
270 media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
271 } else {
272 return false;
275 if (path_start[media_dirname_len] == '\0') {
276 goto out;
279 p = path_start + media_dirname_len + 1;
281 while (true) {
282 if (*p == '\0' || *p == '/') {
283 if (strnequal(p - 3, "/..", 3)) {
284 transition_count--;
285 } else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
286 transition_count++;
289 if (*p == '\0') {
290 break;
292 p++;
295 out:
296 DEBUG(10, ("Going out with transition_count '%i'\n",
297 transition_count));
298 if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
300 ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
301 return true;
303 else return false;
307 * Returns true if the file or directory referenced by the path is
308 * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
309 * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
310 * are assumed to be in the root directory, which is generally a safe
311 * assumption in the fixed-path world of Avid.
313 static bool is_in_media_files(const char *path)
315 bool ret = false;
317 DEBUG(10, ("Entering with path '%s'\n", path));
319 if (starts_with_media_dir(AVID_MXF_DIRNAME,
320 AVID_MXF_DIRNAME_LEN, path) ||
321 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
322 OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
323 ret = true;
325 DEBUG(10, ("Leaving with ret '%s'\n",
326 ret == true ? "true" : "false"));
327 return ret;
331 /* Add client suffix to "pure-number" path.
333 * Caller must free newPath.
335 * Success: return 0
336 * Failure: set errno, newPath NULL, return -1
338 static int alloc_get_client_path(vfs_handle_struct *handle,
339 TALLOC_CTX *ctx,
340 const char *path_in,
341 char **path_out)
343 int status = 0;
344 char *p;
345 char *digits;
346 size_t digits_len;
347 uintmax_t number;
349 *path_out = talloc_strdup(ctx, path_in);
350 if (*path_out == NULL) {
351 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
352 return -1;
355 (void)get_digit_group(*path_out, &number);
357 digits = talloc_asprintf(NULL, "%ju", number);
358 if (digits == NULL) {
359 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
360 return -1;
362 digits_len = strlen(digits);
364 p = strstr_m(path_in, digits);
365 if ((p)
367 ((p[digits_len] == '\0') || (p[digits_len] == '/'))
369 (((p - path_in > 0) && (p[-1] == '/'))
371 (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
373 is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
375 (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
377 (*path_out)[p - path_in + digits_len] = '\0';
379 status = alloc_append_client_suffix(handle, path_out);
380 if (status != 0) {
381 goto out;
384 *path_out = talloc_strdup_append(*path_out, p + digits_len);
385 if (*path_out == NULL) {
386 DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
387 status = -1;
388 goto out;
391 out:
392 /* path_out must be freed in caller. */
393 DEBUG(10, ("Result:'%s'\n", *path_out));
394 return status;
398 * Success: return 0
399 * Failure: set errno, return -1
401 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
402 TALLOC_CTX *ctx,
403 const struct smb_filename *smb_fname,
404 struct smb_filename **client_fname)
406 int status ;
408 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
409 smb_fname->base_name));
411 *client_fname = cp_smb_filename(ctx, smb_fname);
412 if (*client_fname == NULL) {
413 DEBUG(1, ("cp_smb_filename returned NULL\n"));
414 return -1;
416 status = alloc_get_client_path(handle, ctx,
417 smb_fname->base_name,
418 &(*client_fname)->base_name);
419 if (status != 0) {
420 return -1;
423 DEBUG(10, ("Leaving with (*client_fname)->base_name "
424 "'%s'\n", (*client_fname)->base_name));
426 return 0;
431 * Success: return 0
432 * Failure: set errno, return -1
434 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
435 TALLOC_CTX *ctx,
436 char **path,
437 const char *suffix_number)
439 int status;
441 DEBUG(10, ("Entering with suffix_number '%s'\n",
442 suffix_number));
444 *path = talloc_strdup(ctx, suffix_number);
445 if (*path == NULL) {
446 DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
447 return -1;
449 status = alloc_append_client_suffix(handle, path);
450 if (status != 0) {
451 return -1;
454 DEBUG(10, ("Leaving with *path '%s'\n", *path));
456 return 0;
459 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
460 const char *fname,
461 struct um_dirinfo_struct **di_result)
463 int status = 0;
464 char *digits;
465 uintmax_t number;
466 struct um_dirinfo_struct *dip;
468 DEBUG(10, ("Entering with fname '%s'\n", fname));
470 *di_result = talloc(NULL, struct um_dirinfo_struct);
471 if (*di_result == NULL) {
472 goto err;
474 dip = *di_result;
476 dip->dirpath = talloc_strdup(dip, fname);
477 if (dip->dirpath == NULL) {
478 goto err;
481 if (!is_in_media_files(fname)) {
482 dip->isInMediaFiles = false;
483 dip->clientPath = NULL;
484 dip->clientSubDirname = NULL;
485 goto out;
488 dip->isInMediaFiles = true;
490 (void)get_digit_group(fname, &number);
491 digits = talloc_asprintf(talloc_tos(), "%ju", number);
492 if (digits == NULL) {
493 goto err;
496 status = alloc_set_client_dirinfo_path(handle, dip,
497 &dip->clientSubDirname,
498 digits);
499 if (status != 0) {
500 goto err;
503 status = alloc_get_client_path(handle, dip, fname,
504 &dip->clientPath);
505 if (status != 0 || dip->clientPath == NULL) {
506 goto err;
509 out:
510 DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
511 "(*dirInfo)->clientPath '%s'\n",
512 dip->dirpath, dip->clientPath));
513 return status;
515 err:
516 DEBUG(1, ("Failing with fname '%s'\n", fname));
517 TALLOC_FREE(*di_result);
518 status = -1;
519 errno = ENOMEM;
520 return status;
523 /**********************************************************************
524 * VFS functions
525 **********************************************************************/
528 * Success: return 0
529 * Failure: set errno, return -1
531 static int um_statvfs(struct vfs_handle_struct *handle,
532 const struct smb_filename *smb_fname,
533 struct vfs_statvfs_struct *statbuf)
535 int status;
536 struct smb_filename *client_fname = NULL;
538 DEBUG(10, ("Entering with path '%s'\n", smb_fname->base_name));
540 if (!is_in_media_files(smb_fname->base_name)) {
541 return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
544 status = alloc_get_client_smb_fname(handle,
545 talloc_tos(),
546 smb_fname,
547 &client_fname);
548 if (status != 0) {
549 goto err;
552 status = SMB_VFS_NEXT_STATVFS(handle, client_fname, statbuf);
553 err:
554 TALLOC_FREE(client_fname);
555 DEBUG(10, ("Leaving with path '%s'\n", smb_fname->base_name));
556 return status;
559 static DIR *um_fdopendir(vfs_handle_struct *handle,
560 files_struct *fsp,
561 const char *mask,
562 uint32_t attr)
564 struct um_dirinfo_struct *dirInfo = NULL;
565 DIR *dirstream;
567 DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
568 fsp->fsp_name->base_name));
570 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
571 if (!dirstream) {
572 goto err;
575 if (alloc_set_client_dirinfo(handle,
576 fsp->fsp_name->base_name,
577 &dirInfo)) {
578 goto err;
581 dirInfo->dirstream = dirstream;
583 if (!dirInfo->isInMediaFiles) {
585 * FIXME: this is the original code, something must be
586 * missing here, but what? -slow
588 goto out;
591 out:
592 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
593 "dirInfo->clientPath '%s', "
594 "fsp->fsp_name->st.st_ex_mtime %s",
595 dirInfo->dirpath,
596 dirInfo->clientPath,
597 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
598 return (DIR *) dirInfo;
600 err:
601 DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
602 fsp->fsp_name->base_name));
603 TALLOC_FREE(dirInfo);
604 return NULL;
608 * skip own suffixed directory
609 * replace own suffixed directory with non suffixed.
611 * Success: return dirent
612 * End of data: return NULL
613 * Failure: set errno, return NULL
615 static struct dirent *um_readdir(vfs_handle_struct *handle,
616 DIR *dirp,
617 SMB_STRUCT_STAT *sbuf)
619 um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
620 struct dirent *d = NULL;
621 int skip;
623 DEBUG(10, ("dirInfo->dirpath '%s', "
624 "dirInfo->clientPath '%s', "
625 "dirInfo->isInMediaFiles '%s', "
626 "dirInfo->clientSubDirname '%s'\n",
627 dirInfo->dirpath,
628 dirInfo->clientPath,
629 dirInfo->isInMediaFiles ? "true" : "false",
630 dirInfo->clientSubDirname));
632 if (!dirInfo->isInMediaFiles) {
633 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
636 do {
637 const char* dname;
638 bool isAppleDouble;
639 char *digits;
640 size_t digits_len;
641 uintmax_t number;
643 skip = false;
644 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
646 if (d == NULL) {
647 break;
650 /* ignore apple double prefix for logic below */
651 if (is_apple_double(d->d_name)) {
652 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
653 isAppleDouble = true;
654 } else {
655 dname = d->d_name;
656 isAppleDouble = false;
659 DEBUG(10, ("dname = '%s'\n", dname));
661 (void)get_digit_group(dname, &number);
662 digits = talloc_asprintf(talloc_tos(), "%ju", number);
663 if (digits == NULL) {
664 DEBUG(1, ("out of memory"));
665 goto err;
667 digits_len = strlen(digits);
669 if (alloc_set_client_dirinfo_path(handle,
670 dirInfo,
671 &((dirInfo)->clientSubDirname),
672 digits)) {
673 goto err;
677 * If set to "true", vfs shows digits-only
678 * non-suffixed subdirectories. Normally, such
679 * subdirectories can exists only in non-media
680 * directories, so we set it to "false". Otherwise,
681 * if we have such subdirectories (probably created
682 * over not "unityed" connection), it can be little
683 * bit confusing.
685 if (strequal(dname, digits)) {
686 skip = false;
687 } else if (strequal(dname, dirInfo->clientSubDirname)) {
689 * Remove suffix of this client's suffixed
690 * subdirectories
692 if (isAppleDouble) {
693 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
694 } else {
695 d->d_name[digits_len] = '\0';
697 } else if (strnequal(digits, dname, digits_len)) {
699 * Set to false to see another clients subdirectories
701 skip = false;
703 } while (skip);
705 DEBUG(10, ("Leaving um_readdir\n"));
706 return d;
707 err:
708 TALLOC_FREE(dirInfo);
709 return NULL;
712 static void um_seekdir(vfs_handle_struct *handle,
713 DIR *dirp,
714 long offset)
716 DEBUG(10, ("Entering and leaving um_seekdir\n"));
717 SMB_VFS_NEXT_SEEKDIR(handle,
718 ((um_dirinfo_struct*)dirp)->dirstream, offset);
721 static long um_telldir(vfs_handle_struct *handle,
722 DIR *dirp)
724 DEBUG(10, ("Entering and leaving um_telldir\n"));
725 return SMB_VFS_NEXT_TELLDIR(handle,
726 ((um_dirinfo_struct*)dirp)->dirstream);
729 static void um_rewinddir(vfs_handle_struct *handle,
730 DIR *dirp)
732 DEBUG(10, ("Entering and leaving um_rewinddir\n"));
733 SMB_VFS_NEXT_REWINDDIR(handle,
734 ((um_dirinfo_struct*)dirp)->dirstream);
737 static int um_mkdirat(vfs_handle_struct *handle,
738 struct files_struct *dirfsp,
739 const struct smb_filename *smb_fname,
740 mode_t mode)
742 int status;
743 const char *path = smb_fname->base_name;
744 struct smb_filename *client_fname = NULL;
746 DEBUG(10, ("Entering with path '%s'\n", path));
748 if (!is_in_media_files(path) || !is_in_media_dir(path)) {
749 return SMB_VFS_NEXT_MKDIRAT(handle,
750 dirfsp,
751 smb_fname,
752 mode);
755 status = alloc_get_client_smb_fname(handle,
756 talloc_tos(),
757 smb_fname,
758 &client_fname);
759 if (status != 0) {
760 goto err;
763 status = SMB_VFS_NEXT_MKDIRAT(handle,
764 dirfsp,
765 client_fname,
766 mode);
767 err:
768 TALLOC_FREE(client_fname);
769 DEBUG(10, ("Leaving with path '%s'\n", path));
770 return status;
773 static int um_closedir(vfs_handle_struct *handle,
774 DIR *dirp)
776 DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
778 TALLOC_FREE(dirp);
780 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
783 static int um_openat(struct vfs_handle_struct *handle,
784 const struct files_struct *dirfsp,
785 const struct smb_filename *smb_fname,
786 struct files_struct *fsp,
787 int flags,
788 mode_t mode)
790 struct smb_filename *client_fname = NULL;
791 int ret;
793 DBG_DEBUG("Entering with smb_fname->base_name '%s'\n",
794 smb_fname->base_name);
796 if (!is_in_media_files(smb_fname->base_name)) {
797 return SMB_VFS_NEXT_OPENAT(handle,
798 dirfsp,
799 smb_fname,
800 fsp,
801 flags,
802 mode);
805 if (alloc_get_client_smb_fname(handle, talloc_tos(),
806 smb_fname,
807 &client_fname)) {
808 ret = -1;
809 goto err;
813 * FIXME:
814 * What about fsp->fsp_name? We also have to get correct stat
815 * info into fsp and smb_fname for DB files, don't we?
818 DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
819 "smb_fname->st.st_ex_mtime %s"
820 "fsp->fsp_name->st.st_ex_mtime %s",
821 smb_fname->base_name,
822 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
823 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
825 ret = SMB_VFS_NEXT_OPENAT(handle,
826 dirfsp,
827 client_fname,
828 fsp,
829 flags,
830 mode);
831 err:
832 TALLOC_FREE(client_fname);
833 DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
834 smb_fname->base_name));
835 return ret;
838 static NTSTATUS um_create_file(vfs_handle_struct *handle,
839 struct smb_request *req,
840 struct files_struct **dirfsp,
841 struct smb_filename *smb_fname,
842 uint32_t access_mask,
843 uint32_t share_access,
844 uint32_t create_disposition,
845 uint32_t create_options,
846 uint32_t file_attributes,
847 uint32_t oplock_request,
848 const struct smb2_lease *lease,
849 uint64_t allocation_size,
850 uint32_t private_flags,
851 struct security_descriptor *sd,
852 struct ea_list *ea_list,
853 files_struct **result_fsp,
854 int *pinfo,
855 const struct smb2_create_blobs *in_context_blobs,
856 struct smb2_create_blobs *out_context_blobs)
858 NTSTATUS status;
859 struct smb_filename *client_fname = NULL;
861 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
862 smb_fname->base_name));
864 if (!is_in_media_files(smb_fname->base_name)) {
865 return SMB_VFS_NEXT_CREATE_FILE(
866 handle,
867 req,
868 dirfsp,
869 smb_fname,
870 access_mask,
871 share_access,
872 create_disposition,
873 create_options,
874 file_attributes,
875 oplock_request,
876 lease,
877 allocation_size,
878 private_flags,
880 ea_list,
881 result_fsp,
882 pinfo,
883 in_context_blobs,
884 out_context_blobs);
887 if (alloc_get_client_smb_fname(handle, talloc_tos(),
888 smb_fname,
889 &client_fname)) {
890 status = map_nt_error_from_unix(errno);
891 goto err;
895 * FIXME:
896 * This only creates files, so we don't have to worry about
897 * our fake directory stat'ing here. But we still need to
898 * route stat calls for DB files properly, right?
900 status = SMB_VFS_NEXT_CREATE_FILE(
901 handle,
902 req,
903 dirfsp,
904 client_fname,
905 access_mask,
906 share_access,
907 create_disposition,
908 create_options,
909 file_attributes,
910 oplock_request,
911 lease,
912 allocation_size,
913 private_flags,
915 ea_list,
916 result_fsp,
917 pinfo,
918 in_context_blobs,
919 out_context_blobs);
920 err:
921 TALLOC_FREE(client_fname);
922 DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
923 "smb_fname->st.st_ex_mtime %s"
924 " fsp->fsp_name->st.st_ex_mtime %s",
925 smb_fname->base_name,
926 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
927 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
928 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
929 "No fsp time\n"));
930 return status;
933 static int um_renameat(vfs_handle_struct *handle,
934 files_struct *srcfsp,
935 const struct smb_filename *smb_fname_src,
936 files_struct *dstfsp,
937 const struct smb_filename *smb_fname_dst)
939 int status;
940 struct smb_filename *src_client_fname = NULL;
941 struct smb_filename *dst_client_fname = NULL;
943 DEBUG(10, ("Entering with "
944 "smb_fname_src->base_name '%s', "
945 "smb_fname_dst->base_name '%s'\n",
946 smb_fname_src->base_name,
947 smb_fname_dst->base_name));
949 if (!is_in_media_files(smb_fname_src->base_name)
951 !is_in_media_files(smb_fname_dst->base_name)) {
952 return SMB_VFS_NEXT_RENAMEAT(handle,
953 srcfsp,
954 smb_fname_src,
955 dstfsp,
956 smb_fname_dst);
959 status = alloc_get_client_smb_fname(handle, talloc_tos(),
960 smb_fname_src,
961 &src_client_fname);
962 if (status != 0) {
963 goto err;
966 status = alloc_get_client_smb_fname(handle, talloc_tos(),
967 smb_fname_dst,
968 &dst_client_fname);
970 if (status != 0) {
971 goto err;
974 status = SMB_VFS_NEXT_RENAMEAT(handle,
975 srcfsp,
976 src_client_fname,
977 dstfsp,
978 dst_client_fname);
980 err:
981 TALLOC_FREE(dst_client_fname);
982 TALLOC_FREE(src_client_fname);
983 DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
984 " smb_fname_dst->base_name '%s'\n",
985 smb_fname_src->base_name,
986 smb_fname_dst->base_name));
987 return status;
992 * Success: return 0
993 * Failure: set errno, return -1
995 static int um_stat(vfs_handle_struct *handle,
996 struct smb_filename *smb_fname)
998 int status = 0;
999 struct smb_filename *client_fname = NULL;
1001 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1002 smb_fname->base_name));
1004 if (!is_in_media_files(smb_fname->base_name)) {
1005 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1008 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1009 smb_fname,
1010 &client_fname);
1011 if (status != 0) {
1012 goto err;
1014 DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1015 client_fname->base_name));
1017 status = SMB_VFS_NEXT_STAT(handle, client_fname);
1018 if (status != 0) {
1019 goto err;
1023 * Unlike functions with const smb_filename, we have to modify
1024 * smb_fname itself to pass our info back up.
1026 DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1027 smb_fname->base_name, client_fname->base_name));
1028 smb_fname->st = client_fname->st;
1030 err:
1031 TALLOC_FREE(client_fname);
1032 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1033 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1034 return status;
1037 static int um_lstat(vfs_handle_struct *handle,
1038 struct smb_filename *smb_fname)
1040 int status = 0;
1041 struct smb_filename *client_fname = NULL;
1043 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1044 smb_fname->base_name));
1046 if (!is_in_media_files(smb_fname->base_name)) {
1047 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1050 client_fname = NULL;
1052 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1053 smb_fname,
1054 &client_fname);
1055 if (status != 0) {
1056 goto err;
1058 status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1059 if (status != 0) {
1060 goto err;
1063 smb_fname->st = client_fname->st;
1065 err:
1066 TALLOC_FREE(client_fname);
1067 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1068 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1069 return status;
1072 static int um_fstat(vfs_handle_struct *handle,
1073 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1075 int status = 0;
1077 DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1078 "'%s'\n", fsp_str_dbg(fsp)));
1080 status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1081 if (status != 0) {
1082 goto out;
1085 if ((fsp->fsp_name == NULL) ||
1086 !is_in_media_files(fsp->fsp_name->base_name)) {
1087 goto out;
1090 status = um_stat(handle, fsp->fsp_name);
1091 if (status != 0) {
1092 goto out;
1095 *sbuf = fsp->fsp_name->st;
1097 out:
1098 DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1099 fsp->fsp_name != NULL ?
1100 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1101 return status;
1104 static int um_unlinkat(vfs_handle_struct *handle,
1105 struct files_struct *dirfsp,
1106 const struct smb_filename *smb_fname,
1107 int flags)
1109 int ret;
1110 struct smb_filename *client_fname = NULL;
1112 DEBUG(10, ("Entering um_unlinkat\n"));
1114 if (!is_in_media_files(smb_fname->base_name)) {
1115 return SMB_VFS_NEXT_UNLINKAT(handle,
1116 dirfsp,
1117 smb_fname,
1118 flags);
1121 ret = alloc_get_client_smb_fname(handle, talloc_tos(),
1122 smb_fname,
1123 &client_fname);
1124 if (ret != 0) {
1125 goto err;
1128 ret = SMB_VFS_NEXT_UNLINKAT(handle,
1129 dirfsp,
1130 client_fname,
1131 flags);
1133 err:
1134 TALLOC_FREE(client_fname);
1135 return ret;
1138 static int um_chmod(vfs_handle_struct *handle,
1139 const struct smb_filename *smb_fname,
1140 mode_t mode)
1142 int status;
1143 struct smb_filename *client_fname = NULL;
1145 DEBUG(10, ("Entering um_chmod\n"));
1147 if (!is_in_media_files(smb_fname->base_name)) {
1148 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1151 status = alloc_get_client_smb_fname(handle,
1152 talloc_tos(),
1153 smb_fname,
1154 &client_fname);
1155 if (status != 0) {
1156 goto err;
1159 status = SMB_VFS_NEXT_CHMOD(handle, client_fname, mode);
1161 err:
1162 TALLOC_FREE(client_fname);
1163 return status;
1166 static int um_lchown(vfs_handle_struct *handle,
1167 const struct smb_filename *smb_fname,
1168 uid_t uid,
1169 gid_t gid)
1171 int status;
1172 struct smb_filename *client_fname = NULL;
1174 DEBUG(10, ("Entering um_lchown\n"));
1175 if (!is_in_media_files(smb_fname->base_name)) {
1176 return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1179 status = alloc_get_client_smb_fname(handle,
1180 talloc_tos(),
1181 smb_fname,
1182 &client_fname);
1183 if (status != 0) {
1184 goto err;
1187 status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1189 err:
1190 TALLOC_FREE(client_fname);
1191 return status;
1194 static int um_chdir(vfs_handle_struct *handle,
1195 const struct smb_filename *smb_fname)
1197 int status;
1198 struct smb_filename *client_fname = NULL;
1200 DEBUG(10, ("Entering um_chdir\n"));
1202 if (!is_in_media_files(smb_fname->base_name)) {
1203 return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1206 status = alloc_get_client_smb_fname(handle,
1207 talloc_tos(),
1208 smb_fname,
1209 &client_fname);
1210 if (status != 0) {
1211 goto err;
1214 status = SMB_VFS_NEXT_CHDIR(handle, client_fname);
1216 err:
1217 TALLOC_FREE(client_fname);
1218 return status;
1221 static int um_ntimes(vfs_handle_struct *handle,
1222 const struct smb_filename *smb_fname,
1223 struct smb_file_time *ft)
1225 int status;
1226 struct smb_filename *client_fname = NULL;
1228 DEBUG(10, ("Entering um_ntimes\n"));
1230 if (!is_in_media_files(smb_fname->base_name)) {
1231 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1234 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1235 smb_fname, &client_fname);
1236 if (status != 0) {
1237 goto err;
1240 status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
1242 err:
1243 TALLOC_FREE(client_fname);
1244 return status;
1247 static int um_symlinkat(vfs_handle_struct *handle,
1248 const struct smb_filename *link_contents,
1249 struct files_struct *dirfsp,
1250 const struct smb_filename *new_smb_fname)
1252 int status;
1253 struct smb_filename *new_link_target = NULL;
1254 struct smb_filename *new_client_fname = NULL;
1256 DEBUG(10, ("Entering um_symlinkat\n"));
1258 if (!is_in_media_files(link_contents->base_name) &&
1259 !is_in_media_files(new_smb_fname->base_name)) {
1260 return SMB_VFS_NEXT_SYMLINKAT(handle,
1261 link_contents,
1262 dirfsp,
1263 new_smb_fname);
1266 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1267 link_contents, &new_link_target);
1268 if (status != 0) {
1269 goto err;
1271 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1272 new_smb_fname, &new_client_fname);
1273 if (status != 0) {
1274 goto err;
1277 status = SMB_VFS_NEXT_SYMLINKAT(handle,
1278 new_link_target,
1279 dirfsp,
1280 new_client_fname);
1282 err:
1283 TALLOC_FREE(new_link_target);
1284 TALLOC_FREE(new_client_fname);
1285 return status;
1288 static int um_readlinkat(vfs_handle_struct *handle,
1289 files_struct *dirfsp,
1290 const struct smb_filename *smb_fname,
1291 char *buf,
1292 size_t bufsiz)
1294 int status;
1295 struct smb_filename *client_fname = NULL;
1297 DEBUG(10, ("Entering um_readlinkat\n"));
1299 if (!is_in_media_files(smb_fname->base_name)) {
1300 return SMB_VFS_NEXT_READLINKAT(handle,
1301 dirfsp,
1302 smb_fname,
1303 buf,
1304 bufsiz);
1307 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1308 smb_fname, &client_fname);
1309 if (status != 0) {
1310 goto err;
1313 status = SMB_VFS_NEXT_READLINKAT(handle,
1314 dirfsp,
1315 client_fname,
1316 buf,
1317 bufsiz);
1319 err:
1320 TALLOC_FREE(client_fname);
1321 return status;
1324 static int um_linkat(vfs_handle_struct *handle,
1325 files_struct *srcfsp,
1326 const struct smb_filename *old_smb_fname,
1327 files_struct *dstfsp,
1328 const struct smb_filename *new_smb_fname,
1329 int flags)
1331 int status;
1332 struct smb_filename *old_client_fname = NULL;
1333 struct smb_filename *new_client_fname = NULL;
1335 DEBUG(10, ("Entering um_linkat\n"));
1336 if (!is_in_media_files(old_smb_fname->base_name) &&
1337 !is_in_media_files(new_smb_fname->base_name)) {
1338 return SMB_VFS_NEXT_LINKAT(handle,
1339 srcfsp,
1340 old_smb_fname,
1341 dstfsp,
1342 new_smb_fname,
1343 flags);
1346 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1347 old_smb_fname, &old_client_fname);
1348 if (status != 0) {
1349 goto err;
1351 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1352 new_smb_fname, &new_client_fname);
1353 if (status != 0) {
1354 goto err;
1357 status = SMB_VFS_NEXT_LINKAT(handle,
1358 srcfsp,
1359 old_client_fname,
1360 dstfsp,
1361 new_client_fname,
1362 flags);
1364 err:
1365 TALLOC_FREE(old_client_fname);
1366 TALLOC_FREE(new_client_fname);
1367 return status;
1370 static int um_mknodat(vfs_handle_struct *handle,
1371 files_struct *dirfsp,
1372 const struct smb_filename *smb_fname,
1373 mode_t mode,
1374 SMB_DEV_T dev)
1376 int status;
1377 struct smb_filename *client_fname = NULL;
1379 DEBUG(10, ("Entering um_mknodat\n"));
1380 if (!is_in_media_files(smb_fname->base_name)) {
1381 return SMB_VFS_NEXT_MKNODAT(handle,
1382 dirfsp,
1383 smb_fname,
1384 mode,
1385 dev);
1388 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1389 smb_fname, &client_fname);
1390 if (status != 0) {
1391 goto err;
1394 status = SMB_VFS_NEXT_MKNODAT(handle,
1395 dirfsp,
1396 client_fname,
1397 mode,
1398 dev);
1400 err:
1401 TALLOC_FREE(client_fname);
1402 return status;
1405 static struct smb_filename *um_realpath(vfs_handle_struct *handle,
1406 TALLOC_CTX *ctx,
1407 const struct smb_filename *smb_fname)
1409 struct smb_filename *client_fname = NULL;
1410 struct smb_filename *result_fname = NULL;
1411 int status;
1413 DEBUG(10, ("Entering um_realpath\n"));
1415 if (!is_in_media_files(smb_fname->base_name)) {
1416 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1419 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1420 smb_fname, &client_fname);
1421 if (status != 0) {
1422 goto err;
1425 result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, client_fname);
1427 err:
1428 TALLOC_FREE(client_fname);
1429 return result_fname;
1432 static int um_chflags(vfs_handle_struct *handle,
1433 const struct smb_filename *smb_fname,
1434 unsigned int flags)
1436 int status;
1437 struct smb_filename *client_fname = NULL;
1439 DEBUG(10, ("Entering um_mknod\n"));
1440 if (!is_in_media_files(smb_fname->base_name)) {
1441 return SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1444 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1445 smb_fname, &client_fname);
1446 if (status != 0) {
1447 goto err;
1450 status = SMB_VFS_NEXT_CHFLAGS(handle, client_fname, flags);
1452 err:
1453 TALLOC_FREE(client_fname);
1454 return status;
1457 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1458 struct files_struct *fsp,
1459 const struct smb_filename *smb_fname,
1460 TALLOC_CTX *ctx,
1461 unsigned int *num_streams,
1462 struct stream_struct **streams)
1464 NTSTATUS status;
1465 int ret;
1466 struct smb_filename *client_fname = NULL;
1468 DEBUG(10, ("Entering um_streaminfo\n"));
1470 if (!is_in_media_files(smb_fname->base_name)) {
1471 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname,
1472 ctx, num_streams, streams);
1475 ret = alloc_get_client_smb_fname(handle,
1476 talloc_tos(),
1477 smb_fname,
1478 &client_fname);
1479 if (ret != 0) {
1480 status = NT_STATUS_NO_MEMORY;
1481 goto err;
1485 * This only works on files, so we don't have to worry about
1486 * our fake directory stat'ing here. But what does this
1487 * function do, exactly? Does it need extra modifications for
1488 * the Avid stuff?
1490 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_fname,
1491 ctx, num_streams, streams);
1492 err:
1493 TALLOC_FREE(client_fname);
1494 return status;
1498 * Ignoring get_real_filename function because the default doesn't do
1499 * anything.
1502 static NTSTATUS um_get_nt_acl_at(vfs_handle_struct *handle,
1503 struct files_struct *dirfsp,
1504 const struct smb_filename *smb_fname,
1505 uint32_t security_info,
1506 TALLOC_CTX *mem_ctx,
1507 struct security_descriptor **ppdesc)
1509 NTSTATUS status;
1510 char *client_path = NULL;
1511 struct smb_filename *client_smb_fname = NULL;
1512 bool ok;
1513 int ret;
1515 DBG_DEBUG("Entering um_get_nt_acl_at\n");
1517 ok = is_in_media_files(smb_fname->base_name);
1518 if (!ok) {
1519 return SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
1520 dirfsp,
1521 smb_fname,
1522 security_info,
1523 mem_ctx,
1524 ppdesc);
1527 ret = alloc_get_client_path(handle,
1528 talloc_tos(),
1529 smb_fname->base_name,
1530 &client_path);
1531 if (ret != 0) {
1532 status = map_nt_error_from_unix(errno);
1533 goto err;
1536 client_smb_fname = synthetic_smb_fname(talloc_tos(),
1537 client_path,
1538 NULL,
1539 NULL,
1540 smb_fname->twrp,
1541 smb_fname->flags);
1542 if (client_smb_fname == NULL) {
1543 TALLOC_FREE(client_path);
1544 return NT_STATUS_NO_MEMORY;
1547 status = SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
1548 dirfsp,
1549 client_smb_fname,
1550 security_info,
1551 mem_ctx,
1552 ppdesc);
1553 err:
1554 TALLOC_FREE(client_smb_fname);
1555 TALLOC_FREE(client_path);
1556 return status;
1559 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1560 const struct smb_filename *smb_fname,
1561 SMB_ACL_TYPE_T type,
1562 TALLOC_CTX *mem_ctx)
1564 SMB_ACL_T ret;
1565 int saved_errno = 0;
1566 struct smb_filename *client_fname = NULL;
1567 int status;
1569 DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1571 if (!is_in_media_files(smb_fname->base_name)) {
1572 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
1573 type, mem_ctx);
1576 status = alloc_get_client_smb_fname(handle,
1577 talloc_tos(),
1578 smb_fname,
1579 &client_fname);
1580 if (status != 0) {
1581 ret = (SMB_ACL_T)NULL;
1582 goto err;
1585 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_fname,
1586 type, mem_ctx);
1588 err:
1589 if (ret == (SMB_ACL_T)NULL) {
1590 saved_errno = errno;
1592 TALLOC_FREE(client_fname);
1593 if (saved_errno != 0) {
1594 errno = saved_errno;
1596 return ret;
1599 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1600 const struct smb_filename *smb_fname,
1601 SMB_ACL_TYPE_T acltype,
1602 SMB_ACL_T theacl)
1604 int status;
1605 int saved_errno = 0;
1606 struct smb_filename *client_fname = NULL;
1608 DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1610 if (!is_in_media_files(smb_fname->base_name)) {
1611 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
1612 acltype, theacl);
1615 status = alloc_get_client_smb_fname(handle,
1616 talloc_tos(),
1617 smb_fname,
1618 &client_fname);
1619 if (status != 0) {
1620 goto err;
1623 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_fname,
1624 acltype, theacl);
1626 err:
1627 if (status == -1) {
1628 saved_errno = errno;
1630 TALLOC_FREE(client_fname);
1631 if (saved_errno != 0) {
1632 errno = saved_errno;
1634 return status;
1637 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1638 const struct smb_filename *smb_fname)
1640 int status;
1641 int saved_errno = 0;
1642 struct smb_filename *client_fname = NULL;
1644 DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1646 if (!is_in_media_files(smb_fname->base_name)) {
1647 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
1648 smb_fname);
1651 status = alloc_get_client_smb_fname(handle,
1652 talloc_tos(),
1653 smb_fname,
1654 &client_fname);
1655 if (status != 0) {
1656 goto err;
1659 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_fname);
1661 err:
1662 if (status == -1) {
1663 saved_errno = errno;
1665 TALLOC_FREE(client_fname);
1666 if (saved_errno != 0) {
1667 errno = saved_errno;
1669 return status;
1672 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1673 const struct smb_filename *smb_fname,
1674 const char *name,
1675 void *value,
1676 size_t size)
1678 ssize_t ret;
1679 struct smb_filename *client_fname = NULL;
1680 int status;
1682 DEBUG(10, ("Entering um_getxattr\n"));
1683 if (!is_in_media_files(smb_fname->base_name)) {
1684 return SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
1685 name, value, size);
1688 status = alloc_get_client_smb_fname(handle,
1689 talloc_tos(),
1690 smb_fname,
1691 &client_fname);
1692 if (status != 0) {
1693 ret = -1;
1694 goto err;
1697 ret = SMB_VFS_NEXT_GETXATTR(handle, client_fname, name, value, size);
1698 err:
1699 TALLOC_FREE(client_fname);
1700 return ret;
1703 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1704 const struct smb_filename *smb_fname,
1705 char *list,
1706 size_t size)
1708 ssize_t ret;
1709 struct smb_filename *client_fname = NULL;
1710 int status;
1712 DEBUG(10, ("Entering um_listxattr\n"));
1714 if (!is_in_media_files(smb_fname->base_name)) {
1715 return SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
1718 status = alloc_get_client_smb_fname(handle,
1719 talloc_tos(),
1720 smb_fname,
1721 &client_fname);
1722 if (status != 0) {
1723 ret = -1;
1724 goto err;
1727 ret = SMB_VFS_NEXT_LISTXATTR(handle, client_fname, list, size);
1729 err:
1730 TALLOC_FREE(client_fname);
1731 return ret;
1734 static int um_removexattr(struct vfs_handle_struct *handle,
1735 const struct smb_filename *smb_fname,
1736 const char *name)
1738 int status;
1739 struct smb_filename *client_fname = NULL;
1741 DEBUG(10, ("Entering um_removexattr\n"));
1743 if (!is_in_media_files(smb_fname->base_name)) {
1744 return SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
1747 status = alloc_get_client_smb_fname(handle,
1748 talloc_tos(),
1749 smb_fname,
1750 &client_fname);
1751 if (status != 0) {
1752 goto err;
1755 status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_fname, name);
1757 err:
1758 TALLOC_FREE(client_fname);
1759 return status;
1762 static int um_setxattr(struct vfs_handle_struct *handle,
1763 const struct smb_filename *smb_fname,
1764 const char *name,
1765 const void *value,
1766 size_t size,
1767 int flags)
1769 int status;
1770 struct smb_filename *client_fname = NULL;
1772 DEBUG(10, ("Entering um_setxattr\n"));
1774 if (!is_in_media_files(smb_fname->base_name)) {
1775 return SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
1776 size, flags);
1779 status = alloc_get_client_smb_fname(handle,
1780 talloc_tos(),
1781 smb_fname,
1782 &client_fname);
1783 if (status != 0) {
1784 goto err;
1787 status = SMB_VFS_NEXT_SETXATTR(handle, client_fname, name, value,
1788 size, flags);
1790 err:
1791 TALLOC_FREE(client_fname);
1792 return status;
1795 static int um_connect(vfs_handle_struct *handle,
1796 const char *service,
1797 const char *user)
1799 int rc;
1800 struct um_config_data *config;
1801 int enumval;
1803 rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1804 if (rc != 0) {
1805 return rc;
1808 config = talloc_zero(handle->conn, struct um_config_data);
1809 if (!config) {
1810 DEBUG(1, ("talloc_zero() failed\n"));
1811 errno = ENOMEM;
1812 return -1;
1815 enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1816 "clientid", um_clientid, UM_CLIENTID_NAME);
1817 if (enumval == -1) {
1818 DEBUG(1, ("value for %s: type unknown\n",
1819 UM_PARAM_TYPE_NAME));
1820 return -1;
1822 config->clientid = (enum um_clientid)enumval;
1824 SMB_VFS_HANDLE_SET_DATA(handle, config,
1825 NULL, struct um_config_data,
1826 return -1);
1828 return 0;
1831 /* VFS operations structure */
1833 static struct vfs_fn_pointers vfs_um_fns = {
1834 .connect_fn = um_connect,
1836 /* Disk operations */
1838 .statvfs_fn = um_statvfs,
1840 /* Directory operations */
1842 .fdopendir_fn = um_fdopendir,
1843 .readdir_fn = um_readdir,
1844 .seekdir_fn = um_seekdir,
1845 .telldir_fn = um_telldir,
1846 .rewind_dir_fn = um_rewinddir,
1847 .mkdirat_fn = um_mkdirat,
1848 .closedir_fn = um_closedir,
1850 /* File operations */
1852 .openat_fn = um_openat,
1853 .create_file_fn = um_create_file,
1854 .renameat_fn = um_renameat,
1855 .stat_fn = um_stat,
1856 .lstat_fn = um_lstat,
1857 .fstat_fn = um_fstat,
1858 .unlinkat_fn = um_unlinkat,
1859 .chmod_fn = um_chmod,
1860 .lchown_fn = um_lchown,
1861 .chdir_fn = um_chdir,
1862 .ntimes_fn = um_ntimes,
1863 .symlinkat_fn = um_symlinkat,
1864 .readlinkat_fn = um_readlinkat,
1865 .linkat_fn = um_linkat,
1866 .mknodat_fn = um_mknodat,
1867 .realpath_fn = um_realpath,
1868 .chflags_fn = um_chflags,
1869 .streaminfo_fn = um_streaminfo,
1871 /* NT ACL operations. */
1873 .get_nt_acl_at_fn = um_get_nt_acl_at,
1875 /* POSIX ACL operations. */
1877 .sys_acl_get_file_fn = um_sys_acl_get_file,
1878 .sys_acl_set_file_fn = um_sys_acl_set_file,
1879 .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1881 /* EA operations. */
1882 .getxattr_fn = um_getxattr,
1883 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1884 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1885 .listxattr_fn = um_listxattr,
1886 .removexattr_fn = um_removexattr,
1887 .setxattr_fn = um_setxattr,
1890 static_decl_vfs;
1891 NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1893 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1894 "unityed_media", &vfs_um_fns);
1895 if (!NT_STATUS_IS_OK(ret)) {
1896 return ret;
1899 vfs_um_debug_level = debug_add_class("unityed_media");
1901 if (vfs_um_debug_level == -1) {
1902 vfs_um_debug_level = DBGC_VFS;
1903 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1904 "debugging class.\n"));
1907 return ret;