s3: VFS: Change SMB_VFS_CHDIR to use const struct smb_filename * instead of const...
[Samba.git] / source3 / modules / vfs_media_harmony.c
blobbd774b839098f4d55bf06e846674ddb840a0df92
1 /*
2 * $Id: media_harmony.c,v 1.1 2007/11/06 10:07:22 stuart_hc Exp $
4 * Samba VFS module supporting multiple AVID clients sharing media.
6 * Copyright (C) 2005 Philip de Nier <philipn@users.sourceforge.net>
7 * Copyright (C) 2012 Andrew Klaassen <clawsoon@yahoo.com>
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.
27 * Media Harmony is a Samba VFS module that allows multiple AVID
28 * clients to share media. Each client sees their own copy of the
29 * AVID msmMMOB.mdb and msmFMID.pmr files and Creating directories.
31 * Add this module to the vfs objects option in your Samba share
32 * configuration.
33 * eg.
35 * [avid_win]
36 * path = /video
37 * vfs objects = media_harmony
38 * ...
40 * It is recommended that you separate out Samba shares for Mac
41 * and Windows clients, and add the following options to the shares
42 * for Windows clients (NOTE: replace @ with *):
44 * veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
45 * delete veto files = yes
47 * This prevents hidden files from Mac clients interfering with Windows
48 * clients. If you find any more problem hidden files then add them to
49 * the list.
52 * Andrew Klaassen, 2012-03-14
53 * To prevent Avid clients from interrupting each other (via Avid's habit
54 * of launching a database refresh whenever it notices an mtime update
55 * on media directories, i.e. whenever one editor adds new material to a
56 * shared share), I've added code that causes stat information for anything
57 * directly under "Avid MediaFile/MXF" to be taken from
58 * dirname_clientaddr_clientuser if it exists. These files ~aren't~
59 * hidden, unlike the client-suffixed database files.
61 * For example, stat information for
62 * Avid MediaFiles/MXF/1
63 * will come from
64 * Avid MediaFiles/MXF/1_192.168.1.10_dave
65 * for dave working on 192.168.1.10, but will come from
66 * Avid MediaFile/MXF/1_192.168.1.11_susan
67 * for susan working on 192.168.1.11. If those alternate
68 * directories don't exist, the user will get the actual directory's stat
69 * info. When an editor wants to force a database refresh, they update
70 * the mtime on "their" file. This will cause Avid
71 * on that client to see an updated mtime for "Avid MediaFiles/MXF/1",
72 * which will trigger an Avid database refresh just for that editor.
75 * Notes:
76 * - This module is designed to work with AVID editing applications that
77 * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
78 * It is not designed to work as expected in all circumstances for
79 * general use. For example: it is possibly to open client specific
80 * files such as msmMMOB.mdb_192.168.1.10_userx even though is doesn't
81 * show up in a directory listing.
86 #include "includes.h"
87 #include "system/filesys.h"
88 #include "smbd/smbd.h"
89 #include "../smbd/globals.h"
90 #include "auth.h"
91 #include "../lib/tsocket/tsocket.h"
93 #define MH_INFO_DEBUG 10
94 #define MH_ERR_DEBUG 0
96 static const char* MDB_FILENAME = "msmMMOB.mdb";
97 static const size_t MDB_FILENAME_LEN = 11;
98 static const char* PMR_FILENAME = "msmFMID.pmr";
99 static const size_t PMR_FILENAME_LEN = 11;
100 static const char* CREATING_DIRNAME = "Creating";
101 static const size_t CREATING_DIRNAME_LEN = 8;
102 static const char* AVID_MEDIAFILES_DIRNAME = "Avid MediaFiles";
103 static const size_t AVID_MEDIAFILES_DIRNAME_LEN = 15;
104 static const char* OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
105 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
106 static const char* APPLE_DOUBLE_PREFIX = "._";
107 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
108 static const char* AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
109 static const size_t AVID_MXF_DIRNAME_LEN = 19;
111 static int vfs_mh_debug_level = DBGC_VFS;
113 /* supplements the directory list stream */
114 typedef struct mh_dirinfo_struct
116 DIR* dirstream;
117 char *dirpath;
118 char *clientPath;
119 bool isInMediaFiles;
120 char *clientMDBFilename;
121 char *clientPMRFilename;
122 char *clientCreatingDirname;
123 } mh_dirinfo_struct;
126 /* Add "_<ip address>_<user name>" suffix to path or filename.
128 * Success: return 0
129 * Failure: set errno, path NULL, return -1
131 static int alloc_append_client_suffix(vfs_handle_struct *handle,
132 char **path)
134 int status = 0;
135 char *raddr = NULL;
137 DEBUG(MH_INFO_DEBUG, ("Entering with *path '%s'\n", *path));
139 raddr = tsocket_address_inet_addr_string(
140 handle->conn->sconn->remote_address, talloc_tos());
141 if (raddr == NULL)
143 errno = ENOMEM;
144 status = -1;
145 goto err;
148 /* talloc_asprintf_append uses talloc_realloc, which
149 * frees original 'path' memory so we don't have to.
151 *path = talloc_asprintf_append(*path, "_%s_%s",
152 raddr,
153 handle->conn->session_info->unix_info->sanitized_username);
154 if (*path == NULL)
156 DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
157 "out of memory\n"));
158 errno = ENOMEM;
159 status = -1;
160 goto err;
162 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
163 err:
164 TALLOC_FREE(raddr);
165 return status;
169 /* Returns True if the file or directory begins with the appledouble
170 * prefix.
172 static bool is_apple_double(const char* fname)
174 bool ret = False;
176 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
178 if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
179 == 0)
181 ret = True;
183 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
184 ret == True ? "True" : "False"));
185 return ret;
188 static bool starts_with_media_dir(const char* media_dirname,
189 size_t media_dirname_len, const char* path)
191 bool ret = False;
192 const char *path_start;
194 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
195 "path '%s'\n", media_dirname, path));
197 /* Sometimes Samba gives us "./OMFI MediaFiles". */
198 if (strncmp(path, "./", 2) == 0)
200 path_start = &path[2];
202 else {
203 path_start = path;
206 if (strncmp(media_dirname, path_start, media_dirname_len) == 0
209 path_start[media_dirname_len] == '\0'
211 path_start[media_dirname_len] == '/'
215 ret = True;
218 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
219 ret == True ? "True" : "False"));
220 return ret;
224 * Returns True if the file or directory referenced by the path is below
225 * the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME directory
226 * The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME are assumed to
227 * be in the root directory, which is generally a safe assumption
228 * in the fixed-path world of Avid.
230 static bool is_in_media_files(const char* path)
232 bool ret = False;
234 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
236 if (
237 starts_with_media_dir(AVID_MEDIAFILES_DIRNAME,
238 AVID_MEDIAFILES_DIRNAME_LEN, path)
240 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
241 OMFI_MEDIAFILES_DIRNAME_LEN, path)
244 ret = True;
246 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
247 ret == True ? "True" : "False"));
248 return ret;
252 * Returns depth of path under media directory. Deals with the
253 * occasional ..../. and ..../.. paths that get passed to stat.
255 * Assumes is_in_media_files has already been called and has returned
256 * true for the path; if it hasn't, this function will likely crash
257 * and burn.
259 * Not foolproof; something like "Avid MediaFiles/MXF/../foo/1"
260 * would fool it. Haven't seen paths like that getting to the
261 * stat function yet, so ignoring that possibility for now.
263 static int depth_from_media_dir(const char* media_dirname,
264 size_t media_dirname_len, const char* path)
266 int transition_count = 0;
267 const char *path_start;
268 const char *pathPtr;
270 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
271 "path '%s'\n", media_dirname, path));
273 /* Sometimes Samba gives us "./OMFI MediaFiles". */
274 if (strncmp(path, "./", 2) == 0)
276 path_start = &path[2];
278 else {
279 path_start = path;
282 if (path_start[media_dirname_len] == '\0')
284 goto out;
287 pathPtr = &path_start[media_dirname_len + 1];
289 while(1)
291 if (*pathPtr == '\0' || *pathPtr == '/')
293 if (
294 *(pathPtr - 1) == '.'
296 *(pathPtr - 2) == '.'
298 *(pathPtr - 3) == '/'
301 transition_count--;
303 else if (
306 *(pathPtr - 1) == '/'
309 *(pathPtr - 1) == '.'
311 *(pathPtr - 2) == '/'
316 transition_count++;
319 if (*pathPtr == '\0')
321 break;
323 pathPtr++;
326 DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
327 transition_count));
328 out:
329 return transition_count;
332 /* Identifies MDB and PMR files at end of path. */
333 static bool is_avid_database(
334 char *path,
335 size_t path_len,
336 const char *avid_db_filename,
337 const size_t avid_db_filename_len)
339 bool ret = False;
341 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
342 "avid_db_filename '%s', "
343 "path_len '%i', "
344 "avid_db_filename_len '%i'\n",
345 path, avid_db_filename,
346 (int)path_len, (int)avid_db_filename_len));
348 if (
349 path_len > avid_db_filename_len
351 strcmp(&path[path_len - avid_db_filename_len],
352 avid_db_filename) == 0
355 path[path_len - avid_db_filename_len - 1] == '/'
357 (path_len > avid_db_filename_len
358 + APPLE_DOUBLE_PREFIX_LEN
360 path[path_len - avid_db_filename_len
361 - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
363 is_apple_double(&path[path_len
364 - avid_db_filename_len
365 - APPLE_DOUBLE_PREFIX_LEN]))
369 ret = True;
371 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
372 ret == True ? "True" : "False"));
373 return ret;
377 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
378 * CREATING_SUBDIRNAME.
380 * Caller must free newPath.
382 * Success: return 0
383 * Failure: set errno, newPath NULL, return -1
385 static int alloc_get_client_path(vfs_handle_struct *handle,
386 TALLOC_CTX *ctx,
387 const char *path,
388 char **newPath)
390 /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
391 * directory in path - potentially in middle of path
392 * - with suffixed name.
394 int status = 0;
395 char* pathPtr;
396 size_t intermPathLen;
398 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
400 *newPath = talloc_strdup(ctx, path);
401 if (*newPath == NULL)
403 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
404 errno = ENOMEM;
405 status = -1;
406 goto out;
408 DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
409 if (
410 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
413 *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
415 *(pathPtr + CREATING_DIRNAME_LEN) == '/'
419 (pathPtr - path > 0
421 *(pathPtr - 1) == '/')
423 (pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
425 *(pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1) == '/'
427 is_apple_double(pathPtr - APPLE_DOUBLE_PREFIX_LEN))
431 /* Insert client suffix into path. */
432 (*newPath)[pathPtr - path + CREATING_DIRNAME_LEN] = '\0';
433 DEBUG(MH_INFO_DEBUG, ("newPath #2 %s\n", *newPath));
435 if ((status = alloc_append_client_suffix(handle, newPath)))
437 goto out;
440 DEBUG(MH_INFO_DEBUG, ("newPath #3 %s\n", *newPath));
441 *newPath = talloc_strdup_append(*newPath,
442 pathPtr + CREATING_DIRNAME_LEN);
443 if (*newPath == NULL)
445 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path "
446 "ENOMEM #2\n"));
447 errno = ENOMEM;
448 status = -1;
449 goto out;
451 DEBUG(MH_INFO_DEBUG, ("newPath #4 %s\n", *newPath));
454 /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
455 * or /._PMR_FILENAME at newPath end with suffixed name.
457 intermPathLen = strlen(*newPath);
458 if (
459 is_avid_database(*newPath, intermPathLen,
460 MDB_FILENAME, MDB_FILENAME_LEN)
462 is_avid_database(*newPath, intermPathLen,
463 PMR_FILENAME, PMR_FILENAME_LEN)
466 DEBUG(MH_INFO_DEBUG, ("newPath #5 %s\n", *newPath));
467 if ((status = alloc_append_client_suffix(handle, newPath)))
469 goto out;
471 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
473 out:
474 /* newPath must be freed in caller. */
475 DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
476 return status;
480 * Success: return 0
481 * Failure: set errno, return -1
483 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
484 TALLOC_CTX *ctx,
485 const struct smb_filename *smb_fname,
486 struct smb_filename **clientFname)
488 int status = 0;
490 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
491 smb_fname->base_name));
493 *clientFname = cp_smb_filename(ctx, smb_fname);
494 if ((*clientFname) == NULL) {
495 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
496 "NTERR\n"));
497 errno = ENOMEM;
498 status = -1;
499 goto err;
501 if ((status = alloc_get_client_path(handle, ctx,
502 smb_fname->base_name,
503 &(*clientFname)->base_name)))
505 goto err;
507 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
508 "'%s'\n", (*clientFname)->base_name));
509 err:
510 return status;
515 * Success: return 0
516 * Failure: set errno, return -1
518 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
519 TALLOC_CTX *ctx,
520 char **path,
521 const char *avid_db_filename)
523 int status = 0;
525 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
526 avid_db_filename));
528 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
530 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
531 "ENOMEM\n"));
532 errno = ENOMEM;
533 status = -1;
534 goto err;
536 if ((status = alloc_append_client_suffix(handle, path)))
538 goto err;
540 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
541 err:
542 return status;
546 * Replace mtime on clientFname with mtime from client-suffixed
547 * equivalent, if it exists.
549 * Success: return 0
550 * Failure: set errno, return -1
552 static int set_fake_mtime(vfs_handle_struct *handle,
553 TALLOC_CTX *ctx,
554 struct smb_filename **clientFname,
555 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
557 int status = 0;
558 char *statPath;
559 SMB_STRUCT_STAT fakeStat;
560 int copy_len;
562 DEBUG(MH_INFO_DEBUG, ("Entering with (*clientFname)->base_name "
563 "'%s', (*clientFname)->st.st_ex_mtime %s",
564 (*clientFname)->base_name,
565 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
567 if (
568 depth_from_media_dir(AVID_MXF_DIRNAME,
569 AVID_MXF_DIRNAME_LEN,
570 (*clientFname)->base_name)
571 != 1
573 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
574 OMFI_MEDIAFILES_DIRNAME_LEN,
575 (*clientFname)->base_name)
576 != 0
579 goto out;
582 copy_len = strlen((*clientFname)->base_name);
584 /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
585 * We know we're under a media dir, so paths are at least 2 chars
586 * long.
588 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
589 (*clientFname)->base_name[copy_len - 2] == '/')
591 copy_len -= 2;
594 if (((statPath = talloc_strndup(ctx,
595 (*clientFname)->base_name, copy_len)) == NULL))
597 errno = ENOMEM;
598 status = -1;
599 goto err;
601 if ((status = alloc_append_client_suffix(handle, &statPath)))
603 goto err;
606 DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
607 if (statFn(statPath, &fakeStat,
608 lp_fake_directory_create_times(SNUM(handle->conn))))
610 /* This can fail for legitimate reasons - i.e. the
611 * fakeStat directory doesn't exist, which is okay
612 * - so we don't set status. But if it does fail,
613 * we need to skip over the mtime assignment.
615 goto err;
618 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
619 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
620 err:
621 TALLOC_FREE(statPath);
622 out:
623 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
624 "'%s', (*clientFname)->st.st_ex_mtime %s",
625 (*clientFname)->base_name,
626 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
627 return status;
631 * Success: return 0
632 * Failure: set errno, return -1
634 static int mh_statvfs(struct vfs_handle_struct *handle,
635 const struct smb_filename *smb_fname,
636 struct vfs_statvfs_struct *statbuf)
638 int status;
639 struct smb_filename *clientFname = NULL;
641 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n",
642 smb_fname->base_name));
644 if (!is_in_media_files(smb_fname->base_name))
646 status = SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
647 goto out;
650 status = alloc_get_client_smb_fname(handle,
651 talloc_tos(),
652 smb_fname,
653 &clientFname);
654 if (status != 0) {
655 goto err;
658 status = SMB_VFS_NEXT_STATVFS(handle, clientFname, statbuf);
659 err:
660 TALLOC_FREE(clientFname);
661 out:
662 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n",
663 smb_fname->base_name));
664 return status;
667 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
668 const char *fname,
669 struct mh_dirinfo_struct **dirInfo)
671 int status = 0;
672 char *clientPath;
673 TALLOC_CTX *ctx;
675 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
677 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
678 if (*dirInfo == NULL)
680 goto err;
683 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
684 if ((*dirInfo)->dirpath == NULL)
686 goto err;
689 if (!is_in_media_files(fname))
691 (*dirInfo)->clientPath = NULL;
692 (*dirInfo)->clientMDBFilename = NULL;
693 (*dirInfo)->clientPMRFilename = NULL;
694 (*dirInfo)->clientCreatingDirname = NULL;
695 (*dirInfo)->isInMediaFiles = False;
696 goto out;
699 (*dirInfo)->isInMediaFiles = True;
701 if (alloc_set_client_dirinfo_path(handle,
702 *dirInfo,
703 &((*dirInfo)->clientMDBFilename),
704 MDB_FILENAME))
706 goto err;
709 if (alloc_set_client_dirinfo_path(handle,
710 *dirInfo,
711 &((*dirInfo)->clientPMRFilename),
712 PMR_FILENAME))
714 goto err;
717 if (alloc_set_client_dirinfo_path(handle,
718 *dirInfo,
719 &((*dirInfo)->clientCreatingDirname),
720 CREATING_DIRNAME))
722 goto err;
725 clientPath = NULL;
726 ctx = talloc_tos();
728 if (alloc_get_client_path(handle, ctx,
729 fname,
730 &clientPath))
732 goto err;
735 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
736 if ((*dirInfo)->clientPath == NULL)
738 goto err;
741 TALLOC_FREE(clientPath);
743 out:
744 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
745 "(*dirInfo)->clientPath '%s'\n",
746 (*dirInfo)->dirpath,
747 (*dirInfo)->clientPath));
748 return status;
750 err:
751 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
752 TALLOC_FREE(*dirInfo);
753 status = -1;
754 errno = ENOMEM;
755 return status;
758 /* Success: return a mh_dirinfo_struct cast as a DIR
759 * Failure: set errno, return NULL
761 static DIR *mh_opendir(vfs_handle_struct *handle,
762 const struct smb_filename *smb_fname,
763 const char *mask,
764 uint32_t attr)
766 struct mh_dirinfo_struct *dirInfo;
768 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n",
769 smb_fname->base_name));
771 if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo))
773 goto err;
776 if (!dirInfo->isInMediaFiles)
778 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
779 smb_fname, mask, attr);
780 } else {
781 struct smb_filename *smb_fname_clientpath =
782 synthetic_smb_fname(talloc_tos(),
783 dirInfo->clientPath,
784 NULL,
785 NULL,
786 smb_fname->flags);
787 if (smb_fname_clientpath == NULL) {
788 goto err;
791 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
792 smb_fname_clientpath, mask, attr);
793 TALLOC_FREE(smb_fname_clientpath);
796 if (dirInfo->dirstream == NULL) {
797 goto err;
800 /* Success is freed in closedir. */
801 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
802 "dirInfo->clientPath '%s'\n",
803 dirInfo->dirpath,
804 dirInfo->clientPath));
805 return (DIR*)dirInfo;
806 err:
807 /* Failure is freed here. */
808 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n",
809 smb_fname->base_name));
810 TALLOC_FREE(dirInfo);
811 return NULL;
814 static DIR *mh_fdopendir(vfs_handle_struct *handle,
815 files_struct *fsp,
816 const char *mask,
817 uint32_t attr)
819 struct mh_dirinfo_struct *dirInfo = NULL;
820 DIR *dirstream;
822 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
823 fsp->fsp_name->base_name));
825 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
826 if (!dirstream)
828 goto err;
831 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
832 &dirInfo))
834 goto err;
837 dirInfo->dirstream = dirstream;
839 if (! dirInfo->isInMediaFiles) {
840 goto out;
843 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
845 goto err;
848 out:
849 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
850 "dirInfo->clientPath '%s', "
851 "fsp->fsp_name->st.st_ex_mtime %s",
852 dirInfo->dirpath,
853 dirInfo->clientPath,
854 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
855 /* Success is freed in closedir. */
856 return (DIR *) dirInfo;
857 err:
858 /* Failure is freed here. */
859 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
860 fsp->fsp_name->base_name));
861 TALLOC_FREE(dirInfo);
862 return NULL;
866 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
867 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
868 * filenames and CREATING_DIRNAME directory, replace this client's
869 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
870 * directory with non suffixed.
872 * Success: return dirent
873 * End of data: return NULL
874 * Failure: set errno, return NULL
876 static struct dirent *mh_readdir(vfs_handle_struct *handle,
877 DIR *dirp,
878 SMB_STRUCT_STAT *sbuf)
880 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
881 struct dirent *d = NULL;
882 int skip;
884 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
886 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
887 "dirInfo->clientPath '%s', "
888 "dirInfo->isInMediaFiles '%s', "
889 "dirInfo->clientMDBFilename '%s', "
890 "dirInfo->clientPMRFilename '%s', "
891 "dirInfo->clientCreatingDirname '%s'\n",
892 dirInfo->dirpath,
893 dirInfo->clientPath,
894 dirInfo->isInMediaFiles ? "True" : "False",
895 dirInfo->clientMDBFilename,
896 dirInfo->clientPMRFilename,
897 dirInfo->clientCreatingDirname));
899 if (! dirInfo->isInMediaFiles)
901 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
902 goto out;
907 const char* dname;
908 bool isAppleDouble;
910 skip = False;
911 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
913 if (d == NULL)
915 break;
918 /* ignore apple double prefix for logic below */
919 if (is_apple_double(d->d_name))
921 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
922 isAppleDouble = True;
924 else
926 dname = d->d_name;
927 isAppleDouble = False;
930 /* skip Avid-special files with no client suffix */
931 if (
932 strcmp(dname, MDB_FILENAME) == 0
934 strcmp(dname, PMR_FILENAME) == 0
936 strcmp(dname, CREATING_DIRNAME) == 0
939 skip = True;
941 /* chop client suffix off this client's suffixed files */
942 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
944 if (isAppleDouble)
946 d->d_name[MDB_FILENAME_LEN
947 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
949 else
951 d->d_name[MDB_FILENAME_LEN] = '\0';
954 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
956 if (isAppleDouble)
958 d->d_name[PMR_FILENAME_LEN
959 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
961 else
963 d->d_name[PMR_FILENAME_LEN] = '\0';
966 else if (strcmp(dname, dirInfo->clientCreatingDirname)
967 == 0)
969 if (isAppleDouble)
971 d->d_name[CREATING_DIRNAME_LEN
972 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
974 else
976 d->d_name[CREATING_DIRNAME_LEN] = '\0';
980 * Anything that starts as an Avid-special file
981 * that's made it this far should be skipped. This
982 * is different from the original behaviour, which
983 * only skipped other client's suffixed files.
985 else if (
986 strncmp(MDB_FILENAME, dname,
987 MDB_FILENAME_LEN) == 0
989 strncmp(PMR_FILENAME, dname,
990 PMR_FILENAME_LEN) == 0
992 strncmp(CREATING_DIRNAME, dname,
993 CREATING_DIRNAME_LEN) == 0
996 skip = True;
999 while (skip);
1001 out:
1002 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
1003 return d;
1007 * Success: no success result defined.
1008 * Failure: no failure result defined.
1010 static void mh_seekdir(vfs_handle_struct *handle,
1011 DIR *dirp,
1012 long offset)
1014 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1015 SMB_VFS_NEXT_SEEKDIR(handle,
1016 ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1020 * Success: return long
1021 * Failure: no failure result defined.
1023 static long mh_telldir(vfs_handle_struct *handle,
1024 DIR *dirp)
1026 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1027 return SMB_VFS_NEXT_TELLDIR(handle,
1028 ((mh_dirinfo_struct*)dirp)->dirstream);
1032 * Success: no success result defined.
1033 * Failure: no failure result defined.
1035 static void mh_rewinddir(vfs_handle_struct *handle,
1036 DIR *dirp)
1038 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1039 SMB_VFS_NEXT_REWINDDIR(handle,
1040 ((mh_dirinfo_struct*)dirp)->dirstream);
1044 * Success: return 0
1045 * Failure: set errno, return -1
1047 static int mh_mkdir(vfs_handle_struct *handle,
1048 const struct smb_filename *smb_fname,
1049 mode_t mode)
1051 int status;
1052 struct smb_filename *clientFname = NULL;
1053 const char *path = smb_fname->base_name;
1055 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1057 if (!is_in_media_files(path))
1059 status = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1060 goto out;
1063 status = alloc_get_client_smb_fname(handle,
1064 talloc_tos(),
1065 smb_fname,
1066 &clientFname);
1067 if (status != 0) {
1068 goto err;
1071 status = SMB_VFS_NEXT_MKDIR(handle, clientFname, mode);
1072 err:
1073 TALLOC_FREE(clientFname);
1074 out:
1075 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1076 return status;
1080 * Success: return 0
1081 * Failure: set errno, return -1
1083 static int mh_rmdir(vfs_handle_struct *handle,
1084 const struct smb_filename *smb_fname)
1086 int status;
1087 struct smb_filename *clientFname = NULL;
1088 const char *path = smb_fname->base_name;
1090 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1092 if (!is_in_media_files(path))
1094 status = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1095 goto out;
1098 status = alloc_get_client_smb_fname(handle,
1099 talloc_tos(),
1100 smb_fname,
1101 &clientFname);
1102 if (status != 0) {
1103 goto err;
1106 status = SMB_VFS_NEXT_RMDIR(handle, clientFname);
1107 err:
1108 TALLOC_FREE(clientFname);
1109 out:
1110 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1111 return status;
1115 * Success: return 0
1116 * Failure: set errno, return -1
1118 static int mh_closedir(vfs_handle_struct *handle,
1119 DIR *dirp)
1121 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1123 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1124 // Will this talloc_free destroy realdirp?
1125 TALLOC_FREE(dirp);
1127 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1128 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1132 * Success: no success result defined.
1133 * Failure: no failure result defined.
1135 static void mh_init_search_op(vfs_handle_struct *handle,
1136 DIR *dirp)
1138 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1139 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1140 ((mh_dirinfo_struct*)dirp)->dirstream);
1144 * Success: return non-negative file descriptor
1145 * Failure: set errno, return -1
1147 static int mh_open(vfs_handle_struct *handle,
1148 struct smb_filename *smb_fname,
1149 files_struct *fsp,
1150 int flags,
1151 mode_t mode)
1153 int ret;
1154 struct smb_filename *clientFname;
1155 TALLOC_CTX *ctx;
1158 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1159 smb_fname->base_name));
1161 if (!is_in_media_files(smb_fname->base_name))
1163 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1164 mode);
1165 goto out;
1168 clientFname = NULL;
1169 ctx = talloc_tos();
1171 if(alloc_get_client_smb_fname(handle, ctx,
1172 smb_fname,
1173 &clientFname))
1175 ret = -1;
1176 goto err;
1179 // What about fsp->fsp_name?
1180 // We also have to get correct stat info into fsp and smb_fname
1181 // for DB files, don't we?
1183 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1184 "smb_fname->st.st_ex_mtime %s"
1185 " fsp->fsp_name->st.st_ex_mtime %s",
1186 smb_fname->base_name,
1187 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1188 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1190 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1191 err:
1192 TALLOC_FREE(clientFname);
1193 out:
1194 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1195 smb_fname->base_name));
1196 return ret;
1200 * Success: return non-negative file descriptor
1201 * Failure: set errno, return -1
1203 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1204 struct smb_request *req,
1205 uint16_t root_dir_fid,
1206 struct smb_filename *smb_fname,
1207 uint32_t access_mask,
1208 uint32_t share_access,
1209 uint32_t create_disposition,
1210 uint32_t create_options,
1211 uint32_t file_attributes,
1212 uint32_t oplock_request,
1213 struct smb2_lease *lease,
1214 uint64_t allocation_size,
1215 uint32_t private_flags,
1216 struct security_descriptor *sd,
1217 struct ea_list *ea_list,
1218 files_struct **result_fsp,
1219 int *pinfo,
1220 const struct smb2_create_blobs *in_context_blobs,
1221 struct smb2_create_blobs *out_context_blobs)
1223 NTSTATUS status;
1224 struct smb_filename *clientFname;
1225 TALLOC_CTX *ctx;
1228 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1229 smb_fname->base_name));
1230 if (!is_in_media_files(smb_fname->base_name))
1232 status = SMB_VFS_NEXT_CREATE_FILE(
1233 handle,
1234 req,
1235 root_dir_fid,
1236 smb_fname,
1237 access_mask,
1238 share_access,
1239 create_disposition,
1240 create_options,
1241 file_attributes,
1242 oplock_request,
1243 lease,
1244 allocation_size,
1245 private_flags,
1247 ea_list,
1248 result_fsp,
1249 pinfo,
1250 in_context_blobs,
1251 out_context_blobs);
1252 goto out;
1255 clientFname = NULL;
1256 ctx = talloc_tos();
1258 if (alloc_get_client_smb_fname(handle, ctx,
1259 smb_fname,
1260 &clientFname))
1262 status = map_nt_error_from_unix(errno);
1263 goto err;
1266 /* This only creates files, so we don't have to worry about
1267 * our fake directory stat'ing here.
1269 // But we still need to route stat calls for DB files
1270 // properly, right?
1271 status = SMB_VFS_NEXT_CREATE_FILE(
1272 handle,
1273 req,
1274 root_dir_fid,
1275 clientFname,
1276 access_mask,
1277 share_access,
1278 create_disposition,
1279 create_options,
1280 file_attributes,
1281 oplock_request,
1282 lease,
1283 allocation_size,
1284 private_flags,
1286 ea_list,
1287 result_fsp,
1288 pinfo,
1289 in_context_blobs,
1290 out_context_blobs);
1291 err:
1292 TALLOC_FREE(clientFname);
1293 out:
1294 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1295 "smb_fname->st.st_ex_mtime %s"
1296 " fsp->fsp_name->st.st_ex_mtime %s",
1297 smb_fname->base_name,
1298 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1299 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1300 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1301 "No fsp time\n"));
1302 return status;
1306 * Success: return 0
1307 * Failure: set errno, return -1
1309 static int mh_rename(vfs_handle_struct *handle,
1310 const struct smb_filename *smb_fname_src,
1311 const struct smb_filename *smb_fname_dst)
1313 int status;
1314 struct smb_filename *srcClientFname;
1315 struct smb_filename *dstClientFname;
1316 TALLOC_CTX *ctx;
1319 DEBUG(MH_INFO_DEBUG, ("Entering with "
1320 "smb_fname_src->base_name '%s', "
1321 "smb_fname_dst->base_name '%s'\n",
1322 smb_fname_src->base_name,
1323 smb_fname_dst->base_name));
1325 if (!is_in_media_files(smb_fname_src->base_name)
1327 !is_in_media_files(smb_fname_dst->base_name))
1329 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1330 smb_fname_dst);
1331 goto out;
1334 srcClientFname = NULL;
1335 dstClientFname = NULL;
1336 ctx = talloc_tos();
1338 if ((status = alloc_get_client_smb_fname(handle, ctx,
1339 smb_fname_src,
1340 &srcClientFname)))
1342 goto err;
1345 if ((status = alloc_get_client_smb_fname(handle, ctx,
1346 smb_fname_dst,
1347 &dstClientFname)))
1349 goto err;
1352 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1353 dstClientFname);
1354 err:
1355 TALLOC_FREE(dstClientFname);
1356 TALLOC_FREE(srcClientFname);
1357 out:
1358 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1359 " smb_fname_dst->base_name '%s'\n",
1360 smb_fname_src->base_name,
1361 smb_fname_dst->base_name));
1362 return status;
1366 * Success: return 0
1367 * Failure: set errno, return -1
1369 static int mh_stat(vfs_handle_struct *handle,
1370 struct smb_filename *smb_fname)
1372 int status = 0;
1373 struct smb_filename *clientFname;
1374 TALLOC_CTX *ctx;
1377 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1378 smb_fname->base_name));
1380 if (!is_in_media_files(smb_fname->base_name))
1382 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1383 goto out;
1386 clientFname = NULL;
1387 ctx = talloc_tos();
1389 if ((status = alloc_get_client_smb_fname(handle, ctx,
1390 smb_fname,
1391 &clientFname)))
1393 goto err;
1395 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1396 clientFname->base_name));
1397 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1399 goto err;
1401 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1403 goto err;
1406 /* Unlike functions with const smb_filename, we have to
1407 * modify smb_fname itself to pass our info back up.
1409 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1410 "from clientFname '%s'\n",
1411 smb_fname->base_name,
1412 clientFname->base_name));
1413 smb_fname->st = clientFname->st;
1414 err:
1415 TALLOC_FREE(clientFname);
1416 out:
1417 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1418 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1419 return status;
1423 * Success: return 0
1424 * Failure: set errno, return -1
1426 static int mh_lstat(vfs_handle_struct *handle,
1427 struct smb_filename *smb_fname)
1429 int status = 0;
1430 struct smb_filename *clientFname;
1431 TALLOC_CTX *ctx;
1433 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1434 smb_fname->base_name));
1436 if (!is_in_media_files(smb_fname->base_name))
1438 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1439 goto out;
1442 clientFname = NULL;
1443 ctx = talloc_tos();
1445 if ((status = alloc_get_client_smb_fname(handle, ctx,
1446 smb_fname,
1447 &clientFname)))
1449 goto err;
1451 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1453 goto err;
1456 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1458 goto err;
1460 /* Unlike functions with const smb_filename, we have to
1461 * modify smb_fname itself to pass our info back up.
1463 smb_fname->st = clientFname->st;
1464 err:
1465 TALLOC_FREE(clientFname);
1466 out:
1467 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1468 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1469 return status;
1473 * Success: return 0
1474 * Failure: set errno, return -1
1476 static int mh_fstat(vfs_handle_struct *handle,
1477 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1479 int status = 0;
1481 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1482 "'%s'\n", fsp_str_dbg(fsp)));
1484 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1486 goto out;
1489 if (fsp->fsp_name == NULL
1490 || !is_in_media_files(fsp->fsp_name->base_name))
1492 goto out;
1495 if ((status = mh_stat(handle, fsp->fsp_name)))
1497 goto out;
1500 *sbuf = fsp->fsp_name->st;
1501 out:
1502 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1503 "%s",
1504 fsp->fsp_name != NULL ?
1505 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1506 "0"));
1507 return status;
1511 * Success: return 0
1512 * Failure: set errno, return -1
1514 static int mh_unlink(vfs_handle_struct *handle,
1515 const struct smb_filename *smb_fname)
1517 int status;
1518 struct smb_filename *clientFname;
1519 TALLOC_CTX *ctx;
1521 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1522 if (!is_in_media_files(smb_fname->base_name))
1524 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1525 goto out;
1528 clientFname = NULL;
1529 ctx = talloc_tos();
1531 if ((status = alloc_get_client_smb_fname(handle, ctx,
1532 smb_fname,
1533 &clientFname)))
1535 goto err;
1538 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1539 err:
1540 TALLOC_FREE(clientFname);
1541 out:
1542 return status;
1546 * Success: return 0
1547 * Failure: set errno, return -1
1549 static int mh_chmod(vfs_handle_struct *handle,
1550 const struct smb_filename *smb_fname,
1551 mode_t mode)
1553 int status;
1554 struct smb_filename *clientFname = NULL;
1556 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1557 if (!is_in_media_files(smb_fname->base_name))
1559 status = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1560 goto out;
1563 status = alloc_get_client_smb_fname(handle,
1564 talloc_tos(),
1565 smb_fname,
1566 &clientFname);
1567 if (status != 0) {
1568 goto err;
1571 status = SMB_VFS_NEXT_CHMOD(handle, clientFname, mode);
1572 err:
1573 TALLOC_FREE(clientFname);
1574 out:
1575 return status;
1579 * Success: return 0
1580 * Failure: set errno, return -1
1582 static int mh_chown(vfs_handle_struct *handle,
1583 const struct smb_filename *smb_fname,
1584 uid_t uid,
1585 gid_t gid)
1587 int status;
1588 struct smb_filename *clientFname = NULL;
1590 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1591 if (!is_in_media_files(smb_fname->base_name))
1593 status = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1594 goto out;
1597 status = alloc_get_client_smb_fname(handle,
1598 talloc_tos(),
1599 smb_fname,
1600 &clientFname);
1601 if (status != 0) {
1602 goto err;
1605 status = SMB_VFS_NEXT_CHOWN(handle, clientFname, uid, gid);
1606 err:
1607 TALLOC_FREE(clientFname);
1608 out:
1609 return status;
1613 * Success: return 0
1614 * Failure: set errno, return -1
1616 static int mh_lchown(vfs_handle_struct *handle,
1617 const struct smb_filename *smb_fname,
1618 uid_t uid,
1619 gid_t gid)
1621 int status;
1622 struct smb_filename *clientFname = NULL;
1624 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1625 if (!is_in_media_files(smb_fname->base_name))
1627 status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1628 goto out;
1631 status = alloc_get_client_smb_fname(handle,
1632 talloc_tos(),
1633 smb_fname,
1634 &clientFname);
1635 if (status != 0) {
1636 goto err;
1639 status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1640 err:
1641 TALLOC_FREE(clientFname);
1642 out:
1643 return status;
1647 * Success: return 0
1648 * Failure: set errno, return -1
1650 static int mh_chdir(vfs_handle_struct *handle,
1651 const struct smb_filename *smb_fname)
1653 int status;
1654 struct smb_filename *clientFname = NULL;
1656 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1657 if (!is_in_media_files(smb_fname->base_name)) {
1658 status = SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1659 goto out;
1662 status = alloc_get_client_smb_fname(handle,
1663 talloc_tos(),
1664 smb_fname,
1665 &clientFname);
1666 if (status != 0) {
1667 goto err;
1670 status = SMB_VFS_NEXT_CHDIR(handle, clientFname);
1671 err:
1672 TALLOC_FREE(clientFname);
1673 out:
1674 return status;
1678 * Success: return 0
1679 * Failure: set errno, return -1
1681 static int mh_ntimes(vfs_handle_struct *handle,
1682 const struct smb_filename *smb_fname,
1683 struct smb_file_time *ft)
1685 int status;
1686 struct smb_filename *clientFname;
1687 TALLOC_CTX *ctx;
1690 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1691 if (!is_in_media_files(smb_fname->base_name))
1693 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1694 goto out;
1697 clientFname = NULL;
1698 ctx = talloc_tos();
1700 if ((status = alloc_get_client_smb_fname(handle, ctx,
1701 smb_fname,
1702 &clientFname)))
1704 goto err;
1707 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1708 err:
1709 TALLOC_FREE(clientFname);
1710 out:
1711 return status;
1715 * Success: return 0
1716 * Failure: set errno, return -1
1719 static int mh_symlink(vfs_handle_struct *handle,
1720 const char *link_contents,
1721 const struct smb_filename *new_smb_fname)
1723 int status = -1;
1724 char *client_link_contents = NULL;
1725 struct smb_filename *newclientFname = NULL;
1727 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1728 if (!is_in_media_files(link_contents) &&
1729 !is_in_media_files(new_smb_fname->base_name)) {
1730 status = SMB_VFS_NEXT_SYMLINK(handle,
1731 link_contents,
1732 new_smb_fname);
1733 goto out;
1736 if ((status = alloc_get_client_path(handle, talloc_tos(),
1737 link_contents,
1738 &client_link_contents))) {
1739 goto err;
1741 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1742 new_smb_fname,
1743 &newclientFname))) {
1744 goto err;
1747 status = SMB_VFS_NEXT_SYMLINK(handle,
1748 client_link_contents,
1749 newclientFname);
1750 err:
1751 TALLOC_FREE(client_link_contents);
1752 TALLOC_FREE(newclientFname);
1753 out:
1754 return status;
1758 * Success: return byte count
1759 * Failure: set errno, return -1
1761 static int mh_readlink(vfs_handle_struct *handle,
1762 const struct smb_filename *smb_fname,
1763 char *buf,
1764 size_t bufsiz)
1766 int status;
1767 struct smb_filename *clientFname = NULL;
1769 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1770 if (!is_in_media_files(smb_fname->base_name)) {
1771 status = SMB_VFS_NEXT_READLINK(handle, smb_fname, buf, bufsiz);
1772 goto out;
1775 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1776 smb_fname,
1777 &clientFname))) {
1778 goto err;
1781 status = SMB_VFS_NEXT_READLINK(handle, clientFname, buf, bufsiz);
1782 err:
1783 TALLOC_FREE(clientFname);
1784 out:
1785 return status;
1789 * Success: return 0
1790 * Failure: set errno, return -1
1792 static int mh_link(vfs_handle_struct *handle,
1793 const struct smb_filename *old_smb_fname,
1794 const struct smb_filename *new_smb_fname)
1796 int status;
1797 struct smb_filename *oldclientFname = NULL;
1798 struct smb_filename *newclientFname = NULL;
1800 DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1801 if (!is_in_media_files(old_smb_fname->base_name) &&
1802 !is_in_media_files(new_smb_fname->base_name)) {
1803 status = SMB_VFS_NEXT_LINK(handle,
1804 old_smb_fname,
1805 new_smb_fname);
1806 goto out;
1809 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1810 old_smb_fname,
1811 &oldclientFname))) {
1812 goto err;
1814 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1815 new_smb_fname,
1816 &newclientFname))) {
1817 goto err;
1820 status = SMB_VFS_NEXT_LINK(handle, oldclientFname, newclientFname);
1821 err:
1822 TALLOC_FREE(newclientFname);
1823 TALLOC_FREE(oldclientFname);
1824 out:
1825 return status;
1829 * Success: return 0
1830 * Failure: set errno, return -1
1832 static int mh_mknod(vfs_handle_struct *handle,
1833 const struct smb_filename *smb_fname,
1834 mode_t mode,
1835 SMB_DEV_T dev)
1837 int status;
1838 struct smb_filename *clientFname = NULL;
1839 TALLOC_CTX *ctx;
1841 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1842 if (!is_in_media_files(smb_fname->base_name)) {
1843 status = SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
1844 goto out;
1847 ctx = talloc_tos();
1849 if ((status = alloc_get_client_smb_fname(handle, ctx,
1850 smb_fname,
1851 &clientFname))) {
1852 goto err;
1855 status = SMB_VFS_NEXT_MKNOD(handle, clientFname, mode, dev);
1856 err:
1857 TALLOC_FREE(clientFname);
1858 out:
1859 return status;
1863 * Success: return path pointer
1864 * Failure: set errno, return NULL pointer
1866 static char *mh_realpath(vfs_handle_struct *handle,
1867 const char *path)
1869 char *buf;
1870 char *clientPath;
1871 TALLOC_CTX *ctx;
1873 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1874 if (!is_in_media_files(path))
1876 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1877 goto out;
1880 clientPath = NULL;
1881 ctx = talloc_tos();
1883 if (alloc_get_client_path(handle, ctx,
1884 path,
1885 &clientPath))
1887 buf = NULL;
1888 goto err;
1891 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1892 err:
1893 TALLOC_FREE(clientPath);
1894 out:
1895 return buf;
1899 * Success: return 0
1900 * Failure: set errno, return -1
1902 static int mh_chflags(vfs_handle_struct *handle,
1903 const struct smb_filename *smb_fname,
1904 unsigned int flags)
1906 int status;
1907 struct smb_filename *clientFname = NULL;
1908 TALLOC_CTX *ctx;
1910 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1911 if (!is_in_media_files(smb_fname->base_name)) {
1912 status = SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1913 goto out;
1916 ctx = talloc_tos();
1918 if ((status = alloc_get_client_smb_fname(handle, ctx,
1919 smb_fname,
1920 &clientFname))) {
1921 goto err;
1924 status = SMB_VFS_NEXT_CHFLAGS(handle, clientFname, flags);
1925 err:
1926 TALLOC_FREE(clientFname);
1927 out:
1928 return status;
1932 * Success: return NT_STATUS_OK
1933 * Failure: return NT status error
1935 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1936 struct files_struct *fsp,
1937 const struct smb_filename *smb_fname,
1938 TALLOC_CTX *ctx,
1939 unsigned int *num_streams,
1940 struct stream_struct **streams)
1942 NTSTATUS status;
1943 int ret;
1944 struct smb_filename *clientFname = NULL;
1946 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1947 if (!is_in_media_files(smb_fname->base_name)) {
1948 status = SMB_VFS_NEXT_STREAMINFO(handle,
1949 fsp,
1950 smb_fname,
1951 ctx,
1952 num_streams,
1953 streams);
1954 goto out;
1957 ret = alloc_get_client_smb_fname(handle,
1958 talloc_tos(),
1959 smb_fname,
1960 &clientFname);
1961 if (ret != 0) {
1962 status = NT_STATUS_NO_MEMORY;
1963 goto err;
1966 /* This only works on files, so we don't have to worry about
1967 * our fake directory stat'ing here.
1969 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientFname,
1970 ctx, num_streams, streams);
1971 err:
1972 TALLOC_FREE(clientFname);
1973 out:
1974 return status;
1977 /* Ignoring get_real_filename function because the default
1978 * doesn't do anything.
1982 * Success: return NT_STATUS_OK
1983 * Failure: return NT status error
1984 * In this case, "name" is a path.
1986 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
1987 const struct smb_filename *smb_fname,
1988 uint32_t security_info,
1989 TALLOC_CTX *mem_ctx,
1990 struct security_descriptor **ppdesc)
1992 NTSTATUS status;
1993 char *clientPath;
1994 struct smb_filename *client_smb_fname = NULL;
1995 TALLOC_CTX *ctx;
1997 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
1998 if (!is_in_media_files(smb_fname->base_name))
2000 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
2001 security_info,
2002 mem_ctx, ppdesc);
2003 goto out;
2006 clientPath = NULL;
2007 ctx = talloc_tos();
2009 if (alloc_get_client_path(handle, ctx,
2010 smb_fname->base_name,
2011 &clientPath))
2013 status = map_nt_error_from_unix(errno);
2014 goto err;
2017 client_smb_fname = synthetic_smb_fname(talloc_tos(),
2018 clientPath,
2019 NULL,
2020 NULL,
2021 smb_fname->flags);
2022 if (client_smb_fname == NULL) {
2023 TALLOC_FREE(clientPath);
2024 return NT_STATUS_NO_MEMORY;
2027 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
2028 security_info,
2029 mem_ctx, ppdesc);
2030 err:
2031 TALLOC_FREE(clientPath);
2032 TALLOC_FREE(client_smb_fname);
2033 out:
2034 return status;
2038 * Success: return 0
2039 * Failure: set errno, return -1
2041 static int mh_chmod_acl(vfs_handle_struct *handle,
2042 const struct smb_filename *smb_fname,
2043 mode_t mode)
2045 int status;
2046 struct smb_filename *clientFname = NULL;
2048 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2049 if (!is_in_media_files(smb_fname->base_name))
2051 status = SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2052 goto out;
2055 status = alloc_get_client_smb_fname(handle,
2056 talloc_tos(),
2057 smb_fname,
2058 &clientFname);
2059 if (status != 0) {
2060 goto err;
2063 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientFname, mode);
2064 err:
2065 TALLOC_FREE(clientFname);
2066 out:
2067 return status;
2071 * Success: return acl pointer
2072 * Failure: set errno, return NULL
2074 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2075 const struct smb_filename *smb_fname,
2076 SMB_ACL_TYPE_T type,
2077 TALLOC_CTX *mem_ctx)
2079 SMB_ACL_T ret;
2080 int status;
2081 struct smb_filename *clientFname = NULL;
2083 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2084 if (!is_in_media_files(smb_fname->base_name)) {
2085 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
2086 type, mem_ctx);
2087 goto out;
2090 status = alloc_get_client_smb_fname(handle,
2091 talloc_tos(),
2092 smb_fname,
2093 &clientFname);
2094 if (status != 0) {
2095 ret = (SMB_ACL_T)NULL;
2096 goto err;
2099 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientFname, type, mem_ctx);
2100 err:
2101 TALLOC_FREE(clientFname);
2102 out:
2103 return ret;
2107 * Success: return 0
2108 * Failure: set errno, return -1
2109 * In this case, "name" is a path.
2111 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2112 const struct smb_filename *smb_fname,
2113 SMB_ACL_TYPE_T acltype,
2114 SMB_ACL_T theacl)
2116 int status;
2117 struct smb_filename *clientFname = NULL;
2119 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2120 if (!is_in_media_files(smb_fname->base_name)) {
2121 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
2122 acltype, theacl);
2123 goto out;
2126 status = alloc_get_client_smb_fname(handle,
2127 talloc_tos(),
2128 smb_fname,
2129 &clientFname);
2130 if (status != 0) {
2131 goto err;
2134 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientFname,
2135 acltype, theacl);
2136 err:
2137 TALLOC_FREE(clientFname);
2138 out:
2139 return status;
2143 * Success: return 0
2144 * Failure: set errno, return -1
2146 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2147 const struct smb_filename *smb_fname)
2149 int status;
2150 struct smb_filename *clientFname = NULL;
2152 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2153 if (!is_in_media_files(smb_fname->base_name)) {
2154 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2155 smb_fname);
2156 goto out;
2159 status = alloc_get_client_smb_fname(handle,
2160 talloc_tos(),
2161 smb_fname,
2162 &clientFname);
2163 if (status != 0) {
2164 goto err;
2166 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientFname);
2167 err:
2168 TALLOC_FREE(clientFname);
2169 out:
2170 return status;
2174 * Success: return positive number
2175 * Failure: set errno, return -1
2176 * In this case, "name" is an attr name.
2178 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2179 const struct smb_filename *smb_fname,
2180 const char *name,
2181 void *value,
2182 size_t size)
2184 int status;
2185 struct smb_filename *clientFname = NULL;
2186 ssize_t ret;
2188 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2189 if (!is_in_media_files(smb_fname->base_name)) {
2190 ret = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
2191 name, value, size);
2192 goto out;
2195 status = alloc_get_client_smb_fname(handle,
2196 talloc_tos(),
2197 smb_fname,
2198 &clientFname);
2199 if (status != 0) {
2200 ret = -1;
2201 goto err;
2203 ret = SMB_VFS_NEXT_GETXATTR(handle, clientFname, name, value, size);
2204 err:
2205 TALLOC_FREE(clientFname);
2206 out:
2207 return ret;
2211 * Success: return positive number
2212 * Failure: set errno, return -1
2214 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2215 const struct smb_filename *smb_fname,
2216 char *list,
2217 size_t size)
2219 ssize_t ret;
2220 struct smb_filename *clientFname = NULL;
2221 int status;
2223 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2224 if (!is_in_media_files(smb_fname->base_name)) {
2225 ret = SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
2226 goto out;
2229 status = alloc_get_client_smb_fname(handle,
2230 talloc_tos(),
2231 smb_fname,
2232 &clientFname);
2233 if (status != 0) {
2234 ret = -1;
2235 goto err;
2238 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientFname, list, size);
2239 err:
2240 TALLOC_FREE(clientFname);
2241 out:
2242 return ret;
2246 * Success: return 0
2247 * Failure: set errno, return -1
2248 * In this case, "name" is an attr name.
2250 static int mh_removexattr(struct vfs_handle_struct *handle,
2251 const struct smb_filename *smb_fname,
2252 const char *name)
2254 int status;
2255 struct smb_filename *clientFname = NULL;
2257 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2258 if (!is_in_media_files(smb_fname->base_name)) {
2259 status = SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
2260 goto out;
2263 status = alloc_get_client_smb_fname(handle,
2264 talloc_tos(),
2265 smb_fname,
2266 &clientFname);
2267 if (status != 0) {
2268 goto err;
2270 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientFname, name);
2271 err:
2272 TALLOC_FREE(clientFname);
2273 out:
2274 return status;
2278 * Success: return 0
2279 * Failure: set errno, return -1
2280 * In this case, "name" is an attr name.
2282 static int mh_setxattr(struct vfs_handle_struct *handle,
2283 const struct smb_filename *smb_fname,
2284 const char *name,
2285 const void *value,
2286 size_t size,
2287 int flags)
2289 int status;
2290 struct smb_filename *clientFname = NULL;
2292 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2293 if (!is_in_media_files(smb_fname->base_name)) {
2294 status = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
2295 size, flags);
2296 goto out;
2299 status = alloc_get_client_smb_fname(handle,
2300 talloc_tos(),
2301 smb_fname,
2302 &clientFname);
2303 if (status != 0) {
2304 goto err;
2306 status = SMB_VFS_NEXT_SETXATTR(handle, clientFname, name, value,
2307 size, flags);
2308 err:
2309 TALLOC_FREE(clientFname);
2310 out:
2311 return status;
2314 /* VFS operations structure */
2316 static struct vfs_fn_pointers vfs_mh_fns = {
2317 /* Disk operations */
2319 .statvfs_fn = mh_statvfs,
2321 /* Directory operations */
2323 .opendir_fn = mh_opendir,
2324 .fdopendir_fn = mh_fdopendir,
2325 .readdir_fn = mh_readdir,
2326 .seekdir_fn = mh_seekdir,
2327 .telldir_fn = mh_telldir,
2328 .rewind_dir_fn = mh_rewinddir,
2329 .mkdir_fn = mh_mkdir,
2330 .rmdir_fn = mh_rmdir,
2331 .closedir_fn = mh_closedir,
2332 .init_search_op_fn = mh_init_search_op,
2334 /* File operations */
2336 .open_fn = mh_open,
2337 .create_file_fn = mh_create_file,
2338 .rename_fn = mh_rename,
2339 .stat_fn = mh_stat,
2340 .lstat_fn = mh_lstat,
2341 .fstat_fn = mh_fstat,
2342 .unlink_fn = mh_unlink,
2343 .chmod_fn = mh_chmod,
2344 .chown_fn = mh_chown,
2345 .lchown_fn = mh_lchown,
2346 .chdir_fn = mh_chdir,
2347 .ntimes_fn = mh_ntimes,
2348 .symlink_fn = mh_symlink,
2349 .readlink_fn = mh_readlink,
2350 .link_fn = mh_link,
2351 .mknod_fn = mh_mknod,
2352 .realpath_fn = mh_realpath,
2353 .chflags_fn = mh_chflags,
2354 .streaminfo_fn = mh_streaminfo,
2356 /* NT ACL operations. */
2358 .get_nt_acl_fn = mh_get_nt_acl,
2360 /* POSIX ACL operations. */
2362 .chmod_acl_fn = mh_chmod_acl,
2364 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2365 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2366 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2368 /* EA operations. */
2369 .getxattr_fn = mh_getxattr,
2370 .listxattr_fn = mh_listxattr,
2371 .removexattr_fn = mh_removexattr,
2372 .setxattr_fn = mh_setxattr,
2374 /* aio operations */
2377 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *);
2378 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
2380 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2381 "media_harmony", &vfs_mh_fns);
2382 if (!NT_STATUS_IS_OK(ret))
2384 goto out;
2387 vfs_mh_debug_level = debug_add_class("media_harmony");
2389 if (vfs_mh_debug_level == -1) {
2390 vfs_mh_debug_level = DBGC_VFS;
2391 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2392 "debugging class.\n"));
2393 } else {
2394 DEBUG(3, ("media_harmony_init: Debug class number of "
2395 "'media_harmony': %d\n",
2396 vfs_mh_debug_level));
2399 out:
2400 return ret;