Rename set_sd() to set_sd_blob() - this describes what it does.
[Samba/gebeck_regimport.git] / source3 / modules / vfs_media_harmony.c
blob53cb1760d6335e52a4a1915f208646656b3b8703
1 /*
2 * $Id: media_harmony.c,v 1.1 2007/11/06 10:07:22 stuart_hc Exp $
4 * Samba VFS module supporting multiple AVID clients sharing media.
6 * Copyright (C) 2005 Philip de Nier <philipn@users.sourceforge.net>
7 * Copyright (C) 2012 Andrew Klaassen <clawsoon@yahoo.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
27 * Media Harmony is a Samba VFS module that allows multiple AVID
28 * clients to share media. Each client sees their own copy of the
29 * AVID msmMMOB.mdb and msmFMID.pmr files and Creating directories.
31 * Add this module to the vfs objects option in your Samba share
32 * configuration.
33 * eg.
35 * [avid_win]
36 * path = /video
37 * vfs objects = media_harmony
38 * ...
40 * It is recommended that you separate out Samba shares for Mac
41 * and Windows clients, and add the following options to the shares
42 * for Windows clients (NOTE: replace @ with *):
44 * veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
45 * delete veto files = yes
47 * This prevents hidden files from Mac clients interfering with Windows
48 * clients. If you find any more problem hidden files then add them to
49 * the list.
52 * Andrew Klaassen, 2012-03-14
53 * To prevent Avid clients from interrupting each other (via Avid's habit
54 * of launching a database refresh whenever it notices an mtime update
55 * on media directories, i.e. whenever one editor adds new material to a
56 * shared share), I've added code that causes stat information for anything
57 * directly under "Avid MediaFile/MXF" to be taken from
58 * dirname_clientaddr_clientuser if it exists. These files ~aren't~
59 * hidden, unlike the client-suffixed database files.
61 * For example, stat information for
62 * Avid MediaFiles/MXF/1
63 * will come from
64 * Avid MediaFiles/MXF/1_192.168.1.10_dave
65 * for dave working on 192.168.1.10, but will come from
66 * Avid MediaFile/MXF/1_192.168.1.11_susan
67 * for susan working on 192.168.1.11. If those alternate
68 * directories don't exist, the user will get the actual directory's stat
69 * info. When an editor wants to force a database refresh, they update
70 * the mtime on "their" file. This will cause Avid
71 * on that client to see an updated mtime for "Avid MediaFiles/MXF/1",
72 * which will trigger an Avid database refresh just for that editor.
75 * Notes:
76 * - This module is designed to work with AVID editing applications that
77 * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
78 * It is not designed to work as expected in all circumstances for
79 * general use. For example: it is possibly to open client specific
80 * files such as msmMMOB.mdb_192.168.1.10_userx even though is doesn't
81 * show up in a directory listing.
86 #include "includes.h"
87 #include "system/filesys.h"
88 #include "smbd/smbd.h"
89 #include "../smbd/globals.h"
90 #include "auth.h"
91 #include "../lib/tsocket/tsocket.h"
93 #define MH_INFO_DEBUG 10
94 #define MH_ERR_DEBUG 0
96 static const char* 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
117 DIR* dirstream;
118 char *dirpath;
119 char *clientPath;
120 bool isInMediaFiles;
121 char *clientMDBFilename;
122 char *clientPMRFilename;
123 char *clientCreatingDirname;
124 } mh_dirinfo_struct;
127 /* Add "_<ip address>_<user name>" suffix to path or filename.
129 * Success: return 0
130 * Failure: set errno, path NULL, return -1
132 static int alloc_append_client_suffix(vfs_handle_struct *handle,
133 char **path)
135 DEBUG(MH_INFO_DEBUG, ("Entering with *path '%s'\n", *path));
137 int status = 0;
138 char *raddr = NULL;
140 raddr = tsocket_address_inet_addr_string(
141 handle->conn->sconn->remote_address, talloc_tos());
142 if (raddr == NULL)
144 errno = ENOMEM;
145 status = -1;
146 goto err;
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",
153 raddr,
154 handle->conn->session_info->unix_info->sanitized_username);
155 if (*path == NULL)
157 DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
158 "out of memory\n"));
159 errno = ENOMEM;
160 status = -1;
161 goto err;
163 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
164 err:
165 TALLOC_FREE(raddr);
166 return status;
170 /* Returns True if the file or directory begins with the appledouble
171 * prefix.
173 static bool is_apple_double(const char* fname)
175 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
177 bool ret = False;
179 if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
180 == 0)
182 ret = True;
184 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
185 ret == True ? "True" : "False"));
186 return ret;
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));
195 bool ret = False;
196 char* path_start;
198 /* Sometimes Samba gives us "./OMFI MediaFiles". */
199 if (strncmp(path, "./", 2) == 0)
201 path_start = &path[2];
203 else {
204 path_start = path;
207 if (strncmp(media_dirname, path_start, media_dirname_len) == 0
210 path_start[media_dirname_len] == '\0'
212 path_start[media_dirname_len] == '/'
216 ret = True;
219 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
220 ret == True ? "True" : "False"));
221 return ret;
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));
235 bool ret = False;
237 if (
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)
245 ret = True;
247 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
248 ret == True ? "True" : "False"));
249 return ret;
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
258 * and burn.
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;
270 char* path_start;
271 char* pathPtr;
273 /* Sometimes Samba gives us "./OMFI MediaFiles". */
274 if (strncmp(path, "./", 2) == 0)
276 path_start = &path[2];
278 else {
279 path_start = path;
282 if (path_start[media_dirname_len] == '\0')
284 goto out;
287 pathPtr = &path_start[media_dirname_len + 1];
289 while(1)
291 if (*pathPtr == '\0' || *pathPtr == '/')
293 if (
294 *(pathPtr - 1) == '.'
296 *(pathPtr - 2) == '.'
298 *(pathPtr - 3) == '/'
301 transition_count--;
303 else if (
306 *(pathPtr - 1) == '/'
309 *(pathPtr - 1) == '.'
311 *(pathPtr - 2) == '/'
316 transition_count++;
319 if (*pathPtr == '\0')
321 break;
323 pathPtr++;
326 DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
327 transition_count));
328 out:
329 return transition_count;
332 /* Identifies MDB and PMR files at end of path. */
333 static bool is_avid_database(
334 char *path,
335 size_t path_len,
336 const char *avid_db_filename,
337 const size_t avid_db_filename_len)
339 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
340 "avid_db_filename '%s', "
341 "path_len '%i', "
342 "avid_db_filename_len '%i'\n",
343 path, avid_db_filename,
344 path_len, avid_db_filename_len));
346 bool ret = False;
348 if (
349 path_len > avid_db_filename_len
351 strcmp(&path[path_len - avid_db_filename_len],
352 avid_db_filename) == 0
355 path[path_len - avid_db_filename_len - 1] == '/'
357 path_len > avid_db_filename_len
358 + APPLE_DOUBLE_PREFIX_LEN
360 path[path_len - avid_db_filename_len
361 - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
363 is_apple_double(&path[path_len
364 - avid_db_filename_len
365 - APPLE_DOUBLE_PREFIX_LEN])
369 ret = True;
371 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
372 ret == True ? "True" : "False"));
373 return ret;
377 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
378 * CREATING_SUBDIRNAME.
380 * Caller must free newPath.
382 * Success: return 0
383 * Failure: set errno, newPath NULL, return -1
385 static int alloc_get_client_path(vfs_handle_struct *handle,
386 TALLOC_CTX *ctx,
387 const char *path,
388 char **newPath)
390 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.
396 int status = 0;
397 char* pathPtr;
398 *newPath = talloc_strdup(ctx, path);
399 if (*newPath == NULL)
401 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
402 errno = ENOMEM;
403 status = -1;
404 goto out;
406 DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
407 if (
408 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
411 *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
413 *(pathPtr + CREATING_DIRNAME_LEN) == '/'
417 pathPtr - path > 0
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)))
435 goto out;
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 "
444 "ENOMEM #2\n"));
445 errno = ENOMEM;
446 status = -1;
447 goto out;
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);
456 if (
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)))
467 goto out;
469 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
471 out:
472 /* newPath must be freed in caller. */
473 DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
474 return status;
478 * Success: return 0
479 * Failure: set errno, return -1
481 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
482 TALLOC_CTX *ctx,
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));
489 int status = 0;
490 NTSTATUS copystatus;
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 "
496 "NTERR\n"));
497 errno = map_errno_from_nt_status(copystatus);
498 status = -1;
499 goto err;
501 if ((status = alloc_get_client_path(handle, ctx,
502 smb_fname->base_name,
503 &(*clientFname)->base_name)))
505 goto err;
507 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
508 "'%s'\n", (*clientFname)->base_name));
509 err:
510 return status;
515 * Success: return 0
516 * Failure: set errno, return -1
518 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
519 TALLOC_CTX *ctx,
520 char **path,
521 const char *avid_db_filename)
523 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
524 avid_db_filename));
526 int status = 0;
528 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
530 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
531 "ENOMEM\n"));
532 errno = ENOMEM;
533 status = -1;
534 goto err;
536 if ((status = alloc_append_client_suffix(handle, path)))
538 goto err;
540 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
541 err:
542 return status;
546 * Replace mtime on clientFname with mtime from client-suffixed
547 * equivalent, if it exists.
549 * Success: return 0
550 * Failure: set errno, return -1
552 static int set_fake_mtime(vfs_handle_struct *handle,
553 TALLOC_CTX *ctx,
554 struct smb_filename **clientFname,
555 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
557 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))));
562 int status = 0;
564 if (
565 depth_from_media_dir(AVID_MXF_DIRNAME,
566 AVID_MXF_DIRNAME_LEN,
567 (*clientFname)->base_name)
568 != 1
570 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
571 OMFI_MEDIAFILES_DIRNAME_LEN,
572 (*clientFname)->base_name)
573 != 0
576 goto out;
579 char *statPath;
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
585 * long.
587 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
588 (*clientFname)->base_name[copy_len - 2] == '/')
590 copy_len -= 2;
593 if (((statPath = talloc_strndup(ctx,
594 (*clientFname)->base_name, copy_len)) == NULL))
596 errno = ENOMEM;
597 status = -1;
598 goto err;
600 if ((status = alloc_append_client_suffix(handle, &statPath)))
602 goto err;
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.
614 goto err;
617 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
618 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
619 err:
620 TALLOC_FREE(statPath);
621 out:
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))));
626 return status;
630 * Success: return 0
631 * Failure: set errno, return -1
633 static int mh_statvfs(struct vfs_handle_struct *handle,
634 const char *path,
635 struct vfs_statvfs_struct *statbuf)
637 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
639 int status;
641 if (!is_in_media_files(path))
643 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
644 goto out;
647 char *clientPath = NULL;
648 TALLOC_CTX *ctx = talloc_tos();
650 if ((status = alloc_get_client_path(handle, ctx,
651 path,
652 &clientPath)))
654 goto err;
657 status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
658 err:
659 TALLOC_FREE(clientPath);
660 out:
661 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
662 return status;
665 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
666 const char *fname,
667 struct mh_dirinfo_struct **dirInfo)
669 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
671 int status = 0;
673 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
674 if (*dirInfo == NULL)
676 goto err;
679 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
680 if ((*dirInfo)->dirpath == NULL)
682 goto err;
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;
692 goto out;
695 (*dirInfo)->isInMediaFiles = True;
697 if (alloc_set_client_dirinfo_path(handle,
698 *dirInfo,
699 &((*dirInfo)->clientMDBFilename),
700 MDB_FILENAME))
702 goto err;
705 if (alloc_set_client_dirinfo_path(handle,
706 *dirInfo,
707 &((*dirInfo)->clientPMRFilename),
708 PMR_FILENAME))
710 goto err;
713 if (alloc_set_client_dirinfo_path(handle,
714 *dirInfo,
715 &((*dirInfo)->clientCreatingDirname),
716 CREATING_DIRNAME))
718 goto err;
721 char *clientPath = NULL;
722 TALLOC_CTX *ctx = talloc_tos();
724 if (alloc_get_client_path(handle, ctx,
725 fname,
726 &clientPath))
728 goto err;
731 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
732 if ((*dirInfo)->clientPath == NULL)
734 goto err;
737 TALLOC_FREE(clientPath);
739 out:
740 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
741 "(*dirInfo)->clientPath '%s'\n",
742 (*dirInfo)->dirpath,
743 (*dirInfo)->clientPath));
744 return status;
746 err:
747 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
748 TALLOC_FREE(*dirInfo);
749 status = -1;
750 errno = ENOMEM;
751 return status;
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,
758 const char *fname,
759 const char *mask,
760 uint32 attr)
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))
768 goto err;
771 if (!dirInfo->isInMediaFiles)
773 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
774 fname, mask, attr);
775 } else {
776 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
777 dirInfo->clientPath, mask, attr);
780 if (dirInfo->dirstream == NULL) {
781 goto err;
784 out:
785 /* Success is freed in closedir. */
786 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
787 "dirInfo->clientPath '%s'\n",
788 dirInfo->dirpath,
789 dirInfo->clientPath));
790 return (DIR*)dirInfo;
791 err:
792 /* Failure is freed here. */
793 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
794 TALLOC_FREE(dirInfo);
795 return NULL;
798 static DIR *mh_fdopendir(vfs_handle_struct *handle,
799 files_struct *fsp,
800 const char *mask,
801 uint32 attr)
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;
807 DIR *dirstream;
809 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
810 if (!dirstream)
812 goto err;
815 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
816 &dirInfo))
818 goto err;
821 dirInfo->dirstream = dirstream;
823 if (! dirInfo->isInMediaFiles) {
824 goto out;
827 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
829 goto err;
832 out:
833 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
834 "dirInfo->clientPath '%s', "
835 "fsp->fsp_name->st.st_ex_mtime %s",
836 dirInfo->dirpath,
837 dirInfo->clientPath,
838 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
839 /* Success is freed in closedir. */
840 return (DIR *) dirInfo;
841 err:
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);
846 return NULL;
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,
861 DIR *dirp,
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",
874 dirInfo->dirpath,
875 dirInfo->clientPath,
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);
886 goto out;
889 int skip;
892 skip = False;
893 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
895 if (d == NULL)
897 break;
900 const char* dname;
901 bool isAppleDouble;
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;
909 else
911 dname = d->d_name;
912 isAppleDouble = False;
915 /* skip Avid-special files with no client suffix */
916 if (
917 strcmp(dname, MDB_FILENAME) == 0
919 strcmp(dname, PMR_FILENAME) == 0
921 strcmp(dname, CREATING_DIRNAME) == 0
924 skip = True;
926 /* chop client suffix off this client's suffixed files */
927 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
929 if (isAppleDouble)
931 d->d_name[MDB_FILENAME_LEN
932 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
934 else
936 d->d_name[MDB_FILENAME_LEN] = '\0';
939 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
941 if (isAppleDouble)
943 d->d_name[PMR_FILENAME_LEN
944 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
946 else
948 d->d_name[PMR_FILENAME_LEN] = '\0';
951 else if (strcmp(dname, dirInfo->clientCreatingDirname)
952 == 0)
954 if (isAppleDouble)
956 d->d_name[CREATING_DIRNAME_LEN
957 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
959 else
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.
970 else if (
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
981 skip = True;
984 while (skip);
986 out:
987 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
988 return d;
992 * Success: no success result defined.
993 * Failure: no failure result defined.
995 static void mh_seekdir(vfs_handle_struct *handle,
996 DIR *dirp,
997 long offset)
999 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1000 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,
1009 DIR *dirp)
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,
1021 DIR *dirp)
1023 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1024 SMB_VFS_NEXT_REWINDDIR(handle,
1025 ((mh_dirinfo_struct*)dirp)->dirstream);
1029 * Success: return 0
1030 * Failure: set errno, return -1
1032 static int mh_mkdir(vfs_handle_struct *handle,
1033 const char *path,
1034 mode_t mode)
1036 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1038 int status;
1040 if (!is_in_media_files(path))
1042 status = SMB_VFS_NEXT_MKDIR(handle, path, mode);
1043 goto out;
1046 char *clientPath = NULL;
1047 TALLOC_CTX *ctx = talloc_tos();
1049 if ((status = alloc_get_client_path(handle, ctx,
1050 path,
1051 &clientPath)))
1053 goto err;
1056 status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
1057 err:
1058 TALLOC_FREE(clientPath);
1059 out:
1060 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1061 return status;
1065 * Success: return 0
1066 * Failure: set errno, return -1
1068 static int mh_rmdir(vfs_handle_struct *handle,
1069 const char *path)
1071 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1073 int status;
1075 if (!is_in_media_files(path))
1077 status = SMB_VFS_NEXT_RMDIR(handle, path);
1078 goto out;
1081 char *clientPath = NULL;
1082 TALLOC_CTX *ctx = talloc_tos();
1084 if ((status = alloc_get_client_path(handle, ctx,
1085 path,
1086 &clientPath)))
1088 goto err;
1091 status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
1092 err:
1093 TALLOC_FREE(clientPath);
1094 out:
1095 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1096 return status;
1100 * Success: return 0
1101 * Failure: set errno, return -1
1103 static int mh_closedir(vfs_handle_struct *handle,
1104 DIR *dirp)
1106 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1107 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1108 // Will this talloc_free destroy realdirp?
1109 TALLOC_FREE(dirp);
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,
1120 DIR *dirp)
1122 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1123 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,
1133 files_struct *fsp,
1134 int flags,
1135 mode_t mode)
1137 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1138 smb_fname->base_name));
1140 int ret;
1142 if (!is_in_media_files(smb_fname->base_name))
1144 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1145 mode);
1146 goto out;
1149 struct smb_filename *clientFname = NULL;
1150 TALLOC_CTX *ctx = talloc_tos();
1152 if(alloc_get_client_smb_fname(handle, ctx,
1153 smb_fname,
1154 &clientFname))
1156 ret = -1;
1157 goto err;
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);
1172 err:
1173 TALLOC_FREE(clientFname);
1174 out:
1175 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1176 smb_fname->base_name));
1177 return ret;
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,
1199 int *pinfo)
1201 NTSTATUS status;
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(
1208 handle,
1209 req,
1210 root_dir_fid,
1211 smb_fname,
1212 access_mask,
1213 share_access,
1214 create_disposition,
1215 create_options,
1216 file_attributes,
1217 oplock_request,
1218 allocation_size,
1219 private_flags,
1221 ea_list,
1222 result_fsp,
1223 pinfo);
1224 goto out;
1227 struct smb_filename *clientFname = NULL;
1228 TALLOC_CTX *ctx = talloc_tos();
1230 if (alloc_get_client_smb_fname(handle, ctx,
1231 smb_fname,
1232 &clientFname))
1234 status = map_nt_error_from_unix(errno);
1235 goto err;
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
1242 // properly, right?
1243 status = SMB_VFS_NEXT_CREATE_FILE(
1244 handle,
1245 req,
1246 root_dir_fid,
1247 clientFname,
1248 access_mask,
1249 share_access,
1250 create_disposition,
1251 create_options,
1252 file_attributes,
1253 oplock_request,
1254 allocation_size,
1255 private_flags,
1257 ea_list,
1258 result_fsp,
1259 pinfo);
1260 err:
1261 TALLOC_FREE(clientFname);
1262 out:
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)) :
1270 "No fsp time\n"));
1271 return status;
1275 * Success: return 0
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));
1288 int status;
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,
1295 smb_fname_dst);
1296 goto out;
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,
1304 smb_fname_src,
1305 &srcClientFname)))
1307 goto err;
1310 if ((status = alloc_get_client_smb_fname(handle, ctx,
1311 smb_fname_dst,
1312 &dstClientFname)))
1314 goto err;
1317 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1318 dstClientFname);
1319 err:
1320 TALLOC_FREE(dstClientFname);
1321 TALLOC_FREE(srcClientFname);
1322 out:
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));
1327 return status;
1331 * Success: return 0
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));
1340 int status = 0;
1342 if (!is_in_media_files(smb_fname->base_name))
1344 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1345 goto out;
1348 struct smb_filename *clientFname = NULL;
1349 TALLOC_CTX *ctx = talloc_tos();
1351 if ((status = alloc_get_client_smb_fname(handle, ctx,
1352 smb_fname,
1353 &clientFname)))
1355 goto err;
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)))
1361 goto err;
1363 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1365 goto err;
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;
1376 err:
1377 TALLOC_FREE(clientFname);
1378 out:
1379 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1380 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1381 return status;
1385 * Success: return 0
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));
1394 int status = 0;
1396 if (!is_in_media_files(smb_fname->base_name))
1398 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1399 goto out;
1402 struct smb_filename *clientFname = NULL;
1403 TALLOC_CTX *ctx = talloc_tos();
1405 if ((status = alloc_get_client_smb_fname(handle, ctx,
1406 smb_fname,
1407 &clientFname)))
1409 goto err;
1411 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1413 goto err;
1416 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1418 goto err;
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;
1424 err:
1425 TALLOC_FREE(clientFname);
1426 out:
1427 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1428 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1429 return status;
1433 * Success: return 0
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)));
1442 int status = 0;
1444 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1446 goto out;
1449 if (fsp->fsp_name == NULL
1450 || !is_in_media_files(fsp->fsp_name->base_name))
1452 goto out;
1455 if ((status = mh_stat(handle, fsp->fsp_name)))
1457 goto out;
1460 *sbuf = fsp->fsp_name->st;
1461 out:
1462 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1463 "%s",
1464 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1465 return status;
1469 * Success: return 0
1470 * Failure: set errno, return -1
1472 static int mh_unlink(vfs_handle_struct *handle,
1473 const struct smb_filename *smb_fname)
1475 int status;
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);
1481 goto out;
1484 struct smb_filename *clientFname = NULL;
1485 TALLOC_CTX *ctx = talloc_tos();
1487 if ((status = alloc_get_client_smb_fname(handle, ctx,
1488 smb_fname,
1489 &clientFname)))
1491 goto err;
1494 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1495 err:
1496 TALLOC_FREE(clientFname);
1497 out:
1498 return status;
1502 * Success: return 0
1503 * Failure: set errno, return -1
1505 static int mh_chmod(vfs_handle_struct *handle,
1506 const char *path,
1507 mode_t mode)
1509 int status;
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);
1515 goto out;
1518 char *clientPath = NULL;
1519 TALLOC_CTX *ctx = talloc_tos();
1521 if ((status = alloc_get_client_path(handle, ctx,
1522 path,
1523 &clientPath)))
1525 goto err;
1528 status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
1529 err:
1530 TALLOC_FREE(clientPath);
1531 out:
1532 return status;
1536 * Success: return 0
1537 * Failure: set errno, return -1
1539 static int mh_chown(vfs_handle_struct *handle,
1540 const char *path,
1541 uid_t uid,
1542 gid_t gid)
1544 int status;
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);
1550 goto out;
1553 char *clientPath = NULL;
1554 TALLOC_CTX *ctx = talloc_tos();
1556 if ((status = alloc_get_client_path(handle, ctx,
1557 path,
1558 &clientPath)))
1560 goto err;
1563 status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1564 err:
1565 TALLOC_FREE(clientPath);
1566 out:
1567 return status;
1571 * Success: return 0
1572 * Failure: set errno, return -1
1574 static int mh_lchown(vfs_handle_struct *handle,
1575 const char *path,
1576 uid_t uid,
1577 gid_t gid)
1579 int status;
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);
1585 goto out;
1588 char *clientPath = NULL;
1589 TALLOC_CTX *ctx = talloc_tos();
1591 if ((status = alloc_get_client_path(handle, ctx,
1592 path,
1593 &clientPath)))
1595 goto err;
1598 status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1599 err:
1600 TALLOC_FREE(clientPath);
1601 out:
1602 return status;
1606 * Success: return 0
1607 * Failure: set errno, return -1
1609 static int mh_chdir(vfs_handle_struct *handle,
1610 const char *path)
1612 int status;
1614 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1615 if (!is_in_media_files(path))
1617 status = SMB_VFS_NEXT_CHDIR(handle, path);
1618 goto out;
1621 char *clientPath = NULL;
1622 TALLOC_CTX *ctx = talloc_tos();
1624 if ((status = alloc_get_client_path(handle, ctx,
1625 path,
1626 &clientPath)))
1628 goto err;
1631 status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1632 err:
1633 TALLOC_FREE(clientPath);
1634 out:
1635 return status;
1639 * Success: return 0
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)
1646 int status;
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);
1652 goto out;
1655 struct smb_filename *clientFname = NULL;
1656 TALLOC_CTX *ctx = talloc_tos();
1658 if ((status = alloc_get_client_smb_fname(handle, ctx,
1659 smb_fname,
1660 &clientFname)))
1662 goto err;
1665 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1666 err:
1667 TALLOC_FREE(clientFname);
1668 out:
1669 return status;
1673 * Success: return 0
1674 * Failure: set errno, return -1
1676 static int mh_symlink(vfs_handle_struct *handle,
1677 const char *oldpath,
1678 const char *newpath)
1680 int status;
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);
1686 goto out;
1689 char *oldClientPath = NULL;
1690 char *newClientPath = NULL;
1691 TALLOC_CTX *ctx = talloc_tos();
1693 if ((status = alloc_get_client_path(handle, ctx,
1694 oldpath,
1695 &oldClientPath)))
1697 goto err;
1700 if ((status = alloc_get_client_path(handle, ctx,
1701 newpath,
1702 &newClientPath)))
1704 goto err;
1707 status = SMB_VFS_NEXT_SYMLINK(handle,
1708 oldClientPath,
1709 newClientPath);
1711 err:
1712 TALLOC_FREE(newClientPath);
1713 TALLOC_FREE(oldClientPath);
1714 out:
1715 return status;
1719 * Success: return byte count
1720 * Failure: set errno, return -1
1722 static int mh_readlink(vfs_handle_struct *handle,
1723 const char *path,
1724 char *buf,
1725 size_t bufsiz)
1727 int status;
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);
1733 goto out;
1736 char *clientPath = NULL;
1737 TALLOC_CTX *ctx = talloc_tos();
1739 if ((status = alloc_get_client_path(handle, ctx,
1740 path,
1741 &clientPath)))
1743 goto err;
1746 status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1747 err:
1748 TALLOC_FREE(clientPath);
1749 out:
1750 return status;
1754 * Success: return 0
1755 * Failure: set errno, return -1
1757 static int mh_link(vfs_handle_struct *handle,
1758 const char *oldpath,
1759 const char *newpath)
1761 int status;
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);
1767 goto out;
1770 char *oldClientPath = NULL;
1771 char *newClientPath = NULL;
1772 TALLOC_CTX *ctx = talloc_tos();
1774 if ((status = alloc_get_client_path(handle, ctx,
1775 oldpath,
1776 &oldClientPath)))
1778 goto err;
1781 if ((status = alloc_get_client_path(handle, ctx,
1782 newpath,
1783 &newClientPath)))
1785 goto err;
1788 status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1789 err:
1790 TALLOC_FREE(newClientPath);
1791 TALLOC_FREE(oldClientPath);
1792 out:
1793 return status;
1797 * Success: return 0
1798 * Failure: set errno, return -1
1800 static int mh_mknod(vfs_handle_struct *handle,
1801 const char *pathname,
1802 mode_t mode,
1803 SMB_DEV_T dev)
1805 int status;
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);
1811 goto out;
1814 char *clientPath = NULL;
1815 TALLOC_CTX *ctx = talloc_tos();
1817 if ((status = alloc_get_client_path(handle, ctx,
1818 pathname,
1819 &clientPath)))
1821 goto err;
1824 status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1825 err:
1826 TALLOC_FREE(clientPath);
1827 out:
1828 return status;
1832 * Success: return path pointer
1833 * Failure: set errno, return NULL pointer
1835 static char *mh_realpath(vfs_handle_struct *handle,
1836 const char *path)
1838 char *buf;
1840 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1841 if (!is_in_media_files(path))
1843 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1844 goto out;
1847 char *clientPath = NULL;
1848 TALLOC_CTX *ctx = talloc_tos();
1850 if (alloc_get_client_path(handle, ctx,
1851 path,
1852 &clientPath))
1854 buf = NULL;
1855 goto err;
1858 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1859 err:
1860 TALLOC_FREE(clientPath);
1861 out:
1862 return buf;
1866 * Success: return 0
1867 * Failure: set errno, return -1
1869 static int mh_chflags(vfs_handle_struct *handle,
1870 const char *path,
1871 unsigned int flags)
1873 int status;
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);
1879 goto out;
1882 char *clientPath = NULL;
1883 TALLOC_CTX *ctx = talloc_tos();
1885 if ((status = alloc_get_client_path(handle, ctx,
1886 path,
1887 &clientPath)))
1889 goto err;
1892 status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1893 err:
1894 TALLOC_FREE(clientPath);
1895 out:
1896 return status;
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,
1905 const char *fname,
1906 TALLOC_CTX *ctx,
1907 unsigned int *num_streams,
1908 struct stream_struct **streams)
1910 NTSTATUS status;
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);
1917 goto out;
1920 char *clientPath = NULL;
1921 TALLOC_CTX *mem_ctx = talloc_tos();
1923 if (alloc_get_client_path(handle, mem_ctx,
1924 fname,
1925 &clientPath))
1927 status = map_nt_error_from_unix(errno);
1928 goto err;
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);
1938 err:
1939 TALLOC_FREE(clientPath);
1940 out:
1941 return status;
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,
1954 const char *name,
1955 uint32 security_info,
1956 struct security_descriptor **ppdesc)
1958 NTSTATUS status;
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);
1965 goto out;
1968 char *clientPath = NULL;
1969 TALLOC_CTX *ctx = talloc_tos();
1971 if (alloc_get_client_path(handle, ctx,
1972 name,
1973 &clientPath))
1975 status = map_nt_error_from_unix(errno);
1976 goto err;
1979 status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
1980 security_info, ppdesc);
1981 err:
1982 TALLOC_FREE(clientPath);
1983 out:
1984 return status;
1988 * Success: return 0
1989 * Failure: set errno, return -1
1991 static int mh_chmod_acl(vfs_handle_struct *handle,
1992 const char *path,
1993 mode_t mode)
1995 int status;
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);
2001 goto out;
2004 char *clientPath = NULL;
2005 TALLOC_CTX *ctx = talloc_tos();
2007 if ((status = alloc_get_client_path(handle, ctx,
2008 path,
2009 &clientPath)))
2011 goto err;
2014 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2015 err:
2016 TALLOC_FREE(clientPath);
2017 out:
2018 return status;
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,
2026 const char *path_p,
2027 SMB_ACL_TYPE_T type)
2029 SMB_ACL_T ret;
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);
2035 goto out;
2038 char *clientPath = NULL;
2039 TALLOC_CTX *ctx = talloc_tos();
2041 if (alloc_get_client_path(handle, ctx,
2042 path_p,
2043 &clientPath))
2045 ret = NULL;
2046 goto err;
2049 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type);
2050 err:
2051 TALLOC_FREE(clientPath);
2052 out:
2053 return ret;
2057 * Success: return 0
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,
2062 const char *name,
2063 SMB_ACL_TYPE_T acltype,
2064 SMB_ACL_T theacl)
2066 int status;
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,
2072 acltype, theacl);
2073 goto out;
2076 char *clientPath = NULL;
2077 TALLOC_CTX *ctx = talloc_tos();
2079 if ((status = alloc_get_client_path(handle, ctx,
2080 name,
2081 &clientPath)))
2083 goto err;
2086 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2087 acltype, theacl);
2088 err:
2089 TALLOC_FREE(clientPath);
2090 out:
2091 return status;
2095 * Success: return 0
2096 * Failure: set errno, return -1
2098 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2099 const char *path)
2101 int status;
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,
2107 path);
2108 goto out;
2111 char *clientPath = NULL;
2112 TALLOC_CTX *ctx = talloc_tos();
2114 if ((status = alloc_get_client_path(handle, ctx,
2115 path,
2116 &clientPath)))
2118 goto err;
2121 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2122 err:
2123 TALLOC_FREE(clientPath);
2124 out:
2125 return status;
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,
2134 const char *path,
2135 const char *name,
2136 void *value,
2137 size_t size)
2139 ssize_t ret;
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,
2145 size);
2146 goto out;
2149 char *clientPath = NULL;
2150 TALLOC_CTX *ctx = talloc_tos();
2152 if (alloc_get_client_path(handle, ctx,
2153 path,
2154 &clientPath))
2156 ret = -1;
2157 goto err;
2160 ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2161 err:
2162 TALLOC_FREE(clientPath);
2163 out:
2164 return ret;
2168 * Success: return positive number
2169 * Failure: set errno, return -1
2171 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2172 const char *path,
2173 char *list,
2174 size_t size)
2176 ssize_t ret;
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);
2182 goto out;
2185 char *clientPath = NULL;
2186 TALLOC_CTX *ctx = talloc_tos();
2188 if (alloc_get_client_path(handle, ctx,
2189 path,
2190 &clientPath))
2192 ret = -1;
2193 goto err;
2196 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2197 err:
2198 TALLOC_FREE(clientPath);
2199 out:
2200 return ret;
2204 * Success: return 0
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,
2209 const char *path,
2210 const char *name)
2212 int status;
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);
2218 goto out;
2221 char *clientPath = NULL;
2222 TALLOC_CTX *ctx = talloc_tos();
2224 if ((status = alloc_get_client_path(handle, ctx,
2225 path,
2226 &clientPath)))
2228 goto err;
2231 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2232 err:
2233 TALLOC_FREE(clientPath);
2234 out:
2235 return status;
2239 * Success: return 0
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,
2244 const char *path,
2245 const char *name,
2246 const void *value,
2247 size_t size,
2248 int flags)
2250 int status;
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,
2256 size, flags);
2257 goto out;
2260 char *clientPath = NULL;
2261 TALLOC_CTX *ctx = talloc_tos();
2263 if ((status = alloc_get_client_path(handle, ctx,
2264 path,
2265 &clientPath)))
2267 goto err;
2270 status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2271 size, flags);
2272 err:
2273 TALLOC_FREE(clientPath);
2274 out:
2275 return status;
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.
2287 bool ret;
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);
2293 goto out;
2296 struct smb_filename *clientFname = NULL;
2297 TALLOC_CTX *ctx = talloc_tos();
2299 if(alloc_get_client_smb_fname(handle, ctx,
2300 fname,
2301 &clientFname))
2303 ret = -1;
2304 goto err;
2307 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2308 err:
2309 TALLOC_FREE(clientFname);
2310 out:
2311 return ret;
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)
2321 int status;
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);
2327 goto out;
2330 struct smb_filename *clientFname = NULL;
2331 TALLOC_CTX *ctx = talloc_tos();
2333 if ((status = alloc_get_client_smb_fname(handle, ctx,
2334 fname,
2335 &clientFname)))
2337 goto err;
2340 status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2341 err:
2342 TALLOC_FREE(clientFname);
2343 out:
2344 return status;
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 */
2369 .open_fn = mh_open,
2370 .create_file_fn = mh_create_file,
2371 .rename_fn = mh_rename,
2372 .stat_fn = mh_stat,
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,
2383 .link_fn = mh_link,
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))
2421 goto out;
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"));
2430 } else {
2431 DEBUG(3, ("media_harmony_init: Debug class number of "
2432 "'media_harmony': %d\n",
2433 vfs_mh_debug_level));
2436 out:
2437 return ret;