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_mkdir(vfs_handle_struct
*handle
,
1048 const struct smb_filename
*smb_fname
,
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
);
1063 status
= alloc_get_client_smb_fname(handle
,
1071 status
= SMB_VFS_NEXT_MKDIR(handle
, clientFname
, mode
);
1073 TALLOC_FREE(clientFname
);
1075 DEBUG(MH_INFO_DEBUG
, ("Leaving with path '%s'\n", path
));
1081 * Failure: set errno, return -1
1083 static int mh_rmdir(vfs_handle_struct
*handle
,
1084 const struct smb_filename
*smb_fname
)
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
);
1098 status
= alloc_get_client_smb_fname(handle
,
1106 status
= SMB_VFS_NEXT_RMDIR(handle
, clientFname
);
1108 TALLOC_FREE(clientFname
);
1110 DEBUG(MH_INFO_DEBUG
, ("Leaving with path '%s'\n", path
));
1116 * Failure: set errno, return -1
1118 static int mh_closedir(vfs_handle_struct
*handle
,
1121 DIR *realdirp
= ((mh_dirinfo_struct
*)dirp
)->dirstream
;
1123 DEBUG(MH_INFO_DEBUG
, ("Entering mh_closedir\n"));
1124 // Will this talloc_free destroy realdirp?
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
,
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
,
1154 struct smb_filename
*clientFname
;
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
,
1171 if(alloc_get_client_smb_fname(handle
, ctx
,
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
);
1192 TALLOC_FREE(clientFname
);
1194 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->base_name '%s'\n",
1195 smb_fname
->base_name
));
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
,
1220 const struct smb2_create_blobs
*in_context_blobs
,
1221 struct smb2_create_blobs
*out_context_blobs
)
1224 struct smb_filename
*clientFname
;
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(
1258 if (alloc_get_client_smb_fname(handle
, ctx
,
1262 status
= map_nt_error_from_unix(errno
);
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
1271 status
= SMB_VFS_NEXT_CREATE_FILE(
1292 TALLOC_FREE(clientFname
);
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
)) :
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
)
1314 struct smb_filename
*srcClientFname
;
1315 struct smb_filename
*dstClientFname
;
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
,
1334 srcClientFname
= NULL
;
1335 dstClientFname
= NULL
;
1338 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1345 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1352 status
= SMB_VFS_NEXT_RENAME(handle
, srcClientFname
,
1355 TALLOC_FREE(dstClientFname
);
1356 TALLOC_FREE(srcClientFname
);
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
));
1367 * Failure: set errno, return -1
1369 static int mh_stat(vfs_handle_struct
*handle
,
1370 struct smb_filename
*smb_fname
)
1373 struct smb_filename
*clientFname
;
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
);
1389 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
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
)))
1401 if ((status
= set_fake_mtime(handle
, ctx
, &clientFname
, sys_stat
)))
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
;
1415 TALLOC_FREE(clientFname
);
1417 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->st.st_ex_mtime %s",
1418 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
))));
1424 * Failure: set errno, return -1
1426 static int mh_lstat(vfs_handle_struct
*handle
,
1427 struct smb_filename
*smb_fname
)
1430 struct smb_filename
*clientFname
;
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
);
1445 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1451 if ((status
= SMB_VFS_NEXT_LSTAT(handle
, clientFname
)))
1456 if ((status
= set_fake_mtime(handle
, ctx
, &clientFname
, sys_lstat
)))
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
;
1465 TALLOC_FREE(clientFname
);
1467 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->st.st_ex_mtime %s",
1468 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
))));
1474 * Failure: set errno, return -1
1476 static int mh_fstat(vfs_handle_struct
*handle
,
1477 files_struct
*fsp
, SMB_STRUCT_STAT
*sbuf
)
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
)))
1489 if (fsp
->fsp_name
== NULL
1490 || !is_in_media_files(fsp
->fsp_name
->base_name
))
1495 if ((status
= mh_stat(handle
, fsp
->fsp_name
)))
1500 *sbuf
= fsp
->fsp_name
->st
;
1502 DEBUG(MH_INFO_DEBUG
, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1504 fsp
->fsp_name
!= NULL
?
1505 ctime(&(fsp
->fsp_name
->st
.st_ex_mtime
.tv_sec
)) :
1512 * Failure: set errno, return -1
1514 static int mh_unlink(vfs_handle_struct
*handle
,
1515 const struct smb_filename
*smb_fname
)
1518 struct smb_filename
*clientFname
;
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
);
1531 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1538 status
= SMB_VFS_NEXT_UNLINK(handle
, clientFname
);
1540 TALLOC_FREE(clientFname
);
1547 * Failure: set errno, return -1
1549 static int mh_chmod(vfs_handle_struct
*handle
,
1550 const struct smb_filename
*smb_fname
,
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
);
1563 status
= alloc_get_client_smb_fname(handle
,
1571 status
= SMB_VFS_NEXT_CHMOD(handle
, clientFname
, mode
);
1573 TALLOC_FREE(clientFname
);
1580 * Failure: set errno, return -1
1582 static int mh_chown(vfs_handle_struct
*handle
,
1583 const struct smb_filename
*smb_fname
,
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
);
1597 status
= alloc_get_client_smb_fname(handle
,
1605 status
= SMB_VFS_NEXT_CHOWN(handle
, clientFname
, uid
, gid
);
1607 TALLOC_FREE(clientFname
);
1614 * Failure: set errno, return -1
1616 static int mh_lchown(vfs_handle_struct
*handle
,
1617 const struct smb_filename
*smb_fname
,
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
);
1631 status
= alloc_get_client_smb_fname(handle
,
1639 status
= SMB_VFS_NEXT_LCHOWN(handle
, clientFname
, uid
, gid
);
1641 TALLOC_FREE(clientFname
);
1648 * Failure: set errno, return -1
1650 static int mh_chdir(vfs_handle_struct
*handle
,
1651 const struct smb_filename
*smb_fname
)
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
);
1662 status
= alloc_get_client_smb_fname(handle
,
1670 status
= SMB_VFS_NEXT_CHDIR(handle
, clientFname
);
1672 TALLOC_FREE(clientFname
);
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
)
1686 struct smb_filename
*clientFname
;
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
);
1700 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1707 status
= SMB_VFS_NEXT_NTIMES(handle
, clientFname
, ft
);
1709 TALLOC_FREE(clientFname
);
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
)
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
,
1736 if ((status
= alloc_get_client_path(handle
, talloc_tos(),
1738 &client_link_contents
))) {
1741 if ((status
= alloc_get_client_smb_fname(handle
, talloc_tos(),
1743 &newclientFname
))) {
1747 status
= SMB_VFS_NEXT_SYMLINK(handle
,
1748 client_link_contents
,
1751 TALLOC_FREE(client_link_contents
);
1752 TALLOC_FREE(newclientFname
);
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
,
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
);
1775 if ((status
= alloc_get_client_smb_fname(handle
, talloc_tos(),
1781 status
= SMB_VFS_NEXT_READLINK(handle
, clientFname
, buf
, bufsiz
);
1783 TALLOC_FREE(clientFname
);
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
)
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
,
1809 if ((status
= alloc_get_client_smb_fname(handle
, talloc_tos(),
1811 &oldclientFname
))) {
1814 if ((status
= alloc_get_client_smb_fname(handle
, talloc_tos(),
1816 &newclientFname
))) {
1820 status
= SMB_VFS_NEXT_LINK(handle
, oldclientFname
, newclientFname
);
1822 TALLOC_FREE(newclientFname
);
1823 TALLOC_FREE(oldclientFname
);
1830 * Failure: set errno, return -1
1832 static int mh_mknod(vfs_handle_struct
*handle
,
1833 const struct smb_filename
*smb_fname
,
1838 struct smb_filename
*clientFname
= NULL
;
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
);
1849 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1855 status
= SMB_VFS_NEXT_MKNOD(handle
, clientFname
, mode
, dev
);
1857 TALLOC_FREE(clientFname
);
1863 * Success: return path pointer
1864 * Failure: set errno, return NULL pointer
1866 static struct smb_filename
*mh_realpath(vfs_handle_struct
*handle
,
1868 const struct smb_filename
*smb_fname
)
1870 struct smb_filename
*result_fname
= NULL
;
1871 struct smb_filename
*clientFname
= NULL
;
1873 DEBUG(MH_INFO_DEBUG
, ("Entering mh_realpath\n"));
1874 if (!is_in_media_files(smb_fname
->base_name
)) {
1875 return SMB_VFS_NEXT_REALPATH(handle
, ctx
, smb_fname
);
1878 if (alloc_get_client_smb_fname(handle
, ctx
,
1880 &clientFname
) != 0) {
1884 result_fname
= SMB_VFS_NEXT_REALPATH(handle
, ctx
, clientFname
);
1886 TALLOC_FREE(clientFname
);
1887 return result_fname
;
1892 * Failure: set errno, return -1
1894 static int mh_chflags(vfs_handle_struct
*handle
,
1895 const struct smb_filename
*smb_fname
,
1899 struct smb_filename
*clientFname
= NULL
;
1902 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chflags\n"));
1903 if (!is_in_media_files(smb_fname
->base_name
)) {
1904 status
= SMB_VFS_NEXT_CHFLAGS(handle
, smb_fname
, flags
);
1910 if ((status
= alloc_get_client_smb_fname(handle
, ctx
,
1916 status
= SMB_VFS_NEXT_CHFLAGS(handle
, clientFname
, flags
);
1918 TALLOC_FREE(clientFname
);
1924 * Success: return NT_STATUS_OK
1925 * Failure: return NT status error
1927 static NTSTATUS
mh_streaminfo(struct vfs_handle_struct
*handle
,
1928 struct files_struct
*fsp
,
1929 const struct smb_filename
*smb_fname
,
1931 unsigned int *num_streams
,
1932 struct stream_struct
**streams
)
1936 struct smb_filename
*clientFname
= NULL
;
1938 DEBUG(MH_INFO_DEBUG
, ("Entering mh_streaminfo\n"));
1939 if (!is_in_media_files(smb_fname
->base_name
)) {
1940 status
= SMB_VFS_NEXT_STREAMINFO(handle
,
1949 ret
= alloc_get_client_smb_fname(handle
,
1954 status
= NT_STATUS_NO_MEMORY
;
1958 /* This only works on files, so we don't have to worry about
1959 * our fake directory stat'ing here.
1961 status
= SMB_VFS_NEXT_STREAMINFO(handle
, fsp
, clientFname
,
1962 ctx
, num_streams
, streams
);
1964 TALLOC_FREE(clientFname
);
1969 /* Ignoring get_real_filename function because the default
1970 * doesn't do anything.
1974 * Success: return NT_STATUS_OK
1975 * Failure: return NT status error
1976 * In this case, "name" is a path.
1978 static NTSTATUS
mh_get_nt_acl(vfs_handle_struct
*handle
,
1979 const struct smb_filename
*smb_fname
,
1980 uint32_t security_info
,
1981 TALLOC_CTX
*mem_ctx
,
1982 struct security_descriptor
**ppdesc
)
1986 struct smb_filename
*client_smb_fname
= NULL
;
1989 DEBUG(MH_INFO_DEBUG
, ("Entering mh_get_nt_acl\n"));
1990 if (!is_in_media_files(smb_fname
->base_name
))
1992 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, smb_fname
,
2001 if (alloc_get_client_path(handle
, ctx
,
2002 smb_fname
->base_name
,
2005 status
= map_nt_error_from_unix(errno
);
2009 client_smb_fname
= synthetic_smb_fname(talloc_tos(),
2014 if (client_smb_fname
== NULL
) {
2015 TALLOC_FREE(clientPath
);
2016 return NT_STATUS_NO_MEMORY
;
2019 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, client_smb_fname
,
2023 TALLOC_FREE(clientPath
);
2024 TALLOC_FREE(client_smb_fname
);
2031 * Failure: set errno, return -1
2033 static int mh_chmod_acl(vfs_handle_struct
*handle
,
2034 const struct smb_filename
*smb_fname
,
2038 struct smb_filename
*clientFname
= NULL
;
2040 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chmod_acl\n"));
2041 if (!is_in_media_files(smb_fname
->base_name
))
2043 status
= SMB_VFS_NEXT_CHMOD_ACL(handle
, smb_fname
, mode
);
2047 status
= alloc_get_client_smb_fname(handle
,
2055 status
= SMB_VFS_NEXT_CHMOD_ACL(handle
, clientFname
, mode
);
2057 TALLOC_FREE(clientFname
);
2063 * Success: return acl pointer
2064 * Failure: set errno, return NULL
2066 static SMB_ACL_T
mh_sys_acl_get_file(vfs_handle_struct
*handle
,
2067 const struct smb_filename
*smb_fname
,
2068 SMB_ACL_TYPE_T type
,
2069 TALLOC_CTX
*mem_ctx
)
2073 struct smb_filename
*clientFname
= NULL
;
2075 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_get_file\n"));
2076 if (!is_in_media_files(smb_fname
->base_name
)) {
2077 ret
= SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle
, smb_fname
,
2082 status
= alloc_get_client_smb_fname(handle
,
2087 ret
= (SMB_ACL_T
)NULL
;
2091 ret
= SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle
, clientFname
, type
, mem_ctx
);
2093 TALLOC_FREE(clientFname
);
2100 * Failure: set errno, return -1
2101 * In this case, "name" is a path.
2103 static int mh_sys_acl_set_file(vfs_handle_struct
*handle
,
2104 const struct smb_filename
*smb_fname
,
2105 SMB_ACL_TYPE_T acltype
,
2109 struct smb_filename
*clientFname
= NULL
;
2111 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_set_file\n"));
2112 if (!is_in_media_files(smb_fname
->base_name
)) {
2113 status
= SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle
, smb_fname
,
2118 status
= alloc_get_client_smb_fname(handle
,
2126 status
= SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle
, clientFname
,
2129 TALLOC_FREE(clientFname
);
2136 * Failure: set errno, return -1
2138 static int mh_sys_acl_delete_def_file(vfs_handle_struct
*handle
,
2139 const struct smb_filename
*smb_fname
)
2142 struct smb_filename
*clientFname
= NULL
;
2144 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_delete_def_file\n"));
2145 if (!is_in_media_files(smb_fname
->base_name
)) {
2146 status
= SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle
,
2151 status
= alloc_get_client_smb_fname(handle
,
2158 status
= SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle
, clientFname
);
2160 TALLOC_FREE(clientFname
);
2166 * Success: return positive number
2167 * Failure: set errno, return -1
2168 * In this case, "name" is an attr name.
2170 static ssize_t
mh_getxattr(struct vfs_handle_struct
*handle
,
2171 const struct smb_filename
*smb_fname
,
2177 struct smb_filename
*clientFname
= NULL
;
2180 DEBUG(MH_INFO_DEBUG
, ("Entering mh_getxattr\n"));
2181 if (!is_in_media_files(smb_fname
->base_name
)) {
2182 ret
= SMB_VFS_NEXT_GETXATTR(handle
, smb_fname
,
2187 status
= alloc_get_client_smb_fname(handle
,
2195 ret
= SMB_VFS_NEXT_GETXATTR(handle
, clientFname
, name
, value
, size
);
2197 TALLOC_FREE(clientFname
);
2203 * Success: return positive number
2204 * Failure: set errno, return -1
2206 static ssize_t
mh_listxattr(struct vfs_handle_struct
*handle
,
2207 const struct smb_filename
*smb_fname
,
2212 struct smb_filename
*clientFname
= NULL
;
2215 DEBUG(MH_INFO_DEBUG
, ("Entering mh_listxattr\n"));
2216 if (!is_in_media_files(smb_fname
->base_name
)) {
2217 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, smb_fname
, list
, size
);
2221 status
= alloc_get_client_smb_fname(handle
,
2230 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, clientFname
, list
, size
);
2232 TALLOC_FREE(clientFname
);
2239 * Failure: set errno, return -1
2240 * In this case, "name" is an attr name.
2242 static int mh_removexattr(struct vfs_handle_struct
*handle
,
2243 const struct smb_filename
*smb_fname
,
2247 struct smb_filename
*clientFname
= NULL
;
2249 DEBUG(MH_INFO_DEBUG
, ("Entering mh_removexattr\n"));
2250 if (!is_in_media_files(smb_fname
->base_name
)) {
2251 status
= SMB_VFS_NEXT_REMOVEXATTR(handle
, smb_fname
, name
);
2255 status
= alloc_get_client_smb_fname(handle
,
2262 status
= SMB_VFS_NEXT_REMOVEXATTR(handle
, clientFname
, name
);
2264 TALLOC_FREE(clientFname
);
2271 * Failure: set errno, return -1
2272 * In this case, "name" is an attr name.
2274 static int mh_setxattr(struct vfs_handle_struct
*handle
,
2275 const struct smb_filename
*smb_fname
,
2282 struct smb_filename
*clientFname
= NULL
;
2284 DEBUG(MH_INFO_DEBUG
, ("Entering mh_setxattr\n"));
2285 if (!is_in_media_files(smb_fname
->base_name
)) {
2286 status
= SMB_VFS_NEXT_SETXATTR(handle
, smb_fname
, name
, value
,
2291 status
= alloc_get_client_smb_fname(handle
,
2298 status
= SMB_VFS_NEXT_SETXATTR(handle
, clientFname
, name
, value
,
2301 TALLOC_FREE(clientFname
);
2306 /* VFS operations structure */
2308 static struct vfs_fn_pointers vfs_mh_fns
= {
2309 /* Disk operations */
2311 .statvfs_fn
= mh_statvfs
,
2313 /* Directory operations */
2315 .opendir_fn
= mh_opendir
,
2316 .fdopendir_fn
= mh_fdopendir
,
2317 .readdir_fn
= mh_readdir
,
2318 .seekdir_fn
= mh_seekdir
,
2319 .telldir_fn
= mh_telldir
,
2320 .rewind_dir_fn
= mh_rewinddir
,
2321 .mkdir_fn
= mh_mkdir
,
2322 .rmdir_fn
= mh_rmdir
,
2323 .closedir_fn
= mh_closedir
,
2324 .init_search_op_fn
= mh_init_search_op
,
2326 /* File operations */
2329 .create_file_fn
= mh_create_file
,
2330 .rename_fn
= mh_rename
,
2332 .lstat_fn
= mh_lstat
,
2333 .fstat_fn
= mh_fstat
,
2334 .unlink_fn
= mh_unlink
,
2335 .chmod_fn
= mh_chmod
,
2336 .chown_fn
= mh_chown
,
2337 .lchown_fn
= mh_lchown
,
2338 .chdir_fn
= mh_chdir
,
2339 .ntimes_fn
= mh_ntimes
,
2340 .symlink_fn
= mh_symlink
,
2341 .readlink_fn
= mh_readlink
,
2343 .mknod_fn
= mh_mknod
,
2344 .realpath_fn
= mh_realpath
,
2345 .chflags_fn
= mh_chflags
,
2346 .streaminfo_fn
= mh_streaminfo
,
2348 /* NT ACL operations. */
2350 .get_nt_acl_fn
= mh_get_nt_acl
,
2352 /* POSIX ACL operations. */
2354 .chmod_acl_fn
= mh_chmod_acl
,
2356 .sys_acl_get_file_fn
= mh_sys_acl_get_file
,
2357 .sys_acl_set_file_fn
= mh_sys_acl_set_file
,
2358 .sys_acl_delete_def_file_fn
= mh_sys_acl_delete_def_file
,
2360 /* EA operations. */
2361 .getxattr_fn
= mh_getxattr
,
2362 .listxattr_fn
= mh_listxattr
,
2363 .removexattr_fn
= mh_removexattr
,
2364 .setxattr_fn
= mh_setxattr
,
2366 /* aio operations */
2369 NTSTATUS
vfs_media_harmony_init(TALLOC_CTX
*);
2370 NTSTATUS
vfs_media_harmony_init(TALLOC_CTX
*ctx
)
2372 NTSTATUS ret
= smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
2373 "media_harmony", &vfs_mh_fns
);
2374 if (!NT_STATUS_IS_OK(ret
))
2379 vfs_mh_debug_level
= debug_add_class("media_harmony");
2381 if (vfs_mh_debug_level
== -1) {
2382 vfs_mh_debug_level
= DBGC_VFS
;
2383 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2384 "debugging class.\n"));
2386 DEBUG(3, ("media_harmony_init: Debug class number of "
2387 "'media_harmony': %d\n",
2388 vfs_mh_debug_level
));