KCC: docstring for kcc.graph.InternalEdge
[Samba.git] / source3 / modules / vfs_unityed_media.c
blobb4d7dc09b492ec5d753ce8f3ff2ef8199aef7b40
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 char *fname,
555 const char *mask,
556 uint32_t attr)
558 struct um_dirinfo_struct *dirInfo;
560 DEBUG(10, ("Entering with fname '%s'\n", fname));
562 if (alloc_set_client_dirinfo(handle, fname, &dirInfo)) {
563 goto err;
566 if (!dirInfo->isInMediaFiles) {
567 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
568 handle, fname, mask, attr);
569 } else {
570 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(
571 handle, dirInfo->clientPath, mask, attr);
574 if (dirInfo->dirstream == NULL) {
575 goto err;
578 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
579 "dirInfo->clientPath '%s'\n",
580 dirInfo->dirpath,
581 dirInfo->clientPath));
582 return (DIR*)dirInfo;
584 err:
585 DEBUG(1, ("Failing with fname '%s'\n", fname));
586 TALLOC_FREE(dirInfo);
587 return NULL;
590 static DIR *um_fdopendir(vfs_handle_struct *handle,
591 files_struct *fsp,
592 const char *mask,
593 uint32_t attr)
595 struct um_dirinfo_struct *dirInfo = NULL;
596 DIR *dirstream;
598 DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
599 fsp->fsp_name->base_name));
601 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
602 if (!dirstream) {
603 goto err;
606 if (alloc_set_client_dirinfo(handle,
607 fsp->fsp_name->base_name,
608 &dirInfo)) {
609 goto err;
612 dirInfo->dirstream = dirstream;
614 if (!dirInfo->isInMediaFiles) {
616 * FIXME: this is the original code, something must be
617 * missing here, but what? -slow
619 goto out;
622 out:
623 DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
624 "dirInfo->clientPath '%s', "
625 "fsp->fsp_name->st.st_ex_mtime %s",
626 dirInfo->dirpath,
627 dirInfo->clientPath,
628 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
629 return (DIR *) dirInfo;
631 err:
632 DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
633 fsp->fsp_name->base_name));
634 TALLOC_FREE(dirInfo);
635 return NULL;
639 * skip own suffixed directory
640 * replace own suffixed directory with non suffixed.
642 * Success: return dirent
643 * End of data: return NULL
644 * Failure: set errno, return NULL
646 static struct dirent *um_readdir(vfs_handle_struct *handle,
647 DIR *dirp,
648 SMB_STRUCT_STAT *sbuf)
650 um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
651 struct dirent *d = NULL;
652 int skip;
654 DEBUG(10, ("dirInfo->dirpath '%s', "
655 "dirInfo->clientPath '%s', "
656 "dirInfo->isInMediaFiles '%s', "
657 "dirInfo->clientSubDirname '%s'\n",
658 dirInfo->dirpath,
659 dirInfo->clientPath,
660 dirInfo->isInMediaFiles ? "true" : "false",
661 dirInfo->clientSubDirname));
663 if (!dirInfo->isInMediaFiles) {
664 return SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
667 do {
668 const char* dname;
669 bool isAppleDouble;
670 char *digits;
671 size_t digits_len;
672 uintmax_t number;
674 skip = false;
675 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
677 if (d == NULL) {
678 break;
681 /* ignore apple double prefix for logic below */
682 if (is_apple_double(d->d_name)) {
683 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
684 isAppleDouble = true;
685 } else {
686 dname = d->d_name;
687 isAppleDouble = false;
690 DEBUG(10, ("dname = '%s'\n", dname));
692 (void)get_digit_group(dname, &number);
693 digits = talloc_asprintf(talloc_tos(), "%ju", number);
694 if (digits == NULL) {
695 DEBUG(1, ("out of memory"));
696 goto err;
698 digits_len = strlen(digits);
700 if (alloc_set_client_dirinfo_path(handle,
701 dirInfo,
702 &((dirInfo)->clientSubDirname),
703 digits)) {
704 goto err;
708 * If set to "true", vfs shows digits-only
709 * non-suffixed subdirectories. Normally, such
710 * subdirectories can exists only in non-media
711 * directories, so we set it to "false". Otherwise,
712 * if we have such subdirectories (probably created
713 * over not "unityed" connection), it can be little
714 * bit confusing.
716 if (strequal(dname, digits)) {
717 skip = false;
718 } else if (strequal(dname, dirInfo->clientSubDirname)) {
720 * Remove suffix of this client's suffixed
721 * subdirectories
723 if (isAppleDouble) {
724 d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
725 } else {
726 d->d_name[digits_len] = '\0';
728 } else if (strnequal(digits, dname, digits_len)) {
730 * Set to false to see another clients subdirectories
732 skip = false;
734 } while (skip);
736 DEBUG(10, ("Leaving um_readdir\n"));
737 return d;
738 err:
739 TALLOC_FREE(dirInfo);
740 return NULL;
743 static void um_seekdir(vfs_handle_struct *handle,
744 DIR *dirp,
745 long offset)
747 DEBUG(10, ("Entering and leaving um_seekdir\n"));
748 SMB_VFS_NEXT_SEEKDIR(handle,
749 ((um_dirinfo_struct*)dirp)->dirstream, offset);
752 static long um_telldir(vfs_handle_struct *handle,
753 DIR *dirp)
755 DEBUG(10, ("Entering and leaving um_telldir\n"));
756 return SMB_VFS_NEXT_TELLDIR(handle,
757 ((um_dirinfo_struct*)dirp)->dirstream);
760 static void um_rewinddir(vfs_handle_struct *handle,
761 DIR *dirp)
763 DEBUG(10, ("Entering and leaving um_rewinddir\n"));
764 SMB_VFS_NEXT_REWINDDIR(handle,
765 ((um_dirinfo_struct*)dirp)->dirstream);
768 static int um_mkdir(vfs_handle_struct *handle,
769 const char *path,
770 mode_t mode)
772 int status;
773 char *clientPath;
774 TALLOC_CTX *ctx;
777 DEBUG(10, ("Entering with path '%s'\n", path));
779 if (!is_in_media_files(path) || !is_in_media_dir(path)) {
780 return SMB_VFS_NEXT_MKDIR(handle, path, mode);
783 clientPath = NULL;
784 ctx = talloc_tos();
786 if ((status = alloc_get_client_path(handle, ctx,
787 path,
788 &clientPath))) {
789 goto err;
792 status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
793 err:
794 TALLOC_FREE(clientPath);
795 DEBUG(10, ("Leaving with path '%s'\n", path));
796 return status;
799 static int um_rmdir(vfs_handle_struct *handle,
800 const char *path)
802 int status;
803 char *clientPath;
804 TALLOC_CTX *ctx;
807 DEBUG(10, ("Entering with path '%s'\n", path));
809 if (!is_in_media_files(path)) {
810 return SMB_VFS_NEXT_RMDIR(handle, path);
813 clientPath = NULL;
814 ctx = talloc_tos();
816 if ((status = alloc_get_client_path(handle, ctx,
817 path,
818 &clientPath))) {
819 goto err;
822 status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
823 err:
824 TALLOC_FREE(clientPath);
825 DEBUG(10, ("Leaving with path '%s'\n", path));
826 return status;
829 static int um_closedir(vfs_handle_struct *handle,
830 DIR *dirp)
832 DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
834 TALLOC_FREE(dirp);
836 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
839 static void um_init_search_op(vfs_handle_struct *handle,
840 DIR *dirp)
842 DEBUG(10, ("Entering and leaving um_init_search_op\n"));
844 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
845 ((um_dirinfo_struct*)dirp)->dirstream);
848 static int um_open(vfs_handle_struct *handle,
849 struct smb_filename *smb_fname,
850 files_struct *fsp,
851 int flags,
852 mode_t mode)
854 int ret;
855 struct smb_filename *client_fname = NULL;
857 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
858 smb_fname->base_name));
860 if (!is_in_media_files(smb_fname->base_name)) {
861 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
864 if (alloc_get_client_smb_fname(handle, talloc_tos(),
865 smb_fname,
866 &client_fname)) {
867 ret = -1;
868 goto err;
872 * FIXME:
873 * What about fsp->fsp_name? We also have to get correct stat
874 * info into fsp and smb_fname for DB files, don't we?
877 DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
878 "smb_fname->st.st_ex_mtime %s"
879 "fsp->fsp_name->st.st_ex_mtime %s",
880 smb_fname->base_name,
881 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
882 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
884 ret = SMB_VFS_NEXT_OPEN(handle, client_fname, fsp, flags, mode);
885 err:
886 TALLOC_FREE(client_fname);
887 DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
888 smb_fname->base_name));
889 return ret;
892 static NTSTATUS um_create_file(vfs_handle_struct *handle,
893 struct smb_request *req,
894 uint16_t root_dir_fid,
895 struct smb_filename *smb_fname,
896 uint32_t access_mask,
897 uint32_t share_access,
898 uint32_t create_disposition,
899 uint32_t create_options,
900 uint32_t file_attributes,
901 uint32_t oplock_request,
902 struct smb2_lease *lease,
903 uint64_t allocation_size,
904 uint32_t private_flags,
905 struct security_descriptor *sd,
906 struct ea_list *ea_list,
907 files_struct **result_fsp,
908 int *pinfo,
909 const struct smb2_create_blobs *in_context_blobs,
910 struct smb2_create_blobs *out_context_blobs)
912 NTSTATUS status;
913 struct smb_filename *client_fname = NULL;
915 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
916 smb_fname->base_name));
918 if (!is_in_media_files(smb_fname->base_name)) {
919 return SMB_VFS_NEXT_CREATE_FILE(
920 handle,
921 req,
922 root_dir_fid,
923 smb_fname,
924 access_mask,
925 share_access,
926 create_disposition,
927 create_options,
928 file_attributes,
929 oplock_request,
930 lease,
931 allocation_size,
932 private_flags,
934 ea_list,
935 result_fsp,
936 pinfo,
937 in_context_blobs,
938 out_context_blobs);
941 if (alloc_get_client_smb_fname(handle, talloc_tos(),
942 smb_fname,
943 &client_fname)) {
944 status = map_nt_error_from_unix(errno);
945 goto err;
949 * FIXME:
950 * This only creates files, so we don't have to worry about
951 * our fake directory stat'ing here. But we still need to
952 * route stat calls for DB files properly, right?
954 status = SMB_VFS_NEXT_CREATE_FILE(
955 handle,
956 req,
957 root_dir_fid,
958 client_fname,
959 access_mask,
960 share_access,
961 create_disposition,
962 create_options,
963 file_attributes,
964 oplock_request,
965 lease,
966 allocation_size,
967 private_flags,
969 ea_list,
970 result_fsp,
971 pinfo,
972 in_context_blobs,
973 out_context_blobs);
974 err:
975 TALLOC_FREE(client_fname);
976 DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
977 "smb_fname->st.st_ex_mtime %s"
978 " fsp->fsp_name->st.st_ex_mtime %s",
979 smb_fname->base_name,
980 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
981 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
982 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
983 "No fsp time\n"));
984 return status;
987 static int um_rename(vfs_handle_struct *handle,
988 const struct smb_filename *smb_fname_src,
989 const struct smb_filename *smb_fname_dst)
991 int status;
992 struct smb_filename *src_client_fname = NULL;
993 struct smb_filename *dst_client_fname = NULL;
995 DEBUG(10, ("Entering with "
996 "smb_fname_src->base_name '%s', "
997 "smb_fname_dst->base_name '%s'\n",
998 smb_fname_src->base_name,
999 smb_fname_dst->base_name));
1001 if (!is_in_media_files(smb_fname_src->base_name)
1003 !is_in_media_files(smb_fname_dst->base_name)) {
1004 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1005 smb_fname_dst);
1008 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1009 smb_fname_src,
1010 &src_client_fname);
1011 if (status != 0) {
1012 goto err;
1015 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1016 smb_fname_dst,
1017 &dst_client_fname);
1019 if (status != 0) {
1020 goto err;
1023 status = SMB_VFS_NEXT_RENAME(handle, src_client_fname,
1024 dst_client_fname);
1025 err:
1026 TALLOC_FREE(dst_client_fname);
1027 TALLOC_FREE(src_client_fname);
1028 DEBUG(10, ("Leaving with smb_fname_src->base_name '%s',"
1029 " smb_fname_dst->base_name '%s'\n",
1030 smb_fname_src->base_name,
1031 smb_fname_dst->base_name));
1032 return status;
1036 * Success: return 0
1037 * Failure: set errno, return -1
1039 static int um_stat(vfs_handle_struct *handle,
1040 struct smb_filename *smb_fname)
1042 int status = 0;
1043 struct smb_filename *client_fname = NULL;
1045 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1046 smb_fname->base_name));
1048 if (!is_in_media_files(smb_fname->base_name)) {
1049 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1052 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1053 smb_fname,
1054 &client_fname);
1055 if (status != 0) {
1056 goto err;
1058 DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1059 client_fname->base_name));
1061 status = SMB_VFS_NEXT_STAT(handle, client_fname);
1062 if (status != 0) {
1063 goto err;
1067 * Unlike functions with const smb_filename, we have to modify
1068 * smb_fname itself to pass our info back up.
1070 DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1071 smb_fname->base_name, client_fname->base_name));
1072 smb_fname->st = client_fname->st;
1074 err:
1075 TALLOC_FREE(client_fname);
1076 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1077 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1078 return status;
1081 static int um_lstat(vfs_handle_struct *handle,
1082 struct smb_filename *smb_fname)
1084 int status = 0;
1085 struct smb_filename *client_fname = NULL;
1087 DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1088 smb_fname->base_name));
1090 if (!is_in_media_files(smb_fname->base_name)) {
1091 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1094 client_fname = NULL;
1096 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1097 smb_fname,
1098 &client_fname);
1099 if (status != 0) {
1100 goto err;
1102 status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1103 if (status != 0) {
1104 goto err;
1107 smb_fname->st = client_fname->st;
1109 err:
1110 TALLOC_FREE(client_fname);
1111 DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1112 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1113 return status;
1116 static int um_fstat(vfs_handle_struct *handle,
1117 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1119 int status = 0;
1121 DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1122 "'%s'\n", fsp_str_dbg(fsp)));
1124 status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1125 if (status != 0) {
1126 goto out;
1129 if ((fsp->fsp_name == NULL) ||
1130 !is_in_media_files(fsp->fsp_name->base_name)) {
1131 goto out;
1134 status = um_stat(handle, fsp->fsp_name);
1135 if (status != 0) {
1136 goto out;
1139 *sbuf = fsp->fsp_name->st;
1141 out:
1142 DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1143 fsp->fsp_name != NULL ?
1144 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1145 return status;
1148 static int um_unlink(vfs_handle_struct *handle,
1149 const struct smb_filename *smb_fname)
1151 int status;
1152 struct smb_filename *client_fname = NULL;
1154 DEBUG(10, ("Entering um_unlink\n"));
1156 if (!is_in_media_files(smb_fname->base_name)) {
1157 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1160 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1161 smb_fname,
1162 &client_fname);
1163 if (status != 0) {
1164 goto err;
1167 status = SMB_VFS_NEXT_UNLINK(handle, client_fname);
1169 err:
1170 TALLOC_FREE(client_fname);
1171 return status;
1174 static int um_chmod(vfs_handle_struct *handle,
1175 const char *path,
1176 mode_t mode)
1178 int status;
1179 char *client_path = NULL;
1181 DEBUG(10, ("Entering um_chmod\n"));
1183 if (!is_in_media_files(path)) {
1184 return SMB_VFS_NEXT_CHMOD(handle, path, mode);
1187 status = alloc_get_client_path(handle, talloc_tos(),
1188 path, &client_path);
1189 if (status != 0) {
1190 goto err;
1193 status = SMB_VFS_NEXT_CHMOD(handle, client_path, mode);
1195 err:
1196 TALLOC_FREE(client_path);
1197 return status;
1200 static int um_chown(vfs_handle_struct *handle,
1201 const char *path,
1202 uid_t uid,
1203 gid_t gid)
1205 int status;
1206 char *client_path = NULL;
1208 DEBUG(10, ("Entering um_chown\n"));
1210 if (!is_in_media_files(path)) {
1211 return SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1214 status = alloc_get_client_path(handle, talloc_tos(),
1215 path, &client_path);
1216 if (status != 0) {
1217 goto err;
1220 status = SMB_VFS_NEXT_CHOWN(handle, client_path, uid, gid);
1222 err:
1223 TALLOC_FREE(client_path);
1224 return status;
1227 static int um_lchown(vfs_handle_struct *handle,
1228 const char *path,
1229 uid_t uid,
1230 gid_t gid)
1232 int status;
1233 char *client_path = NULL;
1235 DEBUG(10, ("Entering um_lchown\n"));
1236 if (!is_in_media_files(path)) {
1237 return SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1240 status = alloc_get_client_path(handle, talloc_tos(),
1241 path, &client_path);
1242 if (status != 0) {
1243 goto err;
1246 status = SMB_VFS_NEXT_LCHOWN(handle, client_path, uid, gid);
1248 err:
1249 TALLOC_FREE(client_path);
1250 return status;
1253 static int um_chdir(vfs_handle_struct *handle,
1254 const char *path)
1256 int status;
1257 char *client_path = NULL;
1259 DEBUG(10, ("Entering um_chdir\n"));
1261 if (!is_in_media_files(path)) {
1262 return SMB_VFS_NEXT_CHDIR(handle, path);
1265 status = alloc_get_client_path(handle, talloc_tos(),
1266 path, &client_path);
1267 if (status != 0) {
1268 goto err;
1271 status = SMB_VFS_NEXT_CHDIR(handle, client_path);
1273 err:
1274 TALLOC_FREE(client_path);
1275 return status;
1278 static int um_ntimes(vfs_handle_struct *handle,
1279 const struct smb_filename *smb_fname,
1280 struct smb_file_time *ft)
1282 int status;
1283 struct smb_filename *client_fname = NULL;
1285 DEBUG(10, ("Entering um_ntimes\n"));
1287 if (!is_in_media_files(smb_fname->base_name)) {
1288 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1291 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1292 smb_fname, &client_fname);
1293 if (status != 0) {
1294 goto err;
1297 status = SMB_VFS_NEXT_NTIMES(handle, client_fname, ft);
1299 err:
1300 TALLOC_FREE(client_fname);
1301 return status;
1304 static int um_symlink(vfs_handle_struct *handle,
1305 const char *oldpath,
1306 const char *newpath)
1308 int status;
1309 char *old_client_path = NULL;
1310 char *new_client_path = NULL;
1312 DEBUG(10, ("Entering um_symlink\n"));
1314 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1315 return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1318 status = alloc_get_client_path(handle, talloc_tos(),
1319 oldpath, &old_client_path);
1320 if (status != 0) {
1321 goto err;
1324 status = alloc_get_client_path(handle, talloc_tos(),
1325 newpath, &new_client_path);
1326 if (status != 0) {
1327 goto err;
1330 status = SMB_VFS_NEXT_SYMLINK(handle,
1331 old_client_path,
1332 new_client_path);
1334 err:
1335 TALLOC_FREE(new_client_path);
1336 TALLOC_FREE(old_client_path);
1337 return status;
1340 static int um_readlink(vfs_handle_struct *handle,
1341 const char *path,
1342 char *buf,
1343 size_t bufsiz)
1345 int status;
1346 char *client_path = NULL;
1348 DEBUG(10, ("Entering um_readlink\n"));
1350 if (!is_in_media_files(path)) {
1351 return SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1354 status = alloc_get_client_path(handle, talloc_tos(),
1355 path, &client_path);
1356 if (status != 0) {
1357 goto err;
1360 status = SMB_VFS_NEXT_READLINK(handle, client_path, buf, bufsiz);
1362 err:
1363 TALLOC_FREE(client_path);
1364 return status;
1367 static int um_link(vfs_handle_struct *handle,
1368 const char *oldpath,
1369 const char *newpath)
1371 int status;
1372 char *old_client_path = NULL;
1373 char *new_client_path = NULL;
1375 DEBUG(10, ("Entering um_link\n"));
1376 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) {
1377 return SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1380 status = alloc_get_client_path(handle, talloc_tos(),
1381 oldpath, &old_client_path);
1382 if (status != 0) {
1383 goto err;
1386 status = alloc_get_client_path(handle, talloc_tos(),
1387 newpath, &new_client_path);
1388 if (status != 0) {
1389 goto err;
1392 status = SMB_VFS_NEXT_LINK(handle, old_client_path, new_client_path);
1394 err:
1395 TALLOC_FREE(new_client_path);
1396 TALLOC_FREE(old_client_path);
1397 return status;
1400 static int um_mknod(vfs_handle_struct *handle,
1401 const char *pathname,
1402 mode_t mode,
1403 SMB_DEV_T dev)
1405 int status;
1406 char *client_path = NULL;
1408 DEBUG(10, ("Entering um_mknod\n"));
1409 if (!is_in_media_files(pathname)) {
1410 return SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1413 status = alloc_get_client_path(handle, talloc_tos(),
1414 pathname, &client_path);
1415 if (status != 0) {
1416 goto err;
1419 status = SMB_VFS_NEXT_MKNOD(handle, client_path, mode, dev);
1421 err:
1422 TALLOC_FREE(client_path);
1423 return status;
1426 static char *um_realpath(vfs_handle_struct *handle,
1427 const char *path)
1429 char *buf = NULL;
1430 char *client_path = NULL;
1431 int status;
1433 DEBUG(10, ("Entering um_realpath\n"));
1435 if (!is_in_media_files(path)) {
1436 return SMB_VFS_NEXT_REALPATH(handle, path);
1439 status = alloc_get_client_path(handle, talloc_tos(),
1440 path, &client_path);
1441 if (status != 0) {
1442 goto err;
1445 buf = SMB_VFS_NEXT_REALPATH(handle, client_path);
1447 err:
1448 TALLOC_FREE(client_path);
1449 return buf;
1452 static int um_chflags(vfs_handle_struct *handle,
1453 const char *path,
1454 unsigned int flags)
1456 int status;
1457 char *client_path = NULL;
1459 DEBUG(10, ("Entering um_chflags\n"));
1461 if (!is_in_media_files(path)) {
1462 return SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1465 status = alloc_get_client_path(handle, talloc_tos(),
1466 path, &client_path);
1467 if (status != 0) {
1468 goto err;
1471 status = SMB_VFS_NEXT_CHFLAGS(handle, client_path, flags);
1472 err:
1473 TALLOC_FREE(client_path);
1474 return status;
1477 static NTSTATUS um_streaminfo(struct vfs_handle_struct *handle,
1478 struct files_struct *fsp,
1479 const char *fname,
1480 TALLOC_CTX *ctx,
1481 unsigned int *num_streams,
1482 struct stream_struct **streams)
1484 NTSTATUS status;
1485 char *client_path = NULL;
1486 int ret;
1488 DEBUG(10, ("Entering um_streaminfo\n"));
1490 if (!is_in_media_files(fname)) {
1491 return SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1492 ctx, num_streams, streams);
1495 ret = alloc_get_client_path(handle, talloc_tos(),
1496 fname, &client_path);
1497 if (ret != 0) {
1498 status = map_nt_error_from_unix(errno);
1499 goto err;
1503 * This only works on files, so we don't have to worry about
1504 * our fake directory stat'ing here. But what does this
1505 * function do, exactly? Does it need extra modifications for
1506 * the Avid stuff?
1508 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, client_path,
1509 ctx, num_streams, streams);
1510 err:
1511 TALLOC_FREE(client_path);
1512 return status;
1516 * Ignoring get_real_filename function because the default doesn't do
1517 * anything.
1520 static NTSTATUS um_get_nt_acl(vfs_handle_struct *handle,
1521 const char *name,
1522 uint32_t security_info,
1523 TALLOC_CTX *mem_ctx,
1524 struct security_descriptor **ppdesc)
1526 NTSTATUS status;
1527 char *client_path = NULL;
1528 int ret;
1530 DEBUG(10, ("Entering um_get_nt_acl\n"));
1532 if (!is_in_media_files(name)) {
1533 return SMB_VFS_NEXT_GET_NT_ACL(handle, name,
1534 security_info,
1535 mem_ctx, ppdesc);
1538 ret = alloc_get_client_path(handle, talloc_tos(),
1539 name, &client_path);
1540 if (ret != 0) {
1541 status = map_nt_error_from_unix(errno);
1542 goto err;
1545 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_path,
1546 security_info,
1547 mem_ctx, ppdesc);
1548 err:
1549 TALLOC_FREE(client_path);
1550 return status;
1553 static int um_chmod_acl(vfs_handle_struct *handle,
1554 const char *path,
1555 mode_t mode)
1557 int status;
1558 char *client_path = NULL;
1560 DEBUG(10, ("Entering um_chmod_acl\n"));
1562 if (!is_in_media_files(path)) {
1563 return SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
1566 status = alloc_get_client_path(handle, talloc_tos(),
1567 path, &client_path);
1568 if (status != 0) {
1569 goto err;
1572 status = SMB_VFS_NEXT_CHMOD_ACL(handle, client_path, mode);
1574 err:
1575 TALLOC_FREE(client_path);
1576 return status;
1579 static SMB_ACL_T um_sys_acl_get_file(vfs_handle_struct *handle,
1580 const char *path_p,
1581 SMB_ACL_TYPE_T type,
1582 TALLOC_CTX *mem_ctx)
1584 SMB_ACL_T ret;
1585 char *client_path = NULL;
1586 int status;
1588 DEBUG(10, ("Entering um_sys_acl_get_file\n"));
1590 if (!is_in_media_files(path_p)) {
1591 return SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p,
1592 type, mem_ctx);
1595 status = alloc_get_client_path(handle, talloc_tos(),
1596 path_p, &client_path);
1597 if (status != 0) {
1598 ret = NULL;
1599 goto err;
1602 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, client_path, type, mem_ctx);
1604 err:
1605 TALLOC_FREE(client_path);
1606 return ret;
1609 static int um_sys_acl_set_file(vfs_handle_struct *handle,
1610 const char *name,
1611 SMB_ACL_TYPE_T acltype,
1612 SMB_ACL_T theacl)
1614 int status;
1615 char *client_path = NULL;
1617 DEBUG(10, ("Entering um_sys_acl_set_file\n"));
1619 if (!is_in_media_files(name)) {
1620 return SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
1621 acltype, theacl);
1624 status = alloc_get_client_path(handle, talloc_tos(),
1625 name, &client_path);
1626 if (status != 0) {
1627 goto err;
1630 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, client_path,
1631 acltype, theacl);
1633 err:
1634 TALLOC_FREE(client_path);
1635 return status;
1638 static int um_sys_acl_delete_def_file(vfs_handle_struct *handle,
1639 const char *path)
1641 int status;
1642 char *client_path = NULL;
1644 DEBUG(10, ("Entering um_sys_acl_delete_def_file\n"));
1646 if (!is_in_media_files(path)) {
1647 return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, path);
1650 status = alloc_get_client_path(handle, talloc_tos(),
1651 path, &client_path);
1652 if (status != 0) {
1653 goto err;
1656 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, client_path);
1658 err:
1659 TALLOC_FREE(client_path);
1660 return status;
1663 static ssize_t um_getxattr(struct vfs_handle_struct *handle,
1664 const char *path,
1665 const char *name,
1666 void *value,
1667 size_t size)
1669 ssize_t ret;
1670 char *client_path = NULL;
1671 int status;
1673 DEBUG(10, ("Entering um_getxattr\n"));
1674 if (!is_in_media_files(path)) {
1675 return SMB_VFS_NEXT_GETXATTR(handle, path, name, value, size);
1678 status = alloc_get_client_path(handle, talloc_tos(),
1679 path, &client_path);
1680 if (status != 0) {
1681 ret = -1;
1682 goto err;
1685 ret = SMB_VFS_NEXT_GETXATTR(handle, client_path, name, value, size);
1686 err:
1687 TALLOC_FREE(client_path);
1688 return ret;
1691 static ssize_t um_listxattr(struct vfs_handle_struct *handle,
1692 const char *path,
1693 char *list,
1694 size_t size)
1696 ssize_t ret;
1697 char *client_path = NULL;
1698 int status;
1700 DEBUG(10, ("Entering um_listxattr\n"));
1702 if (!is_in_media_files(path)) {
1703 return SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
1706 status = alloc_get_client_path(handle, talloc_tos(),
1707 path, &client_path);
1708 if (status != 0) {
1709 ret = -1;
1710 goto err;
1713 ret = SMB_VFS_NEXT_LISTXATTR(handle, client_path, list, size);
1715 err:
1716 TALLOC_FREE(client_path);
1717 return ret;
1720 static int um_removexattr(struct vfs_handle_struct *handle,
1721 const char *path,
1722 const char *name)
1724 int status;
1725 char *client_path = NULL;
1727 DEBUG(10, ("Entering um_removexattr\n"));
1729 if (!is_in_media_files(path)) {
1730 return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
1733 status = alloc_get_client_path(handle, talloc_tos(),
1734 path, &client_path);
1735 if (status != 0) {
1736 goto err;
1739 status = SMB_VFS_NEXT_REMOVEXATTR(handle, client_path, name);
1741 err:
1742 TALLOC_FREE(client_path);
1743 return status;
1746 static int um_setxattr(struct vfs_handle_struct *handle,
1747 const char *path,
1748 const char *name,
1749 const void *value,
1750 size_t size,
1751 int flags)
1753 int status;
1754 char *client_path = NULL;
1756 DEBUG(10, ("Entering um_setxattr\n"));
1758 if (!is_in_media_files(path)) {
1759 return SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
1760 size, flags);
1763 status = alloc_get_client_path(handle, talloc_tos(),
1764 path, &client_path);
1765 if (status != 0) {
1766 goto err;
1769 status = SMB_VFS_NEXT_SETXATTR(handle, client_path, name, value,
1770 size, flags);
1772 err:
1773 TALLOC_FREE(client_path);
1774 return status;
1777 static bool um_is_offline(struct vfs_handle_struct *handle,
1778 const struct smb_filename *fname,
1779 SMB_STRUCT_STAT *sbuf)
1781 bool ret;
1782 struct smb_filename *client_fname = NULL;
1783 int status;
1785 DEBUG(10, ("Entering um_is_offline\n"));
1787 if (!is_in_media_files(fname->base_name)) {
1788 return SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
1791 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1792 fname, &client_fname);
1793 if (status != 0) {
1794 ret = false;
1795 goto err;
1798 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, client_fname, sbuf);
1800 err:
1801 TALLOC_FREE(client_fname);
1802 return ret;
1805 static int um_set_offline(struct vfs_handle_struct *handle,
1806 const struct smb_filename *fname)
1808 int status;
1809 struct smb_filename *client_fname = NULL;
1811 DEBUG(10, ("Entering um_set_offline\n"));
1813 if (!is_in_media_files(fname->base_name)) {
1814 return SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
1817 status = alloc_get_client_smb_fname(handle, talloc_tos(),
1818 fname, &client_fname);
1819 if (status != 0) {
1820 goto err;
1823 status = SMB_VFS_NEXT_SET_OFFLINE(handle, client_fname);
1825 err:
1826 TALLOC_FREE(client_fname);
1827 return status;
1830 static int um_connect(vfs_handle_struct *handle,
1831 const char *service,
1832 const char *user)
1834 int rc;
1835 struct um_config_data *config;
1836 int enumval;
1838 rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1839 if (rc != 0) {
1840 return rc;
1843 config = talloc_zero(handle->conn, struct um_config_data);
1844 if (!config) {
1845 DEBUG(1, ("talloc_zero() failed\n"));
1846 errno = ENOMEM;
1847 return -1;
1850 enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1851 "clientid", um_clientid, UM_CLIENTID_NAME);
1852 if (enumval == -1) {
1853 DEBUG(1, ("value for %s: type unknown\n",
1854 UM_PARAM_TYPE_NAME));
1855 return -1;
1857 config->clientid = (enum um_clientid)enumval;
1859 SMB_VFS_HANDLE_SET_DATA(handle, config,
1860 NULL, struct um_config_data,
1861 return -1);
1863 return 0;
1866 /* VFS operations structure */
1868 static struct vfs_fn_pointers vfs_um_fns = {
1869 .connect_fn = um_connect,
1871 /* Disk operations */
1873 .statvfs_fn = um_statvfs,
1875 /* Directory operations */
1877 .opendir_fn = um_opendir,
1878 .fdopendir_fn = um_fdopendir,
1879 .readdir_fn = um_readdir,
1880 .seekdir_fn = um_seekdir,
1881 .telldir_fn = um_telldir,
1882 .rewind_dir_fn = um_rewinddir,
1883 .mkdir_fn = um_mkdir,
1884 .rmdir_fn = um_rmdir,
1885 .closedir_fn = um_closedir,
1886 .init_search_op_fn = um_init_search_op,
1888 /* File operations */
1890 .open_fn = um_open,
1891 .create_file_fn = um_create_file,
1892 .rename_fn = um_rename,
1893 .stat_fn = um_stat,
1894 .lstat_fn = um_lstat,
1895 .fstat_fn = um_fstat,
1896 .unlink_fn = um_unlink,
1897 .chmod_fn = um_chmod,
1898 .chown_fn = um_chown,
1899 .lchown_fn = um_lchown,
1900 .chdir_fn = um_chdir,
1901 .ntimes_fn = um_ntimes,
1902 .symlink_fn = um_symlink,
1903 .readlink_fn = um_readlink,
1904 .link_fn = um_link,
1905 .mknod_fn = um_mknod,
1906 .realpath_fn = um_realpath,
1907 .chflags_fn = um_chflags,
1908 .streaminfo_fn = um_streaminfo,
1910 /* NT ACL operations. */
1912 .get_nt_acl_fn = um_get_nt_acl,
1914 /* POSIX ACL operations. */
1916 .chmod_acl_fn = um_chmod_acl,
1918 .sys_acl_get_file_fn = um_sys_acl_get_file,
1919 .sys_acl_set_file_fn = um_sys_acl_set_file,
1920 .sys_acl_delete_def_file_fn = um_sys_acl_delete_def_file,
1922 /* EA operations. */
1923 .getxattr_fn = um_getxattr,
1924 .listxattr_fn = um_listxattr,
1925 .removexattr_fn = um_removexattr,
1926 .setxattr_fn = um_setxattr,
1928 /* aio operations */
1930 /* offline operations */
1931 .is_offline_fn = um_is_offline,
1932 .set_offline_fn = um_set_offline
1935 NTSTATUS vfs_unityed_media_init(void);
1936 NTSTATUS vfs_unityed_media_init(void)
1938 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1939 "unityed_media", &vfs_um_fns);
1940 if (!NT_STATUS_IS_OK(ret)) {
1941 return ret;
1944 vfs_um_debug_level = debug_add_class("unityed_media");
1946 if (vfs_um_debug_level == -1) {
1947 vfs_um_debug_level = DBGC_VFS;
1948 DEBUG(1, ("unityed_media_init: Couldn't register custom "
1949 "debugging class.\n"));
1952 return ret;