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
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
37 * vfs objects = media_harmony
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
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
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.
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.
87 #include "system/filesys.h"
88 #include "smbd/smbd.h"
89 #include "../smbd/globals.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
120 char *clientMDBFilename;
121 char *clientPMRFilename;
122 char *clientCreatingDirname;
126 /* Add "_<ip address>_<user name>" suffix to path or filename.
129 * Failure: set errno, path NULL, return -1
131 static int alloc_append_client_suffix(vfs_handle_struct *handle,
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());
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",
153 handle->conn->session_info->unix_info->sanitized_username);
156 DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
162 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
169 /* Returns True if the file or directory begins with the appledouble
172 static bool is_apple_double(const char* fname)
176 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
178 if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
183 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
184 ret == True ? "True" : "False"));
188 static bool starts_with_media_dir(const char* media_dirname,
189 size_t media_dirname_len, const char* path)
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];
206 if (strncmp(media_dirname, path_start, media_dirname_len) == 0
209 path_start[media_dirname_len] == '\0'
211 path_start[media_dirname_len] == '/'
218 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
219 ret == True ? "True" : "False"));
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)
234 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
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)
246 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
247 ret == True ? "True" : "False"));
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
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;
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];
282 if (path_start[media_dirname_len] == '\0')
287 pathPtr = &path_start[media_dirname_len + 1];
291 if (*pathPtr == '\0' || *pathPtr == '/')
294 *(pathPtr - 1) == '.'
296 *(pathPtr - 2) == '.'
298 *(pathPtr - 3) == '/'
306 *(pathPtr - 1) == '/'
309 *(pathPtr - 1) == '.'
311 *(pathPtr - 2) == '/'
319 if (*pathPtr == '\0')
326 DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
329 return transition_count;
332 /* Identifies MDB and PMR files at end of path. */
333 static bool is_avid_database(
336 const char *avid_db_filename,
337 const size_t avid_db_filename_len)
341 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
342 "avid_db_filename '%s', "
344 "avid_db_filename_len '%i'\n",
345 path, avid_db_filename,
346 (int)path_len, (int)avid_db_filename_len));
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]))
371 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
372 ret == True ? "True" : "False"));
377 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
378 * CREATING_SUBDIRNAME.
380 * Caller must free newPath.
383 * Failure: set errno, newPath NULL, return -1
385 static int alloc_get_client_path(vfs_handle_struct *handle,
390 /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
391 * directory in path - potentially in middle of path
392 * - with suffixed name.
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"));
408 DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
410 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
413 *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
415 *(pathPtr + CREATING_DIRNAME_LEN) == '/'
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)))
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 "
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);
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)))
471 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
474 /* newPath must be freed in caller. */
475 DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
481 * Failure: set errno, return -1
483 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
485 const struct smb_filename *smb_fname,
486 struct smb_filename **clientFname)
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 "
501 if ((status = alloc_get_client_path(handle, ctx,
502 smb_fname->base_name,
503 &(*clientFname)->base_name)))
507 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
508 "'%s'\n", (*clientFname)->base_name));
516 * Failure: set errno, return -1
518 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
521 const char *avid_db_filename)
525 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
528 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
530 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
536 if ((status = alloc_append_client_suffix(handle, path)))
540 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
546 * Replace mtime on clientFname with mtime from client-suffixed
547 * equivalent, if it exists.
550 * Failure: set errno, return -1
552 static int set_fake_mtime(vfs_handle_struct *handle,
554 struct smb_filename **clientFname,
555 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
559 SMB_STRUCT_STAT fakeStat;
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))));
568 depth_from_media_dir(AVID_MXF_DIRNAME,
569 AVID_MXF_DIRNAME_LEN,
570 (*clientFname)->base_name)
573 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
574 OMFI_MEDIAFILES_DIRNAME_LEN,
575 (*clientFname)->base_name)
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
588 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
589 (*clientFname)->base_name[copy_len - 2] == '/')
594 if (((statPath = talloc_strndup(ctx,
595 (*clientFname)->base_name, copy_len)) == NULL))
601 if ((status = alloc_append_client_suffix(handle, &statPath)))
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.
618 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
619 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
621 TALLOC_FREE(statPath);
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))));
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)
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);
650 status = alloc_get_client_smb_fname(handle,
658 status = SMB_VFS_NEXT_STATVFS(handle, clientFname, statbuf);
660 TALLOC_FREE(clientFname);
662 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n",
663 smb_fname->base_name));
667 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
669 struct mh_dirinfo_struct **dirInfo)
675 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
677 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
678 if (*dirInfo == NULL)
683 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
684 if ((*dirInfo)->dirpath == NULL)
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;
699 (*dirInfo)->isInMediaFiles = True;
701 if (alloc_set_client_dirinfo_path(handle,
703 &((*dirInfo)->clientMDBFilename),
709 if (alloc_set_client_dirinfo_path(handle,
711 &((*dirInfo)->clientPMRFilename),
717 if (alloc_set_client_dirinfo_path(handle,
719 &((*dirInfo)->clientCreatingDirname),
728 if (alloc_get_client_path(handle, ctx,
735 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
736 if ((*dirInfo)->clientPath == NULL)
741 TALLOC_FREE(clientPath);
744 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
745 "(*dirInfo)->clientPath '%s'\n",
747 (*dirInfo)->clientPath));
751 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
752 TALLOC_FREE(*dirInfo);
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,
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))
776 if (!dirInfo->isInMediaFiles)
778 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
779 smb_fname, mask, attr);
781 struct smb_filename *smb_fname_clientpath =
782 synthetic_smb_fname(talloc_tos(),
787 if (smb_fname_clientpath == NULL) {
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) {
800 /* Success is freed in closedir. */
801 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
802 "dirInfo->clientPath '%s'\n",
804 dirInfo->clientPath));
805 return (DIR*)dirInfo;
807 /* Failure is freed here. */
808 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n",
809 smb_fname->base_name));
810 TALLOC_FREE(dirInfo);
814 static DIR *mh_fdopendir(vfs_handle_struct *handle,
819 struct mh_dirinfo_struct *dirInfo = NULL;
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);
831 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
837 dirInfo->dirstream = dirstream;
839 if (! dirInfo->isInMediaFiles) {
843 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
849 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
850 "dirInfo->clientPath '%s', "
851 "fsp->fsp_name->st.st_ex_mtime %s",
854 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
855 /* Success is freed in closedir. */
856 return (DIR *) dirInfo;
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);
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,
878 SMB_STRUCT_STAT *sbuf)
880 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
881 struct dirent *d = NULL;
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",
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);
911 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
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;
927 isAppleDouble = False;
930 /* skip Avid-special files with no client suffix */
932 strcmp(dname, MDB_FILENAME) == 0
934 strcmp(dname, PMR_FILENAME) == 0
936 strcmp(dname, CREATING_DIRNAME) == 0
941 /* chop client suffix off this client's suffixed files */
942 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
946 d->d_name[MDB_FILENAME_LEN
947 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
951 d->d_name[MDB_FILENAME_LEN] = '\0';
954 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
958 d->d_name[PMR_FILENAME_LEN
959 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
963 d->d_name[PMR_FILENAME_LEN] = '\0';
966 else if (strcmp(dname, dirInfo->clientCreatingDirname)
971 d->d_name[CREATING_DIRNAME_LEN
972 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
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.
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
1002 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
1007 * Success: no success result defined.
1008 * Failure: no failure result defined.
1010 static void mh_seekdir(vfs_handle_struct *handle,
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,
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,
1038 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1039 SMB_VFS_NEXT_REWINDDIR(handle,
1040 ((mh_dirinfo_struct*)dirp)->dirstream);
1045 * Failure: set errno, return -1
1047 static int mh_mkdirat(vfs_handle_struct *handle,
1048 struct files_struct *dirfsp,
1049 const struct smb_filename *smb_fname,
1053 struct smb_filename *clientFname = NULL;
1054 const char *path = smb_fname->base_name;
1056 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1058 if (!is_in_media_files(path)) {
1059 status = SMB_VFS_NEXT_MKDIRAT(handle,
1066 status = alloc_get_client_smb_fname(handle,
1074 status = SMB_VFS_NEXT_MKDIRAT(handle,
1079 TALLOC_FREE(clientFname);
1081 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1087 * Failure: set errno, return -1
1089 static int mh_rmdir(vfs_handle_struct *handle,
1090 const struct smb_filename *smb_fname)
1093 struct smb_filename *clientFname = NULL;
1094 const char *path = smb_fname->base_name;
1096 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1098 if (!is_in_media_files(path))
1100 status = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1104 status = alloc_get_client_smb_fname(handle,
1112 status = SMB_VFS_NEXT_RMDIR(handle, clientFname);
1114 TALLOC_FREE(clientFname);
1116 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1122 * Failure: set errno, return -1
1124 static int mh_closedir(vfs_handle_struct *handle,
1127 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1129 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1130 // Will this talloc_free destroy realdirp?
1133 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1134 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1138 * Success: return non-negative file descriptor
1139 * Failure: set errno, return -1
1141 static int mh_open(vfs_handle_struct *handle,
1142 struct smb_filename *smb_fname,
1148 struct smb_filename *clientFname;
1152 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1153 smb_fname->base_name));
1155 if (!is_in_media_files(smb_fname->base_name))
1157 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1165 if(alloc_get_client_smb_fname(handle, ctx,
1173 // What about fsp->fsp_name?
1174 // We also have to get correct stat info into fsp and smb_fname
1175 // for DB files, don't we?
1177 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1178 "smb_fname->st.st_ex_mtime %s"
1179 " fsp->fsp_name->st.st_ex_mtime %s",
1180 smb_fname->base_name,
1181 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1182 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1184 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1186 TALLOC_FREE(clientFname);
1188 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1189 smb_fname->base_name));
1194 * Success: return non-negative file descriptor
1195 * Failure: set errno, return -1
1197 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1198 struct smb_request *req,
1199 uint16_t root_dir_fid,
1200 struct smb_filename *smb_fname,
1201 uint32_t access_mask,
1202 uint32_t share_access,
1203 uint32_t create_disposition,
1204 uint32_t create_options,
1205 uint32_t file_attributes,
1206 uint32_t oplock_request,
1207 const struct smb2_lease *lease,
1208 uint64_t allocation_size,
1209 uint32_t private_flags,
1210 struct security_descriptor *sd,
1211 struct ea_list *ea_list,
1212 files_struct **result_fsp,
1214 const struct smb2_create_blobs *in_context_blobs,
1215 struct smb2_create_blobs *out_context_blobs)
1218 struct smb_filename *clientFname;
1222 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1223 smb_fname->base_name));
1224 if (!is_in_media_files(smb_fname->base_name))
1226 status = SMB_VFS_NEXT_CREATE_FILE(
1252 if (alloc_get_client_smb_fname(handle, ctx,
1256 status = map_nt_error_from_unix(errno);
1260 /* This only creates files, so we don't have to worry about
1261 * our fake directory stat'ing here.
1263 // But we still need to route stat calls for DB files
1265 status = SMB_VFS_NEXT_CREATE_FILE(
1286 TALLOC_FREE(clientFname);
1288 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1289 "smb_fname->st.st_ex_mtime %s"
1290 " fsp->fsp_name->st.st_ex_mtime %s",
1291 smb_fname->base_name,
1292 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1293 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1294 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1301 * Failure: set errno, return -1
1303 static int mh_renameat(vfs_handle_struct *handle,
1304 files_struct *srcfsp,
1305 const struct smb_filename *smb_fname_src,
1306 files_struct *dstfsp,
1307 const struct smb_filename *smb_fname_dst)
1310 struct smb_filename *srcClientFname;
1311 struct smb_filename *dstClientFname;
1315 DEBUG(MH_INFO_DEBUG, ("Entering with "
1316 "smb_fname_src->base_name '%s', "
1317 "smb_fname_dst->base_name '%s'\n",
1318 smb_fname_src->base_name,
1319 smb_fname_dst->base_name));
1321 if (!is_in_media_files(smb_fname_src->base_name)
1323 !is_in_media_files(smb_fname_dst->base_name))
1325 status = SMB_VFS_NEXT_RENAMEAT(handle,
1333 srcClientFname = NULL;
1334 dstClientFname = NULL;
1337 if ((status = alloc_get_client_smb_fname(handle, ctx,
1344 if ((status = alloc_get_client_smb_fname(handle, ctx,
1351 status = SMB_VFS_NEXT_RENAMEAT(handle,
1357 TALLOC_FREE(dstClientFname);
1358 TALLOC_FREE(srcClientFname);
1360 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1361 " smb_fname_dst->base_name '%s'\n",
1362 smb_fname_src->base_name,
1363 smb_fname_dst->base_name));
1369 * Failure: set errno, return -1
1371 static int mh_stat(vfs_handle_struct *handle,
1372 struct smb_filename *smb_fname)
1375 struct smb_filename *clientFname;
1379 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1380 smb_fname->base_name));
1382 if (!is_in_media_files(smb_fname->base_name))
1384 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1391 if ((status = alloc_get_client_smb_fname(handle, ctx,
1397 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1398 clientFname->base_name));
1399 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1403 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1408 /* Unlike functions with const smb_filename, we have to
1409 * modify smb_fname itself to pass our info back up.
1411 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1412 "from clientFname '%s'\n",
1413 smb_fname->base_name,
1414 clientFname->base_name));
1415 smb_fname->st = clientFname->st;
1417 TALLOC_FREE(clientFname);
1419 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1420 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1426 * Failure: set errno, return -1
1428 static int mh_lstat(vfs_handle_struct *handle,
1429 struct smb_filename *smb_fname)
1432 struct smb_filename *clientFname;
1435 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1436 smb_fname->base_name));
1438 if (!is_in_media_files(smb_fname->base_name))
1440 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1447 if ((status = alloc_get_client_smb_fname(handle, ctx,
1453 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1458 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1462 /* Unlike functions with const smb_filename, we have to
1463 * modify smb_fname itself to pass our info back up.
1465 smb_fname->st = clientFname->st;
1467 TALLOC_FREE(clientFname);
1469 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1470 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1476 * Failure: set errno, return -1
1478 static int mh_fstat(vfs_handle_struct *handle,
1479 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1483 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1484 "'%s'\n", fsp_str_dbg(fsp)));
1486 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1491 if (fsp->fsp_name == NULL
1492 || !is_in_media_files(fsp->fsp_name->base_name))
1497 if ((status = mh_stat(handle, fsp->fsp_name)))
1502 *sbuf = fsp->fsp_name->st;
1504 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1506 fsp->fsp_name != NULL ?
1507 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1514 * Failure: set errno, return -1
1516 static int mh_unlink(vfs_handle_struct *handle,
1517 const struct smb_filename *smb_fname)
1520 struct smb_filename *clientFname;
1523 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1524 if (!is_in_media_files(smb_fname->base_name))
1526 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1533 if ((status = alloc_get_client_smb_fname(handle, ctx,
1540 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1542 TALLOC_FREE(clientFname);
1549 * Failure: set errno, return -1
1551 static int mh_unlinkat(vfs_handle_struct *handle,
1552 struct files_struct *dirfsp,
1553 const struct smb_filename *smb_fname,
1557 struct smb_filename *clientFname;
1560 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlinkat\n"));
1561 if (!is_in_media_files(smb_fname->base_name)) {
1562 status = SMB_VFS_NEXT_UNLINKAT(handle,
1572 if ((status = alloc_get_client_smb_fname(handle, ctx,
1578 status = SMB_VFS_NEXT_UNLINKAT(handle,
1583 TALLOC_FREE(clientFname);
1590 * Failure: set errno, return -1
1592 static int mh_chmod(vfs_handle_struct *handle,
1593 const struct smb_filename *smb_fname,
1597 struct smb_filename *clientFname = NULL;
1599 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1600 if (!is_in_media_files(smb_fname->base_name))
1602 status = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1606 status = alloc_get_client_smb_fname(handle,
1614 status = SMB_VFS_NEXT_CHMOD(handle, clientFname, mode);
1616 TALLOC_FREE(clientFname);
1623 * Failure: set errno, return -1
1625 static int mh_chown(vfs_handle_struct *handle,
1626 const struct smb_filename *smb_fname,
1631 struct smb_filename *clientFname = NULL;
1633 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1634 if (!is_in_media_files(smb_fname->base_name))
1636 status = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1640 status = alloc_get_client_smb_fname(handle,
1648 status = SMB_VFS_NEXT_CHOWN(handle, clientFname, uid, gid);
1650 TALLOC_FREE(clientFname);
1657 * Failure: set errno, return -1
1659 static int mh_lchown(vfs_handle_struct *handle,
1660 const struct smb_filename *smb_fname,
1665 struct smb_filename *clientFname = NULL;
1667 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1668 if (!is_in_media_files(smb_fname->base_name))
1670 status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1674 status = alloc_get_client_smb_fname(handle,
1682 status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1684 TALLOC_FREE(clientFname);
1691 * Failure: set errno, return -1
1693 static int mh_chdir(vfs_handle_struct *handle,
1694 const struct smb_filename *smb_fname)
1697 struct smb_filename *clientFname = NULL;
1699 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1700 if (!is_in_media_files(smb_fname->base_name)) {
1701 status = SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1705 status = alloc_get_client_smb_fname(handle,
1713 status = SMB_VFS_NEXT_CHDIR(handle, clientFname);
1715 TALLOC_FREE(clientFname);
1722 * Failure: set errno, return -1
1724 static int mh_ntimes(vfs_handle_struct *handle,
1725 const struct smb_filename *smb_fname,
1726 struct smb_file_time *ft)
1729 struct smb_filename *clientFname;
1733 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1734 if (!is_in_media_files(smb_fname->base_name))
1736 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1743 if ((status = alloc_get_client_smb_fname(handle, ctx,
1750 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1752 TALLOC_FREE(clientFname);
1759 * Failure: set errno, return -1
1762 static int mh_symlinkat(vfs_handle_struct *handle,
1763 const char *link_contents,
1764 struct files_struct *dirfsp,
1765 const struct smb_filename *new_smb_fname)
1768 char *client_link_contents = NULL;
1769 struct smb_filename *newclientFname = NULL;
1771 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlinkat\n"));
1772 if (!is_in_media_files(link_contents) &&
1773 !is_in_media_files(new_smb_fname->base_name)) {
1774 status = SMB_VFS_NEXT_SYMLINKAT(handle,
1781 if ((status = alloc_get_client_path(handle, talloc_tos(),
1783 &client_link_contents))) {
1786 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1788 &newclientFname))) {
1792 status = SMB_VFS_NEXT_SYMLINKAT(handle,
1793 client_link_contents,
1797 TALLOC_FREE(client_link_contents);
1798 TALLOC_FREE(newclientFname);
1804 * Success: return byte count
1805 * Failure: set errno, return -1
1807 static int mh_readlinkat(vfs_handle_struct *handle,
1808 files_struct *dirfsp,
1809 const struct smb_filename *smb_fname,
1814 struct smb_filename *clientFname = NULL;
1816 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlinkat\n"));
1817 if (!is_in_media_files(smb_fname->base_name)) {
1818 status = SMB_VFS_NEXT_READLINKAT(handle,
1826 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1832 status = SMB_VFS_NEXT_READLINKAT(handle,
1839 TALLOC_FREE(clientFname);
1846 * Failure: set errno, return -1
1848 static int mh_linkat(vfs_handle_struct *handle,
1849 files_struct *srcfsp,
1850 const struct smb_filename *old_smb_fname,
1851 files_struct *dstfsp,
1852 const struct smb_filename *new_smb_fname,
1856 struct smb_filename *oldclientFname = NULL;
1857 struct smb_filename *newclientFname = NULL;
1859 DEBUG(MH_INFO_DEBUG, ("Entering mh_linkat\n"));
1860 if (!is_in_media_files(old_smb_fname->base_name) &&
1861 !is_in_media_files(new_smb_fname->base_name)) {
1862 status = SMB_VFS_NEXT_LINKAT(handle,
1871 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1873 &oldclientFname))) {
1876 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1878 &newclientFname))) {
1882 status = SMB_VFS_NEXT_LINKAT(handle,
1890 TALLOC_FREE(newclientFname);
1891 TALLOC_FREE(oldclientFname);
1898 * Failure: set errno, return -1
1900 static int mh_mknodat(vfs_handle_struct *handle,
1901 files_struct *dirfsp,
1902 const struct smb_filename *smb_fname,
1907 struct smb_filename *clientFname = NULL;
1910 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknodat\n"));
1911 if (!is_in_media_files(smb_fname->base_name)) {
1912 status = SMB_VFS_NEXT_MKNODAT(handle,
1922 if ((status = alloc_get_client_smb_fname(handle, ctx,
1928 status = SMB_VFS_NEXT_MKNODAT(handle,
1935 TALLOC_FREE(clientFname);
1941 * Success: return path pointer
1942 * Failure: set errno, return NULL pointer
1944 static struct smb_filename *mh_realpath(vfs_handle_struct *handle,
1946 const struct smb_filename *smb_fname)
1948 struct smb_filename *result_fname = NULL;
1949 struct smb_filename *clientFname = NULL;
1951 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1952 if (!is_in_media_files(smb_fname->base_name)) {
1953 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1956 if (alloc_get_client_smb_fname(handle, ctx,
1958 &clientFname) != 0) {
1962 result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, clientFname);
1964 TALLOC_FREE(clientFname);
1965 return result_fname;
1970 * Failure: set errno, return -1
1972 static int mh_chflags(vfs_handle_struct *handle,
1973 const struct smb_filename *smb_fname,
1977 struct smb_filename *clientFname = NULL;
1980 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1981 if (!is_in_media_files(smb_fname->base_name)) {
1982 status = SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1988 if ((status = alloc_get_client_smb_fname(handle, ctx,
1994 status = SMB_VFS_NEXT_CHFLAGS(handle, clientFname, flags);
1996 TALLOC_FREE(clientFname);
2002 * Success: return NT_STATUS_OK
2003 * Failure: return NT status error
2005 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
2006 struct files_struct *fsp,
2007 const struct smb_filename *smb_fname,
2009 unsigned int *num_streams,
2010 struct stream_struct **streams)
2014 struct smb_filename *clientFname = NULL;
2016 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
2017 if (!is_in_media_files(smb_fname->base_name)) {
2018 status = SMB_VFS_NEXT_STREAMINFO(handle,
2027 ret = alloc_get_client_smb_fname(handle,
2032 status = NT_STATUS_NO_MEMORY;
2036 /* This only works on files, so we don't have to worry about
2037 * our fake directory stat'ing here.
2039 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientFname,
2040 ctx, num_streams, streams);
2042 TALLOC_FREE(clientFname);
2047 /* Ignoring get_real_filename function because the default
2048 * doesn't do anything.
2052 * Success: return NT_STATUS_OK
2053 * Failure: return NT status error
2054 * In this case, "name" is a path.
2056 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2057 const struct smb_filename *smb_fname,
2058 uint32_t security_info,
2059 TALLOC_CTX *mem_ctx,
2060 struct security_descriptor **ppdesc)
2064 struct smb_filename *client_smb_fname = NULL;
2067 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2068 if (!is_in_media_files(smb_fname->base_name))
2070 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
2079 if (alloc_get_client_path(handle, ctx,
2080 smb_fname->base_name,
2083 status = map_nt_error_from_unix(errno);
2087 client_smb_fname = synthetic_smb_fname(talloc_tos(),
2092 if (client_smb_fname == NULL) {
2093 TALLOC_FREE(clientPath);
2094 return NT_STATUS_NO_MEMORY;
2097 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
2101 TALLOC_FREE(clientPath);
2102 TALLOC_FREE(client_smb_fname);
2108 * Success: return acl pointer
2109 * Failure: set errno, return NULL
2111 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2112 const struct smb_filename *smb_fname,
2113 SMB_ACL_TYPE_T type,
2114 TALLOC_CTX *mem_ctx)
2118 struct smb_filename *clientFname = NULL;
2120 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2121 if (!is_in_media_files(smb_fname->base_name)) {
2122 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
2127 status = alloc_get_client_smb_fname(handle,
2132 ret = (SMB_ACL_T)NULL;
2136 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientFname, type, mem_ctx);
2138 TALLOC_FREE(clientFname);
2145 * Failure: set errno, return -1
2146 * In this case, "name" is a path.
2148 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2149 const struct smb_filename *smb_fname,
2150 SMB_ACL_TYPE_T acltype,
2154 struct smb_filename *clientFname = NULL;
2156 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2157 if (!is_in_media_files(smb_fname->base_name)) {
2158 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
2163 status = alloc_get_client_smb_fname(handle,
2171 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientFname,
2174 TALLOC_FREE(clientFname);
2181 * Failure: set errno, return -1
2183 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2184 const struct smb_filename *smb_fname)
2187 struct smb_filename *clientFname = NULL;
2189 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2190 if (!is_in_media_files(smb_fname->base_name)) {
2191 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2196 status = alloc_get_client_smb_fname(handle,
2203 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientFname);
2205 TALLOC_FREE(clientFname);
2211 * Success: return positive number
2212 * Failure: set errno, return -1
2213 * In this case, "name" is an attr name.
2215 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2216 const struct smb_filename *smb_fname,
2222 struct smb_filename *clientFname = NULL;
2225 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2226 if (!is_in_media_files(smb_fname->base_name)) {
2227 ret = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
2232 status = alloc_get_client_smb_fname(handle,
2240 ret = SMB_VFS_NEXT_GETXATTR(handle, clientFname, name, value, size);
2242 TALLOC_FREE(clientFname);
2248 * Success: return positive number
2249 * Failure: set errno, return -1
2251 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2252 const struct smb_filename *smb_fname,
2257 struct smb_filename *clientFname = NULL;
2260 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2261 if (!is_in_media_files(smb_fname->base_name)) {
2262 ret = SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
2266 status = alloc_get_client_smb_fname(handle,
2275 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientFname, list, size);
2277 TALLOC_FREE(clientFname);
2284 * Failure: set errno, return -1
2285 * In this case, "name" is an attr name.
2287 static int mh_removexattr(struct vfs_handle_struct *handle,
2288 const struct smb_filename *smb_fname,
2292 struct smb_filename *clientFname = NULL;
2294 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2295 if (!is_in_media_files(smb_fname->base_name)) {
2296 status = SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
2300 status = alloc_get_client_smb_fname(handle,
2307 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientFname, name);
2309 TALLOC_FREE(clientFname);
2316 * Failure: set errno, return -1
2317 * In this case, "name" is an attr name.
2319 static int mh_setxattr(struct vfs_handle_struct *handle,
2320 const struct smb_filename *smb_fname,
2327 struct smb_filename *clientFname = NULL;
2329 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2330 if (!is_in_media_files(smb_fname->base_name)) {
2331 status = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
2336 status = alloc_get_client_smb_fname(handle,
2343 status = SMB_VFS_NEXT_SETXATTR(handle, clientFname, name, value,
2346 TALLOC_FREE(clientFname);
2351 /* VFS operations structure */
2353 static struct vfs_fn_pointers vfs_mh_fns = {
2354 /* Disk operations */
2356 .statvfs_fn = mh_statvfs,
2358 /* Directory operations */
2360 .opendir_fn = mh_opendir,
2361 .fdopendir_fn = mh_fdopendir,
2362 .readdir_fn = mh_readdir,
2363 .seekdir_fn = mh_seekdir,
2364 .telldir_fn = mh_telldir,
2365 .rewind_dir_fn = mh_rewinddir,
2366 .mkdirat_fn = mh_mkdirat,
2367 .rmdir_fn = mh_rmdir,
2368 .closedir_fn = mh_closedir,
2370 /* File operations */
2373 .create_file_fn = mh_create_file,
2374 .renameat_fn = mh_renameat,
2376 .lstat_fn = mh_lstat,
2377 .fstat_fn = mh_fstat,
2378 .unlink_fn = mh_unlink,
2379 .unlinkat_fn = mh_unlinkat,
2380 .chmod_fn = mh_chmod,
2381 .chown_fn = mh_chown,
2382 .lchown_fn = mh_lchown,
2383 .chdir_fn = mh_chdir,
2384 .ntimes_fn = mh_ntimes,
2385 .symlinkat_fn = mh_symlinkat,
2386 .readlinkat_fn = mh_readlinkat,
2387 .linkat_fn = mh_linkat,
2388 .mknodat_fn = mh_mknodat,
2389 .realpath_fn = mh_realpath,
2390 .chflags_fn = mh_chflags,
2391 .streaminfo_fn = mh_streaminfo,
2393 /* NT ACL operations. */
2395 .get_nt_acl_fn = mh_get_nt_acl,
2397 /* POSIX ACL operations. */
2399 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2400 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2401 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2403 /* EA operations. */
2404 .getxattr_fn = mh_getxattr,
2405 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2406 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2407 .listxattr_fn = mh_listxattr,
2408 .removexattr_fn = mh_removexattr,
2409 .setxattr_fn = mh_setxattr,
2411 /* aio operations */
2415 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
2417 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2418 "media_harmony", &vfs_mh_fns);
2419 if (!NT_STATUS_IS_OK(ret))
2424 vfs_mh_debug_level = debug_add_class("media_harmony");
2426 if (vfs_mh_debug_level == -1) {
2427 vfs_mh_debug_level = DBGC_VFS;
2428 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2429 "debugging class.\n"));
2431 DEBUG(3, ("media_harmony_init: Debug class number of "
2432 "'media_harmony': %d\n",
2433 vfs_mh_debug_level));