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* MH_MODULE_NAME
= "media_harmony";
97 static const char* MDB_FILENAME
= "msmMMOB.mdb";
98 static const size_t MDB_FILENAME_LEN
= 11;
99 static const char* PMR_FILENAME
= "msmFMID.pmr";
100 static const size_t PMR_FILENAME_LEN
= 11;
101 static const char* CREATING_DIRNAME
= "Creating";
102 static const size_t CREATING_DIRNAME_LEN
= 8;
103 static const char* AVID_MEDIAFILES_DIRNAME
= "Avid MediaFiles";
104 static const size_t AVID_MEDIAFILES_DIRNAME_LEN
= 15;
105 static const char* OMFI_MEDIAFILES_DIRNAME
= "OMFI MediaFiles";
106 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN
= 15;
107 static const char* APPLE_DOUBLE_PREFIX
= "._";
108 static const size_t APPLE_DOUBLE_PREFIX_LEN
= 2;
109 static const char* AVID_MXF_DIRNAME
= "Avid MediaFiles/MXF";
110 static const size_t AVID_MXF_DIRNAME_LEN
= 19;
112 static int vfs_mh_debug_level
= DBGC_VFS
;
114 /* supplements the directory list stream */
115 typedef struct mh_dirinfo_struct
121 char *clientMDBFilename
;
122 char *clientPMRFilename
;
123 char *clientCreatingDirname
;
127 /* Add "_<ip address>_<user name>" suffix to path or filename.
130 * Failure: set errno, path NULL, return -1
132 static int alloc_append_client_suffix(vfs_handle_struct
*handle
,
135 DEBUG(MH_INFO_DEBUG
, ("Entering with *path '%s'\n", *path
));
140 raddr
= tsocket_address_inet_addr_string(
141 handle
->conn
->sconn
->remote_address
, talloc_tos());
149 /* talloc_asprintf_append uses talloc_realloc, which
150 * frees original 'path' memory so we don't have to.
152 *path
= talloc_asprintf_append(*path
, "_%s_%s",
154 handle
->conn
->session_info
->unix_info
->sanitized_username
);
157 DEBUG(MH_ERR_DEBUG
, ("alloc_append_client_suffix "
163 DEBUG(MH_INFO_DEBUG
, ("Leaving with *path '%s'\n", *path
));
170 /* Returns True if the file or directory begins with the appledouble
173 static bool is_apple_double(const char* fname
)
175 DEBUG(MH_INFO_DEBUG
, ("Entering with fname '%s'\n", fname
));
179 if (strncmp(APPLE_DOUBLE_PREFIX
, fname
, APPLE_DOUBLE_PREFIX_LEN
)
184 DEBUG(MH_INFO_DEBUG
, ("Leaving with ret '%s'\n",
185 ret
== True
? "True" : "False"));
189 static bool starts_with_media_dir(const char* media_dirname
,
190 size_t media_dirname_len
, const char* path
)
192 DEBUG(MH_INFO_DEBUG
, ("Entering with media_dirname '%s' "
193 "path '%s'\n", media_dirname
, path
));
198 /* Sometimes Samba gives us "./OMFI MediaFiles". */
199 if (strncmp(path
, "./", 2) == 0)
201 path_start
= &path
[2];
207 if (strncmp(media_dirname
, path_start
, media_dirname_len
) == 0
210 path_start
[media_dirname_len
] == '\0'
212 path_start
[media_dirname_len
] == '/'
219 DEBUG(MH_INFO_DEBUG
, ("Leaving with ret '%s'\n",
220 ret
== True
? "True" : "False"));
225 * Returns True if the file or directory referenced by the path is below
226 * the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME directory
227 * The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME are assumed to
228 * be in the root directory, which is generally a safe assumption
229 * in the fixed-path world of Avid.
231 static bool is_in_media_files(const char* path
)
233 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s'\n", path
));
238 starts_with_media_dir(AVID_MEDIAFILES_DIRNAME
,
239 AVID_MEDIAFILES_DIRNAME_LEN
, path
)
241 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME
,
242 OMFI_MEDIAFILES_DIRNAME_LEN
, path
)
247 DEBUG(MH_INFO_DEBUG
, ("Leaving with ret '%s'\n",
248 ret
== True
? "True" : "False"));
253 * Returns depth of path under media directory. Deals with the
254 * occasional ..../. and ..../.. paths that get passed to stat.
256 * Assumes is_in_media_files has already been called and has returned
257 * true for the path; if it hasn't, this function will likely crash
260 * Not foolproof; something like "Avid MediaFiles/MXF/../foo/1"
261 * would fool it. Haven't seen paths like that getting to the
262 * stat function yet, so ignoring that possibility for now.
264 static int depth_from_media_dir(const char* media_dirname
,
265 size_t media_dirname_len
, const char* path
)
267 DEBUG(MH_INFO_DEBUG
, ("Entering with media_dirname '%s' "
268 "path '%s'\n", media_dirname
, path
));
269 int transition_count
= 0;
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
)
339 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s', "
340 "avid_db_filename '%s', "
342 "avid_db_filename_len '%i'\n",
343 path
, avid_db_filename
,
344 path_len
, 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 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s'\n", path
));
392 /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
393 * directory in path - potentially in middle of path
394 * - with suffixed name.
398 *newPath
= talloc_strdup(ctx
, path
);
399 if (*newPath
== NULL
)
401 DEBUG(MH_ERR_DEBUG
, ("alloc_get_client_path ENOMEM #1\n"));
406 DEBUG(MH_INFO_DEBUG
, ("newPath #1 %s\n", *newPath
));
408 (pathPtr
= strstr(path
, CREATING_DIRNAME
)) != NULL
411 *(pathPtr
+ CREATING_DIRNAME_LEN
) == '\0'
413 *(pathPtr
+ CREATING_DIRNAME_LEN
) == '/'
419 *(pathPtr
- 1) == '/'
421 pathPtr
- path
> APPLE_DOUBLE_PREFIX_LEN
423 *(pathPtr
- APPLE_DOUBLE_PREFIX_LEN
- 1) == '/'
425 is_apple_double(pathPtr
- APPLE_DOUBLE_PREFIX_LEN
)
429 /* Insert client suffix into path. */
430 (*newPath
)[pathPtr
- path
+ CREATING_DIRNAME_LEN
] = '\0';
431 DEBUG(MH_INFO_DEBUG
, ("newPath #2 %s\n", *newPath
));
433 if (status
= alloc_append_client_suffix(handle
, newPath
))
438 DEBUG(MH_INFO_DEBUG
, ("newPath #3 %s\n", *newPath
));
439 *newPath
= talloc_strdup_append(*newPath
,
440 pathPtr
+ CREATING_DIRNAME_LEN
);
441 if (*newPath
== NULL
)
443 DEBUG(MH_ERR_DEBUG
, ("alloc_get_client_path "
449 DEBUG(MH_INFO_DEBUG
, ("newPath #4 %s\n", *newPath
));
452 /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
453 * or /._PMR_FILENAME at newPath end with suffixed name.
455 size_t intermPathLen
= strlen(*newPath
);
457 is_avid_database(*newPath
, intermPathLen
,
458 MDB_FILENAME
, MDB_FILENAME_LEN
)
460 is_avid_database(*newPath
, intermPathLen
,
461 PMR_FILENAME
, PMR_FILENAME_LEN
)
464 DEBUG(MH_INFO_DEBUG
, ("newPath #5 %s\n", *newPath
));
465 if (status
= alloc_append_client_suffix(handle
, newPath
))
469 DEBUG(MH_INFO_DEBUG
, ("newPath #6 %s\n", *newPath
));
472 /* newPath must be freed in caller. */
473 DEBUG(MH_INFO_DEBUG
, ("Leaving with *newPath '%s'\n", *newPath
));
479 * Failure: set errno, return -1
481 static int alloc_get_client_smb_fname(struct vfs_handle_struct
*handle
,
483 const struct smb_filename
*smb_fname
,
484 struct smb_filename
**clientFname
)
486 DEBUG(MH_INFO_DEBUG
, ("Entering with smb_fname->base_name '%s'\n",
487 smb_fname
->base_name
));
492 copystatus
= copy_smb_filename(ctx
, smb_fname
, clientFname
);
493 if (!NT_STATUS_IS_OK(copystatus
))
495 DEBUG(MH_ERR_DEBUG
, ("alloc_get_client_smb_fname "
497 errno
= map_errno_from_nt_status(copystatus
);
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
)
523 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))
557 DEBUG(MH_INFO_DEBUG
, ("Entering with (*clientFname)->base_name "
558 "'%s', (*clientFname)->st.st_ex_mtime %s",
559 (*clientFname
)->base_name
,
560 ctime(&((*clientFname
)->st
.st_ex_mtime
.tv_sec
))));
565 depth_from_media_dir(AVID_MXF_DIRNAME
,
566 AVID_MXF_DIRNAME_LEN
,
567 (*clientFname
)->base_name
)
570 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME
,
571 OMFI_MEDIAFILES_DIRNAME_LEN
,
572 (*clientFname
)->base_name
)
580 SMB_STRUCT_STAT fakeStat
;
581 int copy_len
= strlen((*clientFname
)->base_name
);
583 /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
584 * We know we're under a media dir, so paths are at least 2 chars
587 if ((*clientFname
)->base_name
[copy_len
- 1] == '.' &&
588 (*clientFname
)->base_name
[copy_len
- 2] == '/')
593 if ((statPath
= talloc_strndup(ctx
,
594 (*clientFname
)->base_name
, copy_len
)) == NULL
)
600 if (status
= alloc_append_client_suffix(handle
, &statPath
))
605 DEBUG(MH_INFO_DEBUG
, ("Fake stat'ing '%s'\n", statPath
));
606 if (statFn(statPath
, &fakeStat
,
607 lp_fake_dir_create_times(SNUM(handle
->conn
))))
609 /* This can fail for legitimate reasons - i.e. the
610 * fakeStat directory doesn't exist, which is okay
611 * - so we don't set status. But if it does fail,
612 * we need to skip over the mtime assignment.
617 DEBUG(MH_INFO_DEBUG
, ("Setting fake mtime from '%s'\n", statPath
));
618 (*clientFname
)->st
.st_ex_mtime
= fakeStat
.st_ex_mtime
;
620 TALLOC_FREE(statPath
);
622 DEBUG(MH_INFO_DEBUG
, ("Leaving with (*clientFname)->base_name "
623 "'%s', (*clientFname)->st.st_ex_mtime %s",
624 (*clientFname
)->base_name
,
625 ctime(&((*clientFname
)->st
.st_ex_mtime
.tv_sec
))));
631 * Failure: set errno, return -1
633 static int mh_statvfs(struct vfs_handle_struct
*handle
,
635 struct vfs_statvfs_struct
*statbuf
)
637 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s'\n", path
));
641 if (!is_in_media_files(path
))
643 status
= SMB_VFS_NEXT_STATVFS(handle
, path
, statbuf
);
647 char *clientPath
= NULL
;
648 TALLOC_CTX
*ctx
= talloc_tos();
650 if (status
= alloc_get_client_path(handle
, ctx
,
657 status
= SMB_VFS_NEXT_STATVFS(handle
, clientPath
, statbuf
);
659 TALLOC_FREE(clientPath
);
661 DEBUG(MH_INFO_DEBUG
, ("Leaving with path '%s'\n", path
));
665 static int alloc_set_client_dirinfo(vfs_handle_struct
*handle
,
667 struct mh_dirinfo_struct
**dirInfo
)
669 DEBUG(MH_INFO_DEBUG
, ("Entering with fname '%s'\n", fname
));
673 *dirInfo
= talloc(NULL
, struct mh_dirinfo_struct
);
674 if (*dirInfo
== NULL
)
679 (*dirInfo
)->dirpath
= talloc_strdup(*dirInfo
, fname
);
680 if ((*dirInfo
)->dirpath
== NULL
)
685 if (!is_in_media_files(fname
))
687 (*dirInfo
)->clientPath
= NULL
;
688 (*dirInfo
)->clientMDBFilename
= NULL
;
689 (*dirInfo
)->clientPMRFilename
= NULL
;
690 (*dirInfo
)->clientCreatingDirname
= NULL
;
691 (*dirInfo
)->isInMediaFiles
= False
;
695 (*dirInfo
)->isInMediaFiles
= True
;
697 if (alloc_set_client_dirinfo_path(handle
,
699 &((*dirInfo
)->clientMDBFilename
),
705 if (alloc_set_client_dirinfo_path(handle
,
707 &((*dirInfo
)->clientPMRFilename
),
713 if (alloc_set_client_dirinfo_path(handle
,
715 &((*dirInfo
)->clientCreatingDirname
),
721 char *clientPath
= NULL
;
722 TALLOC_CTX
*ctx
= talloc_tos();
724 if (alloc_get_client_path(handle
, ctx
,
731 (*dirInfo
)->clientPath
= talloc_strdup(*dirInfo
, clientPath
);
732 if ((*dirInfo
)->clientPath
== NULL
)
737 TALLOC_FREE(clientPath
);
740 DEBUG(MH_INFO_DEBUG
, ("Leaving with (*dirInfo)->dirpath '%s', "
741 "(*dirInfo)->clientPath '%s'\n",
743 (*dirInfo
)->clientPath
));
747 DEBUG(MH_ERR_DEBUG
, ("Failing with fname '%s'\n", fname
));
748 TALLOC_FREE(*dirInfo
);
754 /* Success: return a mh_dirinfo_struct cast as a DIR
755 * Failure: set errno, return NULL
757 static DIR *mh_opendir(vfs_handle_struct
*handle
,
762 DEBUG(MH_INFO_DEBUG
, ("Entering with fname '%s'\n", fname
));
764 struct mh_dirinfo_struct
*dirInfo
;
766 if (alloc_set_client_dirinfo(handle
, fname
, &dirInfo
))
771 if (!dirInfo
->isInMediaFiles
)
773 dirInfo
->dirstream
= SMB_VFS_NEXT_OPENDIR(handle
,
776 dirInfo
->dirstream
= SMB_VFS_NEXT_OPENDIR(handle
,
777 dirInfo
->clientPath
, mask
, attr
);
780 if (dirInfo
->dirstream
== NULL
) {
785 /* Success is freed in closedir. */
786 DEBUG(MH_INFO_DEBUG
, ("Leaving with dirInfo->dirpath '%s', "
787 "dirInfo->clientPath '%s'\n",
789 dirInfo
->clientPath
));
790 return (DIR*)dirInfo
;
792 /* Failure is freed here. */
793 DEBUG(MH_ERR_DEBUG
, ("Failing with fname '%s'\n", fname
));
794 TALLOC_FREE(dirInfo
);
798 static DIR *mh_fdopendir(vfs_handle_struct
*handle
,
803 DEBUG(MH_INFO_DEBUG
, ("Entering with fsp->fsp_name->base_name '%s'\n",
804 fsp
->fsp_name
->base_name
));
806 struct mh_dirinfo_struct
*dirInfo
;
809 dirstream
= SMB_VFS_NEXT_FDOPENDIR(handle
, fsp
, mask
, attr
);
815 if (alloc_set_client_dirinfo(handle
, fsp
->fsp_name
->base_name
,
821 dirInfo
->dirstream
= dirstream
;
823 if (! dirInfo
->isInMediaFiles
) {
827 if (set_fake_mtime(handle
, fsp
, &(fsp
->fsp_name
), sys_stat
))
833 DEBUG(MH_INFO_DEBUG
, ("Leaving with dirInfo->dirpath '%s', "
834 "dirInfo->clientPath '%s', "
835 "fsp->fsp_name->st.st_ex_mtime %s",
838 ctime(&(fsp
->fsp_name
->st
.st_ex_mtime
.tv_sec
))));
839 /* Success is freed in closedir. */
840 return (DIR *) dirInfo
;
842 /* Failure is freed here. */
843 DEBUG(MH_ERR_DEBUG
, ("Failing with fsp->fsp_name->base_name '%s'\n",
844 fsp
->fsp_name
->base_name
));
845 TALLOC_FREE(dirInfo
);
850 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
851 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
852 * filenames and CREATING_DIRNAME directory, replace this client's
853 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
854 * directory with non suffixed.
856 * Success: return dirent
857 * End of data: return NULL
858 * Failure: set errno, return NULL
860 static struct dirent
*mh_readdir(vfs_handle_struct
*handle
,
862 SMB_STRUCT_STAT
*sbuf
)
864 DEBUG(MH_INFO_DEBUG
, ("Entering mh_readdir\n"));
866 mh_dirinfo_struct
* dirInfo
= (mh_dirinfo_struct
*)dirp
;
868 DEBUG(MH_INFO_DEBUG
, ("dirInfo->dirpath '%s', "
869 "dirInfo->clientPath '%s', "
870 "dirInfo->isInMediaFiles '%s', "
871 "dirInfo->clientMDBFilename '%s', "
872 "dirInfo->clientPMRFilename '%s', "
873 "dirInfo->clientCreatingDirname '%s'\n",
876 dirInfo
->isInMediaFiles
? "True" : "False",
877 dirInfo
->clientMDBFilename
,
878 dirInfo
->clientPMRFilename
,
879 dirInfo
->clientCreatingDirname
));
881 struct dirent
*d
= NULL
;
883 if (! dirInfo
->isInMediaFiles
)
885 d
= SMB_VFS_NEXT_READDIR(handle
, dirInfo
->dirstream
, sbuf
);
893 d
= SMB_VFS_NEXT_READDIR(handle
, dirInfo
->dirstream
, sbuf
);
903 /* ignore apple double prefix for logic below */
904 if (is_apple_double(d
->d_name
))
906 dname
= &d
->d_name
[APPLE_DOUBLE_PREFIX_LEN
];
907 isAppleDouble
= True
;
912 isAppleDouble
= False
;
915 /* skip Avid-special files with no client suffix */
917 strcmp(dname
, MDB_FILENAME
) == 0
919 strcmp(dname
, PMR_FILENAME
) == 0
921 strcmp(dname
, CREATING_DIRNAME
) == 0
926 /* chop client suffix off this client's suffixed files */
927 else if (strcmp(dname
, dirInfo
->clientMDBFilename
) == 0)
931 d
->d_name
[MDB_FILENAME_LEN
932 + APPLE_DOUBLE_PREFIX_LEN
] = '\0';
936 d
->d_name
[MDB_FILENAME_LEN
] = '\0';
939 else if (strcmp(dname
, dirInfo
->clientPMRFilename
) == 0)
943 d
->d_name
[PMR_FILENAME_LEN
944 + APPLE_DOUBLE_PREFIX_LEN
] = '\0';
948 d
->d_name
[PMR_FILENAME_LEN
] = '\0';
951 else if (strcmp(dname
, dirInfo
->clientCreatingDirname
)
956 d
->d_name
[CREATING_DIRNAME_LEN
957 + APPLE_DOUBLE_PREFIX_LEN
] = '\0';
961 d
->d_name
[CREATING_DIRNAME_LEN
] = '\0';
965 * Anything that starts as an Avid-special file
966 * that's made it this far should be skipped. This
967 * is different from the original behaviour, which
968 * only skipped other client's suffixed files.
971 strncmp(MDB_FILENAME
, dname
,
972 MDB_FILENAME_LEN
) == 0
974 strncmp(PMR_FILENAME
, dname
,
975 PMR_FILENAME_LEN
) == 0
977 strncmp(CREATING_DIRNAME
, dname
,
978 CREATING_DIRNAME_LEN
) == 0
987 DEBUG(MH_INFO_DEBUG
, ("Leaving mh_readdir\n"));
992 * Success: no success result defined.
993 * Failure: no failure result defined.
995 static void mh_seekdir(vfs_handle_struct
*handle
,
999 DEBUG(MH_INFO_DEBUG
, ("Entering and leaving mh_seekdir\n"));
1000 return SMB_VFS_NEXT_SEEKDIR(handle
,
1001 ((mh_dirinfo_struct
*)dirp
)->dirstream
, offset
);
1005 * Success: return long
1006 * Failure: no failure result defined.
1008 static long mh_telldir(vfs_handle_struct
*handle
,
1011 DEBUG(MH_INFO_DEBUG
, ("Entering and leaving mh_telldir\n"));
1012 return SMB_VFS_NEXT_TELLDIR(handle
,
1013 ((mh_dirinfo_struct
*)dirp
)->dirstream
);
1017 * Success: no success result defined.
1018 * Failure: no failure result defined.
1020 static void mh_rewinddir(vfs_handle_struct
*handle
,
1023 DEBUG(MH_INFO_DEBUG
, ("Entering and leaving mh_rewinddir\n"));
1024 return SMB_VFS_NEXT_REWINDDIR(handle
,
1025 ((mh_dirinfo_struct
*)dirp
)->dirstream
);
1030 * Failure: set errno, return -1
1032 static int mh_mkdir(vfs_handle_struct
*handle
,
1036 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s'\n", path
));
1040 if (!is_in_media_files(path
))
1042 status
= SMB_VFS_NEXT_MKDIR(handle
, path
, mode
);
1046 char *clientPath
= NULL
;
1047 TALLOC_CTX
*ctx
= talloc_tos();
1049 if (status
= alloc_get_client_path(handle
, ctx
,
1056 status
= SMB_VFS_NEXT_MKDIR(handle
, clientPath
, mode
);
1058 TALLOC_FREE(clientPath
);
1060 DEBUG(MH_INFO_DEBUG
, ("Leaving with path '%s'\n", path
));
1066 * Failure: set errno, return -1
1068 static int mh_rmdir(vfs_handle_struct
*handle
,
1071 DEBUG(MH_INFO_DEBUG
, ("Entering with path '%s'\n", path
));
1075 if (!is_in_media_files(path
))
1077 status
= SMB_VFS_NEXT_RMDIR(handle
, path
);
1081 char *clientPath
= NULL
;
1082 TALLOC_CTX
*ctx
= talloc_tos();
1084 if (status
= alloc_get_client_path(handle
, ctx
,
1091 status
= SMB_VFS_NEXT_RMDIR(handle
, clientPath
);
1093 TALLOC_FREE(clientPath
);
1095 DEBUG(MH_INFO_DEBUG
, ("Leaving with path '%s'\n", path
));
1101 * Failure: set errno, return -1
1103 static int mh_closedir(vfs_handle_struct
*handle
,
1106 DEBUG(MH_INFO_DEBUG
, ("Entering mh_closedir\n"));
1107 DIR *realdirp
= ((mh_dirinfo_struct
*)dirp
)->dirstream
;
1108 // Will this talloc_free destroy realdirp?
1111 DEBUG(MH_INFO_DEBUG
, ("Leaving mh_closedir\n"));
1112 return SMB_VFS_NEXT_CLOSEDIR(handle
, realdirp
);
1116 * Success: no success result defined.
1117 * Failure: no failure result defined.
1119 static void mh_init_search_op(vfs_handle_struct
*handle
,
1122 DEBUG(MH_INFO_DEBUG
, ("Entering and leaving mh_init_search_op\n"));
1123 return SMB_VFS_NEXT_INIT_SEARCH_OP(handle
,
1124 ((mh_dirinfo_struct
*)dirp
)->dirstream
);
1128 * Success: return non-negative file descriptor
1129 * Failure: set errno, return -1
1131 static int mh_open(vfs_handle_struct
*handle
,
1132 struct smb_filename
*smb_fname
,
1137 DEBUG(MH_INFO_DEBUG
, ("Entering with smb_fname->base_name '%s'\n",
1138 smb_fname
->base_name
));
1142 if (!is_in_media_files(smb_fname
->base_name
))
1144 ret
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
,
1149 struct smb_filename
*clientFname
= NULL
;
1150 TALLOC_CTX
*ctx
= talloc_tos();
1152 if(alloc_get_client_smb_fname(handle
, ctx
,
1160 // What about fsp->fsp_name?
1161 // We also have to get correct stat info into fsp and smb_fname
1162 // for DB files, don't we?
1164 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->base_name '%s' "
1165 "smb_fname->st.st_ex_mtime %s"
1166 " fsp->fsp_name->st.st_ex_mtime %s",
1167 smb_fname
->base_name
,
1168 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
)),
1169 ctime(&(fsp
->fsp_name
->st
.st_ex_mtime
.tv_sec
))));
1171 ret
= SMB_VFS_NEXT_OPEN(handle
, clientFname
, fsp
, flags
, mode
);
1173 TALLOC_FREE(clientFname
);
1175 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->base_name '%s'\n",
1176 smb_fname
->base_name
));
1181 * Success: return non-negative file descriptor
1182 * Failure: set errno, return -1
1184 static NTSTATUS
mh_create_file(vfs_handle_struct
*handle
,
1185 struct smb_request
*req
,
1186 uint16_t root_dir_fid
,
1187 struct smb_filename
*smb_fname
,
1188 uint32_t access_mask
,
1189 uint32_t share_access
,
1190 uint32_t create_disposition
,
1191 uint32_t create_options
,
1192 uint32_t file_attributes
,
1193 uint32_t oplock_request
,
1194 uint64_t allocation_size
,
1195 uint32_t private_flags
,
1196 struct security_descriptor
*sd
,
1197 struct ea_list
*ea_list
,
1198 files_struct
**result_fsp
,
1203 DEBUG(MH_INFO_DEBUG
, ("Entering with smb_fname->base_name '%s'\n",
1204 smb_fname
->base_name
));
1205 if (!is_in_media_files(smb_fname
->base_name
))
1207 status
= SMB_VFS_NEXT_CREATE_FILE(
1227 struct smb_filename
*clientFname
= NULL
;
1228 TALLOC_CTX
*ctx
= talloc_tos();
1230 if (alloc_get_client_smb_fname(handle
, ctx
,
1234 status
= map_nt_error_from_unix(errno
);
1238 /* This only creates files, so we don't have to worry about
1239 * our fake directory stat'ing here.
1241 // But we still need to route stat calls for DB files
1243 status
= SMB_VFS_NEXT_CREATE_FILE(
1261 TALLOC_FREE(clientFname
);
1263 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->base_name '%s'"
1264 "smb_fname->st.st_ex_mtime %s"
1265 " fsp->fsp_name->st.st_ex_mtime %s",
1266 smb_fname
->base_name
,
1267 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
)),
1268 (*result_fsp
) && VALID_STAT((*result_fsp
)->fsp_name
->st
) ?
1269 ctime(&((*result_fsp
)->fsp_name
->st
.st_ex_mtime
.tv_sec
)) :
1276 * Failure: set errno, return -1
1278 static int mh_rename(vfs_handle_struct
*handle
,
1279 const struct smb_filename
*smb_fname_src
,
1280 const struct smb_filename
*smb_fname_dst
)
1282 DEBUG(MH_INFO_DEBUG
, ("Entering with "
1283 "smb_fname_src->base_name '%s', "
1284 "smb_fname_dst->base_name '%s'\n",
1285 smb_fname_src
->base_name
,
1286 smb_fname_dst
->base_name
));
1290 if (!is_in_media_files(smb_fname_src
->base_name
)
1292 !is_in_media_files(smb_fname_dst
->base_name
))
1294 status
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
,
1299 struct smb_filename
*srcClientFname
= NULL
;
1300 struct smb_filename
*dstClientFname
= NULL
;
1301 TALLOC_CTX
*ctx
= talloc_tos();
1303 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1310 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1317 status
= SMB_VFS_NEXT_RENAME(handle
, srcClientFname
,
1320 TALLOC_FREE(dstClientFname
);
1321 TALLOC_FREE(srcClientFname
);
1323 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname_src->base_name '%s',"
1324 " smb_fname_dst->base_name '%s'\n",
1325 smb_fname_src
->base_name
,
1326 smb_fname_dst
->base_name
));
1332 * Failure: set errno, return -1
1334 static int mh_stat(vfs_handle_struct
*handle
,
1335 struct smb_filename
*smb_fname
)
1337 DEBUG(MH_INFO_DEBUG
, ("Entering with smb_fname->base_name '%s'\n",
1338 smb_fname
->base_name
));
1342 if (!is_in_media_files(smb_fname
->base_name
))
1344 status
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1348 struct smb_filename
*clientFname
= NULL
;
1349 TALLOC_CTX
*ctx
= talloc_tos();
1351 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1357 DEBUG(MH_INFO_DEBUG
, ("Stat'ing clientFname->base_name '%s'\n",
1358 clientFname
->base_name
));
1359 if (status
= SMB_VFS_NEXT_STAT(handle
, clientFname
))
1363 if (status
= set_fake_mtime(handle
, ctx
, &clientFname
, sys_stat
))
1368 /* Unlike functions with const smb_filename, we have to
1369 * modify smb_fname itself to pass our info back up.
1371 DEBUG(MH_INFO_DEBUG
, ("Setting smb_fname '%s' stat "
1372 "from clientFname '%s'\n",
1373 smb_fname
->base_name
,
1374 clientFname
->base_name
));
1375 smb_fname
->st
= clientFname
->st
;
1377 TALLOC_FREE(clientFname
);
1379 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->st.st_ex_mtime %s",
1380 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
))));
1386 * Failure: set errno, return -1
1388 static int mh_lstat(vfs_handle_struct
*handle
,
1389 struct smb_filename
*smb_fname
)
1391 DEBUG(MH_INFO_DEBUG
, ("Entering with smb_fname->base_name '%s'\n",
1392 smb_fname
->base_name
));
1396 if (!is_in_media_files(smb_fname
->base_name
))
1398 status
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1402 struct smb_filename
*clientFname
= NULL
;
1403 TALLOC_CTX
*ctx
= talloc_tos();
1405 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1411 if (status
= SMB_VFS_NEXT_LSTAT(handle
, clientFname
))
1416 if (status
= set_fake_mtime(handle
, ctx
, &clientFname
, sys_lstat
))
1420 /* Unlike functions with const smb_filename, we have to
1421 * modify smb_fname itself to pass our info back up.
1423 smb_fname
->st
= clientFname
->st
;
1425 TALLOC_FREE(clientFname
);
1427 DEBUG(MH_INFO_DEBUG
, ("Leaving with smb_fname->st.st_ex_mtime %s",
1428 ctime(&(smb_fname
->st
.st_ex_mtime
.tv_sec
))));
1434 * Failure: set errno, return -1
1436 static int mh_fstat(vfs_handle_struct
*handle
,
1437 files_struct
*fsp
, SMB_STRUCT_STAT
*sbuf
)
1439 DEBUG(MH_INFO_DEBUG
, ("Entering with fsp->fsp_name->base_name "
1440 "'%s'\n", fsp_str_dbg(fsp
)));
1444 if (status
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
))
1449 if (fsp
->fsp_name
== NULL
1450 || !is_in_media_files(fsp
->fsp_name
->base_name
))
1455 if (status
= mh_stat(handle
, fsp
->fsp_name
))
1460 *sbuf
= fsp
->fsp_name
->st
;
1462 DEBUG(MH_INFO_DEBUG
, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1464 ctime(&(fsp
->fsp_name
->st
.st_ex_mtime
.tv_sec
))));
1470 * Failure: set errno, return -1
1472 static int mh_unlink(vfs_handle_struct
*handle
,
1473 const struct smb_filename
*smb_fname
)
1477 DEBUG(MH_INFO_DEBUG
, ("Entering mh_unlink\n"));
1478 if (!is_in_media_files(smb_fname
->base_name
))
1480 status
= SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
1484 struct smb_filename
*clientFname
= NULL
;
1485 TALLOC_CTX
*ctx
= talloc_tos();
1487 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1494 status
= SMB_VFS_NEXT_UNLINK(handle
, clientFname
);
1496 TALLOC_FREE(clientFname
);
1503 * Failure: set errno, return -1
1505 static int mh_chmod(vfs_handle_struct
*handle
,
1511 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chmod\n"));
1512 if (!is_in_media_files(path
))
1514 status
= SMB_VFS_NEXT_CHMOD(handle
, path
, mode
);
1518 char *clientPath
= NULL
;
1519 TALLOC_CTX
*ctx
= talloc_tos();
1521 if (status
= alloc_get_client_path(handle
, ctx
,
1528 status
= SMB_VFS_NEXT_CHMOD(handle
, clientPath
, mode
);
1530 TALLOC_FREE(clientPath
);
1537 * Failure: set errno, return -1
1539 static int mh_chown(vfs_handle_struct
*handle
,
1546 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chown\n"));
1547 if (!is_in_media_files(path
))
1549 status
= SMB_VFS_NEXT_CHOWN(handle
, path
, uid
, gid
);
1553 char *clientPath
= NULL
;
1554 TALLOC_CTX
*ctx
= talloc_tos();
1556 if (status
= alloc_get_client_path(handle
, ctx
,
1563 status
= SMB_VFS_NEXT_CHOWN(handle
, clientPath
, uid
, gid
);
1565 TALLOC_FREE(clientPath
);
1572 * Failure: set errno, return -1
1574 static int mh_lchown(vfs_handle_struct
*handle
,
1581 DEBUG(MH_INFO_DEBUG
, ("Entering mh_lchown\n"));
1582 if (!is_in_media_files(path
))
1584 status
= SMB_VFS_NEXT_LCHOWN(handle
, path
, uid
, gid
);
1588 char *clientPath
= NULL
;
1589 TALLOC_CTX
*ctx
= talloc_tos();
1591 if (status
= alloc_get_client_path(handle
, ctx
,
1598 status
= SMB_VFS_NEXT_LCHOWN(handle
, clientPath
, uid
, gid
);
1600 TALLOC_FREE(clientPath
);
1607 * Failure: set errno, return -1
1609 static int mh_chdir(vfs_handle_struct
*handle
,
1614 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chdir\n"));
1615 if (!is_in_media_files(path
))
1617 status
= SMB_VFS_NEXT_CHDIR(handle
, path
);
1621 char *clientPath
= NULL
;
1622 TALLOC_CTX
*ctx
= talloc_tos();
1624 if (status
= alloc_get_client_path(handle
, ctx
,
1631 status
= SMB_VFS_NEXT_CHDIR(handle
, clientPath
);
1633 TALLOC_FREE(clientPath
);
1640 * Failure: set errno, return -1
1642 static int mh_ntimes(vfs_handle_struct
*handle
,
1643 const struct smb_filename
*smb_fname
,
1644 struct smb_file_time
*ft
)
1648 DEBUG(MH_INFO_DEBUG
, ("Entering mh_ntimes\n"));
1649 if (!is_in_media_files(smb_fname
->base_name
))
1651 status
= SMB_VFS_NEXT_NTIMES(handle
, smb_fname
, ft
);
1655 struct smb_filename
*clientFname
= NULL
;
1656 TALLOC_CTX
*ctx
= talloc_tos();
1658 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
1665 status
= SMB_VFS_NEXT_NTIMES(handle
, clientFname
, ft
);
1667 TALLOC_FREE(clientFname
);
1674 * Failure: set errno, return -1
1676 static int mh_symlink(vfs_handle_struct
*handle
,
1677 const char *oldpath
,
1678 const char *newpath
)
1682 DEBUG(MH_INFO_DEBUG
, ("Entering mh_symlink\n"));
1683 if (!is_in_media_files(oldpath
) && !is_in_media_files(newpath
))
1685 status
= SMB_VFS_NEXT_SYMLINK(handle
, oldpath
, newpath
);
1689 char *oldClientPath
= NULL
;
1690 char *newClientPath
= NULL
;
1691 TALLOC_CTX
*ctx
= talloc_tos();
1693 if (status
= alloc_get_client_path(handle
, ctx
,
1700 if (status
= alloc_get_client_path(handle
, ctx
,
1707 status
= SMB_VFS_NEXT_SYMLINK(handle
,
1712 TALLOC_FREE(newClientPath
);
1713 TALLOC_FREE(oldClientPath
);
1719 * Success: return byte count
1720 * Failure: set errno, return -1
1722 static int mh_readlink(vfs_handle_struct
*handle
,
1729 DEBUG(MH_INFO_DEBUG
, ("Entering mh_readlink\n"));
1730 if (!is_in_media_files(path
))
1732 status
= SMB_VFS_NEXT_READLINK(handle
, path
, buf
, bufsiz
);
1736 char *clientPath
= NULL
;
1737 TALLOC_CTX
*ctx
= talloc_tos();
1739 if (status
= alloc_get_client_path(handle
, ctx
,
1746 status
= SMB_VFS_NEXT_READLINK(handle
, clientPath
, buf
, bufsiz
);
1748 TALLOC_FREE(clientPath
);
1755 * Failure: set errno, return -1
1757 static int mh_link(vfs_handle_struct
*handle
,
1758 const char *oldpath
,
1759 const char *newpath
)
1763 DEBUG(MH_INFO_DEBUG
, ("Entering mh_link\n"));
1764 if (!is_in_media_files(oldpath
) && !is_in_media_files(newpath
))
1766 status
= SMB_VFS_NEXT_LINK(handle
, oldpath
, newpath
);
1770 char *oldClientPath
= NULL
;
1771 char *newClientPath
= NULL
;
1772 TALLOC_CTX
*ctx
= talloc_tos();
1774 if (status
= alloc_get_client_path(handle
, ctx
,
1781 if (status
= alloc_get_client_path(handle
, ctx
,
1788 status
= SMB_VFS_NEXT_LINK(handle
, oldClientPath
, newClientPath
);
1790 TALLOC_FREE(newClientPath
);
1791 TALLOC_FREE(oldClientPath
);
1798 * Failure: set errno, return -1
1800 static int mh_mknod(vfs_handle_struct
*handle
,
1801 const char *pathname
,
1807 DEBUG(MH_INFO_DEBUG
, ("Entering mh_mknod\n"));
1808 if (!is_in_media_files(pathname
))
1810 status
= SMB_VFS_NEXT_MKNOD(handle
, pathname
, mode
, dev
);
1814 char *clientPath
= NULL
;
1815 TALLOC_CTX
*ctx
= talloc_tos();
1817 if (status
= alloc_get_client_path(handle
, ctx
,
1824 status
= SMB_VFS_NEXT_MKNOD(handle
, clientPath
, mode
, dev
);
1826 TALLOC_FREE(clientPath
);
1832 * Success: return path pointer
1833 * Failure: set errno, return NULL pointer
1835 static char *mh_realpath(vfs_handle_struct
*handle
,
1840 DEBUG(MH_INFO_DEBUG
, ("Entering mh_realpath\n"));
1841 if (!is_in_media_files(path
))
1843 buf
= SMB_VFS_NEXT_REALPATH(handle
, path
);
1847 char *clientPath
= NULL
;
1848 TALLOC_CTX
*ctx
= talloc_tos();
1850 if (alloc_get_client_path(handle
, ctx
,
1858 buf
= SMB_VFS_NEXT_REALPATH(handle
, clientPath
);
1860 TALLOC_FREE(clientPath
);
1867 * Failure: set errno, return -1
1869 static int mh_chflags(vfs_handle_struct
*handle
,
1875 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chflags\n"));
1876 if (!is_in_media_files(path
))
1878 status
= SMB_VFS_NEXT_CHFLAGS(handle
, path
, flags
);
1882 char *clientPath
= NULL
;
1883 TALLOC_CTX
*ctx
= talloc_tos();
1885 if (status
= alloc_get_client_path(handle
, ctx
,
1892 status
= SMB_VFS_NEXT_CHFLAGS(handle
, clientPath
, flags
);
1894 TALLOC_FREE(clientPath
);
1900 * Success: return NT_STATUS_OK
1901 * Failure: return NT status error
1903 static NTSTATUS
mh_streaminfo(struct vfs_handle_struct
*handle
,
1904 struct files_struct
*fsp
,
1907 unsigned int *num_streams
,
1908 struct stream_struct
**streams
)
1912 DEBUG(MH_INFO_DEBUG
, ("Entering mh_streaminfo\n"));
1913 if (!is_in_media_files(fname
))
1915 status
= SMB_VFS_NEXT_STREAMINFO(handle
, fsp
, fname
,
1916 ctx
, num_streams
, streams
);
1920 char *clientPath
= NULL
;
1921 TALLOC_CTX
*mem_ctx
= talloc_tos();
1923 if (alloc_get_client_path(handle
, mem_ctx
,
1927 status
= map_nt_error_from_unix(errno
);
1931 /* This only works on files, so we don't have to worry about
1932 * our fake directory stat'ing here.
1934 // But what does this function do, exactly? Does it need
1935 // extra modifications for the Avid stuff?
1936 status
= SMB_VFS_NEXT_STREAMINFO(handle
, fsp
, clientPath
,
1937 ctx
, num_streams
, streams
);
1939 TALLOC_FREE(clientPath
);
1944 /* Ignoring get_real_filename function because the default
1945 * doesn't do anything.
1949 * Success: return NT_STATUS_OK
1950 * Failure: return NT status error
1951 * In this case, "name" is a path.
1953 static NTSTATUS
mh_get_nt_acl(vfs_handle_struct
*handle
,
1955 uint32 security_info
,
1956 struct security_descriptor
**ppdesc
)
1960 DEBUG(MH_INFO_DEBUG
, ("Entering mh_get_nt_acl\n"));
1961 if (!is_in_media_files(name
))
1963 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, name
,
1964 security_info
, ppdesc
);
1968 char *clientPath
= NULL
;
1969 TALLOC_CTX
*ctx
= talloc_tos();
1971 if (alloc_get_client_path(handle
, ctx
,
1975 status
= map_nt_error_from_unix(errno
);
1979 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, clientPath
,
1980 security_info
, ppdesc
);
1982 TALLOC_FREE(clientPath
);
1989 * Failure: set errno, return -1
1991 static int mh_chmod_acl(vfs_handle_struct
*handle
,
1997 DEBUG(MH_INFO_DEBUG
, ("Entering mh_chmod_acl\n"));
1998 if (!is_in_media_files(path
))
2000 status
= SMB_VFS_NEXT_CHMOD_ACL(handle
, path
, mode
);
2004 char *clientPath
= NULL
;
2005 TALLOC_CTX
*ctx
= talloc_tos();
2007 if (status
= alloc_get_client_path(handle
, ctx
,
2014 status
= SMB_VFS_NEXT_CHMOD_ACL(handle
, clientPath
, mode
);
2016 TALLOC_FREE(clientPath
);
2022 * Success: return acl pointer
2023 * Failure: set errno, return NULL
2025 static SMB_ACL_T
mh_sys_acl_get_file(vfs_handle_struct
*handle
,
2027 SMB_ACL_TYPE_T type
)
2031 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_get_file\n"));
2032 if (!is_in_media_files(path_p
))
2034 ret
= SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle
, path_p
, type
);
2038 char *clientPath
= NULL
;
2039 TALLOC_CTX
*ctx
= talloc_tos();
2041 if (alloc_get_client_path(handle
, ctx
,
2049 ret
= SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle
, clientPath
, type
);
2051 TALLOC_FREE(clientPath
);
2058 * Failure: set errno, return -1
2059 * In this case, "name" is a path.
2061 static int mh_sys_acl_set_file(vfs_handle_struct
*handle
,
2063 SMB_ACL_TYPE_T acltype
,
2068 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_set_file\n"));
2069 if (!is_in_media_files(name
))
2071 status
= SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle
, name
,
2076 char *clientPath
= NULL
;
2077 TALLOC_CTX
*ctx
= talloc_tos();
2079 if (status
= alloc_get_client_path(handle
, ctx
,
2086 status
= SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle
, clientPath
,
2089 TALLOC_FREE(clientPath
);
2096 * Failure: set errno, return -1
2098 static int mh_sys_acl_delete_def_file(vfs_handle_struct
*handle
,
2103 DEBUG(MH_INFO_DEBUG
, ("Entering mh_sys_acl_delete_def_file\n"));
2104 if (!is_in_media_files(path
))
2106 status
= SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle
,
2111 char *clientPath
= NULL
;
2112 TALLOC_CTX
*ctx
= talloc_tos();
2114 if (status
= alloc_get_client_path(handle
, ctx
,
2121 status
= SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle
, clientPath
);
2123 TALLOC_FREE(clientPath
);
2129 * Success: return positive number
2130 * Failure: set errno, return -1
2131 * In this case, "name" is an attr name.
2133 static ssize_t
mh_getxattr(struct vfs_handle_struct
*handle
,
2141 DEBUG(MH_INFO_DEBUG
, ("Entering mh_getxattr\n"));
2142 if (!is_in_media_files(path
))
2144 ret
= SMB_VFS_NEXT_GETXATTR(handle
, path
, name
, value
,
2149 char *clientPath
= NULL
;
2150 TALLOC_CTX
*ctx
= talloc_tos();
2152 if (alloc_get_client_path(handle
, ctx
,
2160 ret
= SMB_VFS_NEXT_GETXATTR(handle
, clientPath
, name
, value
, size
);
2162 TALLOC_FREE(clientPath
);
2168 * Success: return positive number
2169 * Failure: set errno, return -1
2171 static ssize_t
mh_listxattr(struct vfs_handle_struct
*handle
,
2178 DEBUG(MH_INFO_DEBUG
, ("Entering mh_listxattr\n"));
2179 if (!is_in_media_files(path
))
2181 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, path
, list
, size
);
2185 char *clientPath
= NULL
;
2186 TALLOC_CTX
*ctx
= talloc_tos();
2188 if (alloc_get_client_path(handle
, ctx
,
2196 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, clientPath
, list
, size
);
2198 TALLOC_FREE(clientPath
);
2205 * Failure: set errno, return -1
2206 * In this case, "name" is an attr name.
2208 static int mh_removexattr(struct vfs_handle_struct
*handle
,
2214 DEBUG(MH_INFO_DEBUG
, ("Entering mh_removexattr\n"));
2215 if (!is_in_media_files(path
))
2217 status
= SMB_VFS_NEXT_REMOVEXATTR(handle
, path
, name
);
2221 char *clientPath
= NULL
;
2222 TALLOC_CTX
*ctx
= talloc_tos();
2224 if (status
= alloc_get_client_path(handle
, ctx
,
2231 status
= SMB_VFS_NEXT_REMOVEXATTR(handle
, clientPath
, name
);
2233 TALLOC_FREE(clientPath
);
2240 * Failure: set errno, return -1
2241 * In this case, "name" is an attr name.
2243 static int mh_setxattr(struct vfs_handle_struct
*handle
,
2252 DEBUG(MH_INFO_DEBUG
, ("Entering mh_setxattr\n"));
2253 if (!is_in_media_files(path
))
2255 status
= SMB_VFS_NEXT_SETXATTR(handle
, path
, name
, value
,
2260 char *clientPath
= NULL
;
2261 TALLOC_CTX
*ctx
= talloc_tos();
2263 if (status
= alloc_get_client_path(handle
, ctx
,
2270 status
= SMB_VFS_NEXT_SETXATTR(handle
, clientPath
, name
, value
,
2273 TALLOC_FREE(clientPath
);
2279 * Success: return true
2280 * Failure: set errno, return false
2282 static bool mh_is_offline(struct vfs_handle_struct
*handle
,
2283 const struct smb_filename
*fname
,
2284 SMB_STRUCT_STAT
*sbuf
)
2286 // check if sbuf is modified further down the chain.
2289 DEBUG(MH_INFO_DEBUG
, ("Entering mh_is_offline\n"));
2290 if (!is_in_media_files(fname
->base_name
))
2292 ret
= SMB_VFS_NEXT_IS_OFFLINE(handle
, fname
, sbuf
);
2296 struct smb_filename
*clientFname
= NULL
;
2297 TALLOC_CTX
*ctx
= talloc_tos();
2299 if(alloc_get_client_smb_fname(handle
, ctx
,
2307 ret
= SMB_VFS_NEXT_IS_OFFLINE(handle
, clientFname
, sbuf
);
2309 TALLOC_FREE(clientFname
);
2315 * Success: return 0 (?)
2316 * Failure: set errno, return -1
2318 static int mh_set_offline(struct vfs_handle_struct
*handle
,
2319 const struct smb_filename
*fname
)
2323 DEBUG(MH_INFO_DEBUG
, ("Entering mh_set_offline\n"));
2324 if (!is_in_media_files(fname
->base_name
))
2326 status
= SMB_VFS_NEXT_SET_OFFLINE(handle
, fname
);
2330 struct smb_filename
*clientFname
= NULL
;
2331 TALLOC_CTX
*ctx
= talloc_tos();
2333 if (status
= alloc_get_client_smb_fname(handle
, ctx
,
2340 status
= SMB_VFS_NEXT_SET_OFFLINE(handle
, clientFname
);
2342 TALLOC_FREE(clientFname
);
2347 /* VFS operations structure */
2349 static struct vfs_fn_pointers vfs_mh_fns
= {
2350 /* Disk operations */
2352 .statvfs_fn
= mh_statvfs
,
2354 /* Directory operations */
2356 .opendir_fn
= mh_opendir
,
2357 .fdopendir_fn
= mh_fdopendir
,
2358 .readdir_fn
= mh_readdir
,
2359 .seekdir_fn
= mh_seekdir
,
2360 .telldir_fn
= mh_telldir
,
2361 .rewind_dir_fn
= mh_rewinddir
,
2362 .mkdir_fn
= mh_mkdir
,
2363 .rmdir_fn
= mh_rmdir
,
2364 .closedir_fn
= mh_closedir
,
2365 .init_search_op_fn
= mh_init_search_op
,
2367 /* File operations */
2370 .create_file_fn
= mh_create_file
,
2371 .rename_fn
= mh_rename
,
2373 .lstat_fn
= mh_lstat
,
2374 .fstat_fn
= mh_fstat
,
2375 .unlink_fn
= mh_unlink
,
2376 .chmod_fn
= mh_chmod
,
2377 .chown_fn
= mh_chown
,
2378 .lchown_fn
= mh_lchown
,
2379 .chdir_fn
= mh_chdir
,
2380 .ntimes_fn
= mh_ntimes
,
2381 .symlink_fn
= mh_symlink
,
2382 .readlink_fn
= mh_readlink
,
2384 .mknod_fn
= mh_mknod
,
2385 .realpath_fn
= mh_realpath
,
2386 .chflags_fn
= mh_chflags
,
2387 .streaminfo_fn
= mh_streaminfo
,
2389 /* NT ACL operations. */
2391 .get_nt_acl_fn
= mh_get_nt_acl
,
2393 /* POSIX ACL operations. */
2395 .chmod_acl_fn
= mh_chmod_acl
,
2397 .sys_acl_get_file_fn
= mh_sys_acl_get_file
,
2398 .sys_acl_set_file_fn
= mh_sys_acl_set_file
,
2399 .sys_acl_delete_def_file_fn
= mh_sys_acl_delete_def_file
,
2401 /* EA operations. */
2402 .getxattr_fn
= mh_getxattr
,
2403 .listxattr_fn
= mh_listxattr
,
2404 .removexattr_fn
= mh_removexattr
,
2405 .setxattr_fn
= mh_setxattr
,
2407 /* aio operations */
2409 /* offline operations */
2410 .is_offline_fn
= mh_is_offline
,
2411 .set_offline_fn
= mh_set_offline
2414 NTSTATUS
vfs_media_harmony_init(void);
2415 NTSTATUS
vfs_media_harmony_init(void)
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
));