debug: Set close-on-exec for the main log file FD
[Samba.git] / source3 / modules / vfs_media_harmony.c
blobeedbc95ebcf4fc04974fae020bc79a5a95629713
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 int status = 0;
136 char *raddr = NULL;
138 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());
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 bool ret = False;
177 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
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 bool ret = False;
193 char* path_start;
195 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
196 "path '%s'\n", media_dirname, path));
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 bool ret = False;
235 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
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 int transition_count = 0;
268 char* path_start;
269 char* pathPtr;
271 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
272 "path '%s'\n", media_dirname, path));
274 /* Sometimes Samba gives us "./OMFI MediaFiles". */
275 if (strncmp(path, "./", 2) == 0)
277 path_start = &path[2];
279 else {
280 path_start = path;
283 if (path_start[media_dirname_len] == '\0')
285 goto out;
288 pathPtr = &path_start[media_dirname_len + 1];
290 while(1)
292 if (*pathPtr == '\0' || *pathPtr == '/')
294 if (
295 *(pathPtr - 1) == '.'
297 *(pathPtr - 2) == '.'
299 *(pathPtr - 3) == '/'
302 transition_count--;
304 else if (
307 *(pathPtr - 1) == '/'
310 *(pathPtr - 1) == '.'
312 *(pathPtr - 2) == '/'
317 transition_count++;
320 if (*pathPtr == '\0')
322 break;
324 pathPtr++;
327 DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
328 transition_count));
329 out:
330 return transition_count;
333 /* Identifies MDB and PMR files at end of path. */
334 static bool is_avid_database(
335 char *path,
336 size_t path_len,
337 const char *avid_db_filename,
338 const size_t avid_db_filename_len)
340 bool ret = False;
342 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
343 "avid_db_filename '%s', "
344 "path_len '%i', "
345 "avid_db_filename_len '%i'\n",
346 path, avid_db_filename,
347 (int)path_len, (int)avid_db_filename_len));
349 if (
350 path_len > avid_db_filename_len
352 strcmp(&path[path_len - avid_db_filename_len],
353 avid_db_filename) == 0
356 path[path_len - avid_db_filename_len - 1] == '/'
358 path_len > avid_db_filename_len
359 + APPLE_DOUBLE_PREFIX_LEN
361 path[path_len - avid_db_filename_len
362 - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
364 is_apple_double(&path[path_len
365 - avid_db_filename_len
366 - APPLE_DOUBLE_PREFIX_LEN])
370 ret = True;
372 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
373 ret == True ? "True" : "False"));
374 return ret;
378 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
379 * CREATING_SUBDIRNAME.
381 * Caller must free newPath.
383 * Success: return 0
384 * Failure: set errno, newPath NULL, return -1
386 static int alloc_get_client_path(vfs_handle_struct *handle,
387 TALLOC_CTX *ctx,
388 const char *path,
389 char **newPath)
391 /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
392 * directory in path - potentially in middle of path
393 * - with suffixed name.
395 int status = 0;
396 char* pathPtr;
397 size_t intermPathLen;
399 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
401 *newPath = talloc_strdup(ctx, path);
402 if (*newPath == NULL)
404 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
405 errno = ENOMEM;
406 status = -1;
407 goto out;
409 DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
410 if (
411 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
414 *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
416 *(pathPtr + CREATING_DIRNAME_LEN) == '/'
420 pathPtr - path > 0
422 *(pathPtr - 1) == '/'
424 pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
426 *(pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1) == '/'
428 is_apple_double(pathPtr - APPLE_DOUBLE_PREFIX_LEN)
432 /* Insert client suffix into path. */
433 (*newPath)[pathPtr - path + CREATING_DIRNAME_LEN] = '\0';
434 DEBUG(MH_INFO_DEBUG, ("newPath #2 %s\n", *newPath));
436 if ((status = alloc_append_client_suffix(handle, newPath)))
438 goto out;
441 DEBUG(MH_INFO_DEBUG, ("newPath #3 %s\n", *newPath));
442 *newPath = talloc_strdup_append(*newPath,
443 pathPtr + CREATING_DIRNAME_LEN);
444 if (*newPath == NULL)
446 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path "
447 "ENOMEM #2\n"));
448 errno = ENOMEM;
449 status = -1;
450 goto out;
452 DEBUG(MH_INFO_DEBUG, ("newPath #4 %s\n", *newPath));
455 /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
456 * or /._PMR_FILENAME at newPath end with suffixed name.
458 intermPathLen = strlen(*newPath);
459 if (
460 is_avid_database(*newPath, intermPathLen,
461 MDB_FILENAME, MDB_FILENAME_LEN)
463 is_avid_database(*newPath, intermPathLen,
464 PMR_FILENAME, PMR_FILENAME_LEN)
467 DEBUG(MH_INFO_DEBUG, ("newPath #5 %s\n", *newPath));
468 if ((status = alloc_append_client_suffix(handle, newPath)))
470 goto out;
472 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
474 out:
475 /* newPath must be freed in caller. */
476 DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
477 return status;
481 * Success: return 0
482 * Failure: set errno, return -1
484 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
485 TALLOC_CTX *ctx,
486 const struct smb_filename *smb_fname,
487 struct smb_filename **clientFname)
489 int status = 0;
490 NTSTATUS copystatus;
492 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
493 smb_fname->base_name));
495 *clientFname = cp_smb_filename(ctx, smb_fname);
496 if ((*clientFname) == NULL) {
497 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
498 "NTERR\n"));
499 errno = ENOMEM;
500 status = -1;
501 goto err;
503 if ((status = alloc_get_client_path(handle, ctx,
504 smb_fname->base_name,
505 &(*clientFname)->base_name)))
507 goto err;
509 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
510 "'%s'\n", (*clientFname)->base_name));
511 err:
512 return status;
517 * Success: return 0
518 * Failure: set errno, return -1
520 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
521 TALLOC_CTX *ctx,
522 char **path,
523 const char *avid_db_filename)
525 int status = 0;
527 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
528 avid_db_filename));
530 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
532 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
533 "ENOMEM\n"));
534 errno = ENOMEM;
535 status = -1;
536 goto err;
538 if ((status = alloc_append_client_suffix(handle, path)))
540 goto err;
542 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
543 err:
544 return status;
548 * Replace mtime on clientFname with mtime from client-suffixed
549 * equivalent, if it exists.
551 * Success: return 0
552 * Failure: set errno, return -1
554 static int set_fake_mtime(vfs_handle_struct *handle,
555 TALLOC_CTX *ctx,
556 struct smb_filename **clientFname,
557 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
559 int status = 0;
560 char *statPath;
561 SMB_STRUCT_STAT fakeStat;
562 int copy_len;
564 DEBUG(MH_INFO_DEBUG, ("Entering with (*clientFname)->base_name "
565 "'%s', (*clientFname)->st.st_ex_mtime %s",
566 (*clientFname)->base_name,
567 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
569 if (
570 depth_from_media_dir(AVID_MXF_DIRNAME,
571 AVID_MXF_DIRNAME_LEN,
572 (*clientFname)->base_name)
573 != 1
575 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
576 OMFI_MEDIAFILES_DIRNAME_LEN,
577 (*clientFname)->base_name)
578 != 0
581 goto out;
584 copy_len = strlen((*clientFname)->base_name);
586 /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
587 * We know we're under a media dir, so paths are at least 2 chars
588 * long.
590 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
591 (*clientFname)->base_name[copy_len - 2] == '/')
593 copy_len -= 2;
596 if (((statPath = talloc_strndup(ctx,
597 (*clientFname)->base_name, copy_len)) == NULL))
599 errno = ENOMEM;
600 status = -1;
601 goto err;
603 if ((status = alloc_append_client_suffix(handle, &statPath)))
605 goto err;
608 DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
609 if (statFn(statPath, &fakeStat,
610 lp_fake_dir_create_times(SNUM(handle->conn))))
612 /* This can fail for legitimate reasons - i.e. the
613 * fakeStat directory doesn't exist, which is okay
614 * - so we don't set status. But if it does fail,
615 * we need to skip over the mtime assignment.
617 goto err;
620 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
621 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
622 err:
623 TALLOC_FREE(statPath);
624 out:
625 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
626 "'%s', (*clientFname)->st.st_ex_mtime %s",
627 (*clientFname)->base_name,
628 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
629 return status;
633 * Success: return 0
634 * Failure: set errno, return -1
636 static int mh_statvfs(struct vfs_handle_struct *handle,
637 const char *path,
638 struct vfs_statvfs_struct *statbuf)
640 int status;
641 char *clientPath;
642 TALLOC_CTX *ctx;
644 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
646 if (!is_in_media_files(path))
648 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
649 goto out;
652 clientPath = NULL;
653 ctx = talloc_tos();
655 if ((status = alloc_get_client_path(handle, ctx,
656 path,
657 &clientPath)))
659 goto err;
662 status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
663 err:
664 TALLOC_FREE(clientPath);
665 out:
666 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
667 return status;
670 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
671 const char *fname,
672 struct mh_dirinfo_struct **dirInfo)
674 int status = 0;
675 char *clientPath;
676 TALLOC_CTX *ctx;
678 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
680 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
681 if (*dirInfo == NULL)
683 goto err;
686 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
687 if ((*dirInfo)->dirpath == NULL)
689 goto err;
692 if (!is_in_media_files(fname))
694 (*dirInfo)->clientPath = NULL;
695 (*dirInfo)->clientMDBFilename = NULL;
696 (*dirInfo)->clientPMRFilename = NULL;
697 (*dirInfo)->clientCreatingDirname = NULL;
698 (*dirInfo)->isInMediaFiles = False;
699 goto out;
702 (*dirInfo)->isInMediaFiles = True;
704 if (alloc_set_client_dirinfo_path(handle,
705 *dirInfo,
706 &((*dirInfo)->clientMDBFilename),
707 MDB_FILENAME))
709 goto err;
712 if (alloc_set_client_dirinfo_path(handle,
713 *dirInfo,
714 &((*dirInfo)->clientPMRFilename),
715 PMR_FILENAME))
717 goto err;
720 if (alloc_set_client_dirinfo_path(handle,
721 *dirInfo,
722 &((*dirInfo)->clientCreatingDirname),
723 CREATING_DIRNAME))
725 goto err;
728 clientPath = NULL;
729 ctx = talloc_tos();
731 if (alloc_get_client_path(handle, ctx,
732 fname,
733 &clientPath))
735 goto err;
738 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
739 if ((*dirInfo)->clientPath == NULL)
741 goto err;
744 TALLOC_FREE(clientPath);
746 out:
747 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
748 "(*dirInfo)->clientPath '%s'\n",
749 (*dirInfo)->dirpath,
750 (*dirInfo)->clientPath));
751 return status;
753 err:
754 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
755 TALLOC_FREE(*dirInfo);
756 status = -1;
757 errno = ENOMEM;
758 return status;
761 /* Success: return a mh_dirinfo_struct cast as a DIR
762 * Failure: set errno, return NULL
764 static DIR *mh_opendir(vfs_handle_struct *handle,
765 const char *fname,
766 const char *mask,
767 uint32 attr)
769 struct mh_dirinfo_struct *dirInfo;
771 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
773 if (alloc_set_client_dirinfo(handle, fname, &dirInfo))
775 goto err;
778 if (!dirInfo->isInMediaFiles)
780 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
781 fname, mask, attr);
782 } else {
783 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
784 dirInfo->clientPath, mask, attr);
787 if (dirInfo->dirstream == NULL) {
788 goto err;
791 out:
792 /* Success is freed in closedir. */
793 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
794 "dirInfo->clientPath '%s'\n",
795 dirInfo->dirpath,
796 dirInfo->clientPath));
797 return (DIR*)dirInfo;
798 err:
799 /* Failure is freed here. */
800 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
801 TALLOC_FREE(dirInfo);
802 return NULL;
805 static DIR *mh_fdopendir(vfs_handle_struct *handle,
806 files_struct *fsp,
807 const char *mask,
808 uint32 attr)
810 struct mh_dirinfo_struct *dirInfo = NULL;
811 DIR *dirstream;
813 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
814 fsp->fsp_name->base_name));
816 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
817 if (!dirstream)
819 goto err;
822 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
823 &dirInfo))
825 goto err;
828 dirInfo->dirstream = dirstream;
830 if (! dirInfo->isInMediaFiles) {
831 goto out;
834 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
836 goto err;
839 out:
840 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
841 "dirInfo->clientPath '%s', "
842 "fsp->fsp_name->st.st_ex_mtime %s",
843 dirInfo->dirpath,
844 dirInfo->clientPath,
845 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
846 /* Success is freed in closedir. */
847 return (DIR *) dirInfo;
848 err:
849 /* Failure is freed here. */
850 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
851 fsp->fsp_name->base_name));
852 TALLOC_FREE(dirInfo);
853 return NULL;
857 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
858 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
859 * filenames and CREATING_DIRNAME directory, replace this client's
860 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
861 * directory with non suffixed.
863 * Success: return dirent
864 * End of data: return NULL
865 * Failure: set errno, return NULL
867 static struct dirent *mh_readdir(vfs_handle_struct *handle,
868 DIR *dirp,
869 SMB_STRUCT_STAT *sbuf)
871 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
872 struct dirent *d = NULL;
873 int skip;
875 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
877 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
878 "dirInfo->clientPath '%s', "
879 "dirInfo->isInMediaFiles '%s', "
880 "dirInfo->clientMDBFilename '%s', "
881 "dirInfo->clientPMRFilename '%s', "
882 "dirInfo->clientCreatingDirname '%s'\n",
883 dirInfo->dirpath,
884 dirInfo->clientPath,
885 dirInfo->isInMediaFiles ? "True" : "False",
886 dirInfo->clientMDBFilename,
887 dirInfo->clientPMRFilename,
888 dirInfo->clientCreatingDirname));
890 if (! dirInfo->isInMediaFiles)
892 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
893 goto out;
898 const char* dname;
899 bool isAppleDouble;
901 skip = False;
902 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
904 if (d == NULL)
906 break;
909 /* ignore apple double prefix for logic below */
910 if (is_apple_double(d->d_name))
912 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
913 isAppleDouble = True;
915 else
917 dname = d->d_name;
918 isAppleDouble = False;
921 /* skip Avid-special files with no client suffix */
922 if (
923 strcmp(dname, MDB_FILENAME) == 0
925 strcmp(dname, PMR_FILENAME) == 0
927 strcmp(dname, CREATING_DIRNAME) == 0
930 skip = True;
932 /* chop client suffix off this client's suffixed files */
933 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
935 if (isAppleDouble)
937 d->d_name[MDB_FILENAME_LEN
938 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
940 else
942 d->d_name[MDB_FILENAME_LEN] = '\0';
945 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
947 if (isAppleDouble)
949 d->d_name[PMR_FILENAME_LEN
950 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
952 else
954 d->d_name[PMR_FILENAME_LEN] = '\0';
957 else if (strcmp(dname, dirInfo->clientCreatingDirname)
958 == 0)
960 if (isAppleDouble)
962 d->d_name[CREATING_DIRNAME_LEN
963 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
965 else
967 d->d_name[CREATING_DIRNAME_LEN] = '\0';
971 * Anything that starts as an Avid-special file
972 * that's made it this far should be skipped. This
973 * is different from the original behaviour, which
974 * only skipped other client's suffixed files.
976 else if (
977 strncmp(MDB_FILENAME, dname,
978 MDB_FILENAME_LEN) == 0
980 strncmp(PMR_FILENAME, dname,
981 PMR_FILENAME_LEN) == 0
983 strncmp(CREATING_DIRNAME, dname,
984 CREATING_DIRNAME_LEN) == 0
987 skip = True;
990 while (skip);
992 out:
993 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
994 return d;
998 * Success: no success result defined.
999 * Failure: no failure result defined.
1001 static void mh_seekdir(vfs_handle_struct *handle,
1002 DIR *dirp,
1003 long offset)
1005 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1006 SMB_VFS_NEXT_SEEKDIR(handle,
1007 ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1011 * Success: return long
1012 * Failure: no failure result defined.
1014 static long mh_telldir(vfs_handle_struct *handle,
1015 DIR *dirp)
1017 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1018 return SMB_VFS_NEXT_TELLDIR(handle,
1019 ((mh_dirinfo_struct*)dirp)->dirstream);
1023 * Success: no success result defined.
1024 * Failure: no failure result defined.
1026 static void mh_rewinddir(vfs_handle_struct *handle,
1027 DIR *dirp)
1029 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1030 SMB_VFS_NEXT_REWINDDIR(handle,
1031 ((mh_dirinfo_struct*)dirp)->dirstream);
1035 * Success: return 0
1036 * Failure: set errno, return -1
1038 static int mh_mkdir(vfs_handle_struct *handle,
1039 const char *path,
1040 mode_t mode)
1042 int status;
1043 char *clientPath;
1044 TALLOC_CTX *ctx;
1047 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1049 if (!is_in_media_files(path))
1051 status = SMB_VFS_NEXT_MKDIR(handle, path, mode);
1052 goto out;
1055 clientPath = NULL;
1056 ctx = talloc_tos();
1058 if ((status = alloc_get_client_path(handle, ctx,
1059 path,
1060 &clientPath)))
1062 goto err;
1065 status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
1066 err:
1067 TALLOC_FREE(clientPath);
1068 out:
1069 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1070 return status;
1074 * Success: return 0
1075 * Failure: set errno, return -1
1077 static int mh_rmdir(vfs_handle_struct *handle,
1078 const char *path)
1080 int status;
1081 char *clientPath;
1082 TALLOC_CTX *ctx;
1085 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1087 if (!is_in_media_files(path))
1089 status = SMB_VFS_NEXT_RMDIR(handle, path);
1090 goto out;
1093 clientPath = NULL;
1094 ctx = talloc_tos();
1096 if ((status = alloc_get_client_path(handle, ctx,
1097 path,
1098 &clientPath)))
1100 goto err;
1103 status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
1104 err:
1105 TALLOC_FREE(clientPath);
1106 out:
1107 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1108 return status;
1112 * Success: return 0
1113 * Failure: set errno, return -1
1115 static int mh_closedir(vfs_handle_struct *handle,
1116 DIR *dirp)
1118 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1120 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1121 // Will this talloc_free destroy realdirp?
1122 TALLOC_FREE(dirp);
1124 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1125 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1129 * Success: no success result defined.
1130 * Failure: no failure result defined.
1132 static void mh_init_search_op(vfs_handle_struct *handle,
1133 DIR *dirp)
1135 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1136 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1137 ((mh_dirinfo_struct*)dirp)->dirstream);
1141 * Success: return non-negative file descriptor
1142 * Failure: set errno, return -1
1144 static int mh_open(vfs_handle_struct *handle,
1145 struct smb_filename *smb_fname,
1146 files_struct *fsp,
1147 int flags,
1148 mode_t mode)
1150 int ret;
1151 struct smb_filename *clientFname;
1152 TALLOC_CTX *ctx;
1155 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1156 smb_fname->base_name));
1158 if (!is_in_media_files(smb_fname->base_name))
1160 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1161 mode);
1162 goto out;
1165 clientFname = NULL;
1166 ctx = talloc_tos();
1168 if(alloc_get_client_smb_fname(handle, ctx,
1169 smb_fname,
1170 &clientFname))
1172 ret = -1;
1173 goto err;
1176 // What about fsp->fsp_name?
1177 // We also have to get correct stat info into fsp and smb_fname
1178 // for DB files, don't we?
1180 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1181 "smb_fname->st.st_ex_mtime %s"
1182 " fsp->fsp_name->st.st_ex_mtime %s",
1183 smb_fname->base_name,
1184 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1185 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1187 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1188 err:
1189 TALLOC_FREE(clientFname);
1190 out:
1191 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1192 smb_fname->base_name));
1193 return ret;
1197 * Success: return non-negative file descriptor
1198 * Failure: set errno, return -1
1200 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1201 struct smb_request *req,
1202 uint16_t root_dir_fid,
1203 struct smb_filename *smb_fname,
1204 uint32_t access_mask,
1205 uint32_t share_access,
1206 uint32_t create_disposition,
1207 uint32_t create_options,
1208 uint32_t file_attributes,
1209 uint32_t oplock_request,
1210 uint64_t allocation_size,
1211 uint32_t private_flags,
1212 struct security_descriptor *sd,
1213 struct ea_list *ea_list,
1214 files_struct **result_fsp,
1215 int *pinfo)
1217 NTSTATUS status;
1218 struct smb_filename *clientFname;
1219 TALLOC_CTX *ctx;
1222 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1223 smb_fname->base_name));
1224 if (!is_in_media_files(smb_fname->base_name))
1226 status = SMB_VFS_NEXT_CREATE_FILE(
1227 handle,
1228 req,
1229 root_dir_fid,
1230 smb_fname,
1231 access_mask,
1232 share_access,
1233 create_disposition,
1234 create_options,
1235 file_attributes,
1236 oplock_request,
1237 allocation_size,
1238 private_flags,
1240 ea_list,
1241 result_fsp,
1242 pinfo);
1243 goto out;
1246 clientFname = NULL;
1247 ctx = talloc_tos();
1249 if (alloc_get_client_smb_fname(handle, ctx,
1250 smb_fname,
1251 &clientFname))
1253 status = map_nt_error_from_unix(errno);
1254 goto err;
1257 /* This only creates files, so we don't have to worry about
1258 * our fake directory stat'ing here.
1260 // But we still need to route stat calls for DB files
1261 // properly, right?
1262 status = SMB_VFS_NEXT_CREATE_FILE(
1263 handle,
1264 req,
1265 root_dir_fid,
1266 clientFname,
1267 access_mask,
1268 share_access,
1269 create_disposition,
1270 create_options,
1271 file_attributes,
1272 oplock_request,
1273 allocation_size,
1274 private_flags,
1276 ea_list,
1277 result_fsp,
1278 pinfo);
1279 err:
1280 TALLOC_FREE(clientFname);
1281 out:
1282 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1283 "smb_fname->st.st_ex_mtime %s"
1284 " fsp->fsp_name->st.st_ex_mtime %s",
1285 smb_fname->base_name,
1286 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1287 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1288 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1289 "No fsp time\n"));
1290 return status;
1294 * Success: return 0
1295 * Failure: set errno, return -1
1297 static int mh_rename(vfs_handle_struct *handle,
1298 const struct smb_filename *smb_fname_src,
1299 const struct smb_filename *smb_fname_dst)
1301 int status;
1302 struct smb_filename *srcClientFname;
1303 struct smb_filename *dstClientFname;
1304 TALLOC_CTX *ctx;
1307 DEBUG(MH_INFO_DEBUG, ("Entering with "
1308 "smb_fname_src->base_name '%s', "
1309 "smb_fname_dst->base_name '%s'\n",
1310 smb_fname_src->base_name,
1311 smb_fname_dst->base_name));
1313 if (!is_in_media_files(smb_fname_src->base_name)
1315 !is_in_media_files(smb_fname_dst->base_name))
1317 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1318 smb_fname_dst);
1319 goto out;
1322 srcClientFname = NULL;
1323 dstClientFname = NULL;
1324 ctx = talloc_tos();
1326 if ((status = alloc_get_client_smb_fname(handle, ctx,
1327 smb_fname_src,
1328 &srcClientFname)))
1330 goto err;
1333 if ((status = alloc_get_client_smb_fname(handle, ctx,
1334 smb_fname_dst,
1335 &dstClientFname)))
1337 goto err;
1340 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1341 dstClientFname);
1342 err:
1343 TALLOC_FREE(dstClientFname);
1344 TALLOC_FREE(srcClientFname);
1345 out:
1346 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1347 " smb_fname_dst->base_name '%s'\n",
1348 smb_fname_src->base_name,
1349 smb_fname_dst->base_name));
1350 return status;
1354 * Success: return 0
1355 * Failure: set errno, return -1
1357 static int mh_stat(vfs_handle_struct *handle,
1358 struct smb_filename *smb_fname)
1360 int status = 0;
1361 struct smb_filename *clientFname;
1362 TALLOC_CTX *ctx;
1365 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1366 smb_fname->base_name));
1368 if (!is_in_media_files(smb_fname->base_name))
1370 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1371 goto out;
1374 clientFname = NULL;
1375 ctx = talloc_tos();
1377 if ((status = alloc_get_client_smb_fname(handle, ctx,
1378 smb_fname,
1379 &clientFname)))
1381 goto err;
1383 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1384 clientFname->base_name));
1385 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1387 goto err;
1389 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1391 goto err;
1394 /* Unlike functions with const smb_filename, we have to
1395 * modify smb_fname itself to pass our info back up.
1397 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1398 "from clientFname '%s'\n",
1399 smb_fname->base_name,
1400 clientFname->base_name));
1401 smb_fname->st = clientFname->st;
1402 err:
1403 TALLOC_FREE(clientFname);
1404 out:
1405 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1406 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1407 return status;
1411 * Success: return 0
1412 * Failure: set errno, return -1
1414 static int mh_lstat(vfs_handle_struct *handle,
1415 struct smb_filename *smb_fname)
1417 int status = 0;
1418 struct smb_filename *clientFname;
1419 TALLOC_CTX *ctx;
1421 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1422 smb_fname->base_name));
1424 if (!is_in_media_files(smb_fname->base_name))
1426 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1427 goto out;
1430 clientFname = NULL;
1431 ctx = talloc_tos();
1433 if ((status = alloc_get_client_smb_fname(handle, ctx,
1434 smb_fname,
1435 &clientFname)))
1437 goto err;
1439 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1441 goto err;
1444 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1446 goto err;
1448 /* Unlike functions with const smb_filename, we have to
1449 * modify smb_fname itself to pass our info back up.
1451 smb_fname->st = clientFname->st;
1452 err:
1453 TALLOC_FREE(clientFname);
1454 out:
1455 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1456 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1457 return status;
1461 * Success: return 0
1462 * Failure: set errno, return -1
1464 static int mh_fstat(vfs_handle_struct *handle,
1465 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1467 int status = 0;
1469 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1470 "'%s'\n", fsp_str_dbg(fsp)));
1472 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1474 goto out;
1477 if (fsp->fsp_name == NULL
1478 || !is_in_media_files(fsp->fsp_name->base_name))
1480 goto out;
1483 if ((status = mh_stat(handle, fsp->fsp_name)))
1485 goto out;
1488 *sbuf = fsp->fsp_name->st;
1489 out:
1490 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1491 "%s",
1492 fsp->fsp_name != NULL ?
1493 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1494 "0"));
1495 return status;
1499 * Success: return 0
1500 * Failure: set errno, return -1
1502 static int mh_unlink(vfs_handle_struct *handle,
1503 const struct smb_filename *smb_fname)
1505 int status;
1506 struct smb_filename *clientFname;
1507 TALLOC_CTX *ctx;
1509 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1510 if (!is_in_media_files(smb_fname->base_name))
1512 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1513 goto out;
1516 clientFname = NULL;
1517 ctx = talloc_tos();
1519 if ((status = alloc_get_client_smb_fname(handle, ctx,
1520 smb_fname,
1521 &clientFname)))
1523 goto err;
1526 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1527 err:
1528 TALLOC_FREE(clientFname);
1529 out:
1530 return status;
1534 * Success: return 0
1535 * Failure: set errno, return -1
1537 static int mh_chmod(vfs_handle_struct *handle,
1538 const char *path,
1539 mode_t mode)
1541 int status;
1542 char *clientPath;
1543 TALLOC_CTX *ctx;
1545 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1546 if (!is_in_media_files(path))
1548 status = SMB_VFS_NEXT_CHMOD(handle, path, mode);
1549 goto out;
1552 clientPath = NULL;
1553 ctx = talloc_tos();
1555 if ((status = alloc_get_client_path(handle, ctx,
1556 path,
1557 &clientPath)))
1559 goto err;
1562 status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
1563 err:
1564 TALLOC_FREE(clientPath);
1565 out:
1566 return status;
1570 * Success: return 0
1571 * Failure: set errno, return -1
1573 static int mh_chown(vfs_handle_struct *handle,
1574 const char *path,
1575 uid_t uid,
1576 gid_t gid)
1578 int status;
1579 char *clientPath;
1580 TALLOC_CTX *ctx;
1582 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1583 if (!is_in_media_files(path))
1585 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1586 goto out;
1589 clientPath = NULL;
1590 ctx = talloc_tos();
1592 if ((status = alloc_get_client_path(handle, ctx,
1593 path,
1594 &clientPath)))
1596 goto err;
1599 status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1600 err:
1601 TALLOC_FREE(clientPath);
1602 out:
1603 return status;
1607 * Success: return 0
1608 * Failure: set errno, return -1
1610 static int mh_lchown(vfs_handle_struct *handle,
1611 const char *path,
1612 uid_t uid,
1613 gid_t gid)
1615 int status;
1616 char *clientPath;
1617 TALLOC_CTX *ctx;
1619 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1620 if (!is_in_media_files(path))
1622 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1623 goto out;
1626 clientPath = NULL;
1627 ctx = talloc_tos();
1629 if ((status = alloc_get_client_path(handle, ctx,
1630 path,
1631 &clientPath)))
1633 goto err;
1636 status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1637 err:
1638 TALLOC_FREE(clientPath);
1639 out:
1640 return status;
1644 * Success: return 0
1645 * Failure: set errno, return -1
1647 static int mh_chdir(vfs_handle_struct *handle,
1648 const char *path)
1650 int status;
1651 char *clientPath;
1652 TALLOC_CTX *ctx;
1654 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1655 if (!is_in_media_files(path))
1657 status = SMB_VFS_NEXT_CHDIR(handle, path);
1658 goto out;
1661 clientPath = NULL;
1662 ctx = talloc_tos();
1664 if ((status = alloc_get_client_path(handle, ctx,
1665 path,
1666 &clientPath)))
1668 goto err;
1671 status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1672 err:
1673 TALLOC_FREE(clientPath);
1674 out:
1675 return status;
1679 * Success: return 0
1680 * Failure: set errno, return -1
1682 static int mh_ntimes(vfs_handle_struct *handle,
1683 const struct smb_filename *smb_fname,
1684 struct smb_file_time *ft)
1686 int status;
1687 struct smb_filename *clientFname;
1688 TALLOC_CTX *ctx;
1691 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1692 if (!is_in_media_files(smb_fname->base_name))
1694 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1695 goto out;
1698 clientFname = NULL;
1699 ctx = talloc_tos();
1701 if ((status = alloc_get_client_smb_fname(handle, ctx,
1702 smb_fname,
1703 &clientFname)))
1705 goto err;
1708 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1709 err:
1710 TALLOC_FREE(clientFname);
1711 out:
1712 return status;
1716 * Success: return 0
1717 * Failure: set errno, return -1
1719 static int mh_symlink(vfs_handle_struct *handle,
1720 const char *oldpath,
1721 const char *newpath)
1723 int status;
1724 char *oldClientPath;
1725 char *newClientPath;
1726 TALLOC_CTX *ctx;
1728 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1729 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1731 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1732 goto out;
1735 oldClientPath = NULL;
1736 newClientPath = NULL;
1737 ctx = talloc_tos();
1739 if ((status = alloc_get_client_path(handle, ctx,
1740 oldpath,
1741 &oldClientPath)))
1743 goto err;
1746 if ((status = alloc_get_client_path(handle, ctx,
1747 newpath,
1748 &newClientPath)))
1750 goto err;
1753 status = SMB_VFS_NEXT_SYMLINK(handle,
1754 oldClientPath,
1755 newClientPath);
1757 err:
1758 TALLOC_FREE(newClientPath);
1759 TALLOC_FREE(oldClientPath);
1760 out:
1761 return status;
1765 * Success: return byte count
1766 * Failure: set errno, return -1
1768 static int mh_readlink(vfs_handle_struct *handle,
1769 const char *path,
1770 char *buf,
1771 size_t bufsiz)
1773 int status;
1774 char *clientPath;
1775 TALLOC_CTX *ctx;
1777 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1778 if (!is_in_media_files(path))
1780 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1781 goto out;
1784 clientPath = NULL;
1785 ctx = talloc_tos();
1787 if ((status = alloc_get_client_path(handle, ctx,
1788 path,
1789 &clientPath)))
1791 goto err;
1794 status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1795 err:
1796 TALLOC_FREE(clientPath);
1797 out:
1798 return status;
1802 * Success: return 0
1803 * Failure: set errno, return -1
1805 static int mh_link(vfs_handle_struct *handle,
1806 const char *oldpath,
1807 const char *newpath)
1809 int status;
1810 char *oldClientPath;
1811 char *newClientPath;
1812 TALLOC_CTX *ctx;
1814 DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1815 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1817 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1818 goto out;
1821 oldClientPath = NULL;
1822 newClientPath = NULL;
1823 ctx = talloc_tos();
1825 if ((status = alloc_get_client_path(handle, ctx,
1826 oldpath,
1827 &oldClientPath)))
1829 goto err;
1832 if ((status = alloc_get_client_path(handle, ctx,
1833 newpath,
1834 &newClientPath)))
1836 goto err;
1839 status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1840 err:
1841 TALLOC_FREE(newClientPath);
1842 TALLOC_FREE(oldClientPath);
1843 out:
1844 return status;
1848 * Success: return 0
1849 * Failure: set errno, return -1
1851 static int mh_mknod(vfs_handle_struct *handle,
1852 const char *pathname,
1853 mode_t mode,
1854 SMB_DEV_T dev)
1856 int status;
1857 char *clientPath;
1858 TALLOC_CTX *ctx;
1860 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1861 if (!is_in_media_files(pathname))
1863 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1864 goto out;
1867 clientPath = NULL;
1868 ctx = talloc_tos();
1870 if ((status = alloc_get_client_path(handle, ctx,
1871 pathname,
1872 &clientPath)))
1874 goto err;
1877 status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1878 err:
1879 TALLOC_FREE(clientPath);
1880 out:
1881 return status;
1885 * Success: return path pointer
1886 * Failure: set errno, return NULL pointer
1888 static char *mh_realpath(vfs_handle_struct *handle,
1889 const char *path)
1891 char *buf;
1892 char *clientPath;
1893 TALLOC_CTX *ctx;
1895 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1896 if (!is_in_media_files(path))
1898 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1899 goto out;
1902 clientPath = NULL;
1903 ctx = talloc_tos();
1905 if (alloc_get_client_path(handle, ctx,
1906 path,
1907 &clientPath))
1909 buf = NULL;
1910 goto err;
1913 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1914 err:
1915 TALLOC_FREE(clientPath);
1916 out:
1917 return buf;
1921 * Success: return 0
1922 * Failure: set errno, return -1
1924 static int mh_chflags(vfs_handle_struct *handle,
1925 const char *path,
1926 unsigned int flags)
1928 int status;
1929 char *clientPath;
1930 TALLOC_CTX *ctx;
1932 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1933 if (!is_in_media_files(path))
1935 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1936 goto out;
1939 clientPath = NULL;
1940 ctx = talloc_tos();
1942 if ((status = alloc_get_client_path(handle, ctx,
1943 path,
1944 &clientPath)))
1946 goto err;
1949 status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1950 err:
1951 TALLOC_FREE(clientPath);
1952 out:
1953 return status;
1957 * Success: return NT_STATUS_OK
1958 * Failure: return NT status error
1960 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1961 struct files_struct *fsp,
1962 const char *fname,
1963 TALLOC_CTX *ctx,
1964 unsigned int *num_streams,
1965 struct stream_struct **streams)
1967 NTSTATUS status;
1968 char *clientPath;
1969 TALLOC_CTX *mem_ctx;
1971 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1972 if (!is_in_media_files(fname))
1974 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1975 ctx, num_streams, streams);
1976 goto out;
1979 clientPath = NULL;
1980 mem_ctx = talloc_tos();
1982 if (alloc_get_client_path(handle, mem_ctx,
1983 fname,
1984 &clientPath))
1986 status = map_nt_error_from_unix(errno);
1987 goto err;
1990 /* This only works on files, so we don't have to worry about
1991 * our fake directory stat'ing here.
1993 // But what does this function do, exactly? Does it need
1994 // extra modifications for the Avid stuff?
1995 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
1996 ctx, num_streams, streams);
1997 err:
1998 TALLOC_FREE(clientPath);
1999 out:
2000 return status;
2003 /* Ignoring get_real_filename function because the default
2004 * doesn't do anything.
2008 * Success: return NT_STATUS_OK
2009 * Failure: return NT status error
2010 * In this case, "name" is a path.
2012 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2013 const char *name,
2014 uint32 security_info,
2015 TALLOC_CTX *mem_ctx,
2016 struct security_descriptor **ppdesc)
2018 NTSTATUS status;
2019 char *clientPath;
2020 TALLOC_CTX *ctx;
2022 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2023 if (!is_in_media_files(name))
2025 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name,
2026 security_info,
2027 mem_ctx, ppdesc);
2028 goto out;
2031 clientPath = NULL;
2032 ctx = talloc_tos();
2034 if (alloc_get_client_path(handle, ctx,
2035 name,
2036 &clientPath))
2038 status = map_nt_error_from_unix(errno);
2039 goto err;
2042 status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
2043 security_info,
2044 mem_ctx, ppdesc);
2045 err:
2046 TALLOC_FREE(clientPath);
2047 out:
2048 return status;
2052 * Success: return 0
2053 * Failure: set errno, return -1
2055 static int mh_chmod_acl(vfs_handle_struct *handle,
2056 const char *path,
2057 mode_t mode)
2059 int status;
2060 char *clientPath;
2061 TALLOC_CTX *ctx;
2063 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2064 if (!is_in_media_files(path))
2066 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2067 goto out;
2070 clientPath = NULL;
2071 ctx = talloc_tos();
2073 if ((status = alloc_get_client_path(handle, ctx,
2074 path,
2075 &clientPath)))
2077 goto err;
2080 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2081 err:
2082 TALLOC_FREE(clientPath);
2083 out:
2084 return status;
2088 * Success: return acl pointer
2089 * Failure: set errno, return NULL
2091 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2092 const char *path_p,
2093 SMB_ACL_TYPE_T type,
2094 TALLOC_CTX *mem_ctx)
2096 SMB_ACL_T ret;
2097 char *clientPath;
2098 TALLOC_CTX *ctx;
2100 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2101 if (!is_in_media_files(path_p))
2103 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2104 goto out;
2107 clientPath = NULL;
2108 ctx = talloc_tos();
2110 if (alloc_get_client_path(handle, ctx,
2111 path_p,
2112 &clientPath))
2114 ret = NULL;
2115 goto err;
2118 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2119 err:
2120 TALLOC_FREE(clientPath);
2121 out:
2122 return ret;
2126 * Success: return 0
2127 * Failure: set errno, return -1
2128 * In this case, "name" is a path.
2130 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2131 const char *name,
2132 SMB_ACL_TYPE_T acltype,
2133 SMB_ACL_T theacl)
2135 int status;
2136 char *clientPath;
2137 TALLOC_CTX *ctx;
2139 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2140 if (!is_in_media_files(name))
2142 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2143 acltype, theacl);
2144 goto out;
2147 clientPath = NULL;
2148 ctx = talloc_tos();
2150 if ((status = alloc_get_client_path(handle, ctx,
2151 name,
2152 &clientPath)))
2154 goto err;
2157 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2158 acltype, theacl);
2159 err:
2160 TALLOC_FREE(clientPath);
2161 out:
2162 return status;
2166 * Success: return 0
2167 * Failure: set errno, return -1
2169 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2170 const char *path)
2172 int status;
2173 char *clientPath;
2174 TALLOC_CTX *ctx;
2176 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2177 if (!is_in_media_files(path))
2179 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2180 path);
2181 goto out;
2184 clientPath = NULL;
2185 ctx = talloc_tos();
2187 if ((status = alloc_get_client_path(handle, ctx,
2188 path,
2189 &clientPath)))
2191 goto err;
2194 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2195 err:
2196 TALLOC_FREE(clientPath);
2197 out:
2198 return status;
2202 * Success: return positive number
2203 * Failure: set errno, return -1
2204 * In this case, "name" is an attr name.
2206 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2207 const char *path,
2208 const char *name,
2209 void *value,
2210 size_t size)
2212 ssize_t ret;
2213 char *clientPath;
2214 TALLOC_CTX *ctx;
2216 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2217 if (!is_in_media_files(path))
2219 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2220 size);
2221 goto out;
2224 clientPath = NULL;
2225 ctx = talloc_tos();
2227 if (alloc_get_client_path(handle, ctx,
2228 path,
2229 &clientPath))
2231 ret = -1;
2232 goto err;
2235 ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2236 err:
2237 TALLOC_FREE(clientPath);
2238 out:
2239 return ret;
2243 * Success: return positive number
2244 * Failure: set errno, return -1
2246 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2247 const char *path,
2248 char *list,
2249 size_t size)
2251 ssize_t ret;
2252 char *clientPath;
2253 TALLOC_CTX *ctx;
2255 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2256 if (!is_in_media_files(path))
2258 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2259 goto out;
2262 clientPath = NULL;
2263 ctx = talloc_tos();
2265 if (alloc_get_client_path(handle, ctx,
2266 path,
2267 &clientPath))
2269 ret = -1;
2270 goto err;
2273 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2274 err:
2275 TALLOC_FREE(clientPath);
2276 out:
2277 return ret;
2281 * Success: return 0
2282 * Failure: set errno, return -1
2283 * In this case, "name" is an attr name.
2285 static int mh_removexattr(struct vfs_handle_struct *handle,
2286 const char *path,
2287 const char *name)
2289 int status;
2290 char *clientPath;
2291 TALLOC_CTX *ctx;
2293 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2294 if (!is_in_media_files(path))
2296 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2297 goto out;
2300 clientPath = NULL;
2301 ctx = talloc_tos();
2303 if ((status = alloc_get_client_path(handle, ctx,
2304 path,
2305 &clientPath)))
2307 goto err;
2310 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2311 err:
2312 TALLOC_FREE(clientPath);
2313 out:
2314 return status;
2318 * Success: return 0
2319 * Failure: set errno, return -1
2320 * In this case, "name" is an attr name.
2322 static int mh_setxattr(struct vfs_handle_struct *handle,
2323 const char *path,
2324 const char *name,
2325 const void *value,
2326 size_t size,
2327 int flags)
2329 int status;
2330 char *clientPath;
2331 TALLOC_CTX *ctx;
2333 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2334 if (!is_in_media_files(path))
2336 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2337 size, flags);
2338 goto out;
2341 clientPath = NULL;
2342 ctx = talloc_tos();
2344 if ((status = alloc_get_client_path(handle, ctx,
2345 path,
2346 &clientPath)))
2348 goto err;
2351 status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2352 size, flags);
2353 err:
2354 TALLOC_FREE(clientPath);
2355 out:
2356 return status;
2360 * Success: return true
2361 * Failure: set errno, return false
2363 static bool mh_is_offline(struct vfs_handle_struct *handle,
2364 const struct smb_filename *fname,
2365 SMB_STRUCT_STAT *sbuf)
2367 // check if sbuf is modified further down the chain.
2368 bool ret;
2369 struct smb_filename *clientFname;
2370 TALLOC_CTX *ctx;
2372 DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2373 if (!is_in_media_files(fname->base_name))
2375 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2376 goto out;
2379 clientFname = NULL;
2380 ctx = talloc_tos();
2382 if(alloc_get_client_smb_fname(handle, ctx,
2383 fname,
2384 &clientFname))
2386 ret = -1;
2387 goto err;
2390 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2391 err:
2392 TALLOC_FREE(clientFname);
2393 out:
2394 return ret;
2398 * Success: return 0 (?)
2399 * Failure: set errno, return -1
2401 static int mh_set_offline(struct vfs_handle_struct *handle,
2402 const struct smb_filename *fname)
2404 int status;
2405 struct smb_filename *clientFname;
2406 TALLOC_CTX *ctx;
2408 DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2409 if (!is_in_media_files(fname->base_name))
2411 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2412 goto out;
2415 clientFname = NULL;
2416 ctx = talloc_tos();
2418 if ((status = alloc_get_client_smb_fname(handle, ctx,
2419 fname,
2420 &clientFname)))
2422 goto err;
2425 status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2426 err:
2427 TALLOC_FREE(clientFname);
2428 out:
2429 return status;
2432 /* VFS operations structure */
2434 static struct vfs_fn_pointers vfs_mh_fns = {
2435 /* Disk operations */
2437 .statvfs_fn = mh_statvfs,
2439 /* Directory operations */
2441 .opendir_fn = mh_opendir,
2442 .fdopendir_fn = mh_fdopendir,
2443 .readdir_fn = mh_readdir,
2444 .seekdir_fn = mh_seekdir,
2445 .telldir_fn = mh_telldir,
2446 .rewind_dir_fn = mh_rewinddir,
2447 .mkdir_fn = mh_mkdir,
2448 .rmdir_fn = mh_rmdir,
2449 .closedir_fn = mh_closedir,
2450 .init_search_op_fn = mh_init_search_op,
2452 /* File operations */
2454 .open_fn = mh_open,
2455 .create_file_fn = mh_create_file,
2456 .rename_fn = mh_rename,
2457 .stat_fn = mh_stat,
2458 .lstat_fn = mh_lstat,
2459 .fstat_fn = mh_fstat,
2460 .unlink_fn = mh_unlink,
2461 .chmod_fn = mh_chmod,
2462 .chown_fn = mh_chown,
2463 .lchown_fn = mh_lchown,
2464 .chdir_fn = mh_chdir,
2465 .ntimes_fn = mh_ntimes,
2466 .symlink_fn = mh_symlink,
2467 .readlink_fn = mh_readlink,
2468 .link_fn = mh_link,
2469 .mknod_fn = mh_mknod,
2470 .realpath_fn = mh_realpath,
2471 .chflags_fn = mh_chflags,
2472 .streaminfo_fn = mh_streaminfo,
2474 /* NT ACL operations. */
2476 .get_nt_acl_fn = mh_get_nt_acl,
2478 /* POSIX ACL operations. */
2480 .chmod_acl_fn = mh_chmod_acl,
2482 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2483 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2484 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2486 /* EA operations. */
2487 .getxattr_fn = mh_getxattr,
2488 .listxattr_fn = mh_listxattr,
2489 .removexattr_fn = mh_removexattr,
2490 .setxattr_fn = mh_setxattr,
2492 /* aio operations */
2494 /* offline operations */
2495 .is_offline_fn = mh_is_offline,
2496 .set_offline_fn = mh_set_offline
2499 NTSTATUS vfs_media_harmony_init(void);
2500 NTSTATUS vfs_media_harmony_init(void)
2502 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2503 "media_harmony", &vfs_mh_fns);
2504 if (!NT_STATUS_IS_OK(ret))
2506 goto out;
2509 vfs_mh_debug_level = debug_add_class("media_harmony");
2511 if (vfs_mh_debug_level == -1) {
2512 vfs_mh_debug_level = DBGC_VFS;
2513 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2514 "debugging class.\n"));
2515 } else {
2516 DEBUG(3, ("media_harmony_init: Debug class number of "
2517 "'media_harmony': %d\n",
2518 vfs_mh_debug_level));
2521 out:
2522 return ret;