s3:modules: s/struct timed_event/struct tevent_timer
[Samba/gebeck_regimport.git] / source3 / modules / vfs_media_harmony.c
blob79b165c794f59803a468949522b8547a3c0f46f8
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 copystatus = copy_smb_filename(ctx, smb_fname, clientFname);
496 if (!NT_STATUS_IS_OK(copystatus))
498 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
499 "NTERR\n"));
500 errno = map_errno_from_nt_status(copystatus);
501 status = -1;
502 goto err;
504 if ((status = alloc_get_client_path(handle, ctx,
505 smb_fname->base_name,
506 &(*clientFname)->base_name)))
508 goto err;
510 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
511 "'%s'\n", (*clientFname)->base_name));
512 err:
513 return status;
518 * Success: return 0
519 * Failure: set errno, return -1
521 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
522 TALLOC_CTX *ctx,
523 char **path,
524 const char *avid_db_filename)
526 int status = 0;
528 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
529 avid_db_filename));
531 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
533 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
534 "ENOMEM\n"));
535 errno = ENOMEM;
536 status = -1;
537 goto err;
539 if ((status = alloc_append_client_suffix(handle, path)))
541 goto err;
543 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
544 err:
545 return status;
549 * Replace mtime on clientFname with mtime from client-suffixed
550 * equivalent, if it exists.
552 * Success: return 0
553 * Failure: set errno, return -1
555 static int set_fake_mtime(vfs_handle_struct *handle,
556 TALLOC_CTX *ctx,
557 struct smb_filename **clientFname,
558 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
560 int status = 0;
561 char *statPath;
562 SMB_STRUCT_STAT fakeStat;
563 int copy_len;
565 DEBUG(MH_INFO_DEBUG, ("Entering with (*clientFname)->base_name "
566 "'%s', (*clientFname)->st.st_ex_mtime %s",
567 (*clientFname)->base_name,
568 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
570 if (
571 depth_from_media_dir(AVID_MXF_DIRNAME,
572 AVID_MXF_DIRNAME_LEN,
573 (*clientFname)->base_name)
574 != 1
576 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
577 OMFI_MEDIAFILES_DIRNAME_LEN,
578 (*clientFname)->base_name)
579 != 0
582 goto out;
585 copy_len = strlen((*clientFname)->base_name);
587 /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
588 * We know we're under a media dir, so paths are at least 2 chars
589 * long.
591 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
592 (*clientFname)->base_name[copy_len - 2] == '/')
594 copy_len -= 2;
597 if (((statPath = talloc_strndup(ctx,
598 (*clientFname)->base_name, copy_len)) == NULL))
600 errno = ENOMEM;
601 status = -1;
602 goto err;
604 if ((status = alloc_append_client_suffix(handle, &statPath)))
606 goto err;
609 DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
610 if (statFn(statPath, &fakeStat,
611 lp_fake_dir_create_times(SNUM(handle->conn))))
613 /* This can fail for legitimate reasons - i.e. the
614 * fakeStat directory doesn't exist, which is okay
615 * - so we don't set status. But if it does fail,
616 * we need to skip over the mtime assignment.
618 goto err;
621 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
622 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
623 err:
624 TALLOC_FREE(statPath);
625 out:
626 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
627 "'%s', (*clientFname)->st.st_ex_mtime %s",
628 (*clientFname)->base_name,
629 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
630 return status;
634 * Success: return 0
635 * Failure: set errno, return -1
637 static int mh_statvfs(struct vfs_handle_struct *handle,
638 const char *path,
639 struct vfs_statvfs_struct *statbuf)
641 int status;
642 char *clientPath;
643 TALLOC_CTX *ctx;
645 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
647 if (!is_in_media_files(path))
649 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
650 goto out;
653 clientPath = NULL;
654 ctx = talloc_tos();
656 if ((status = alloc_get_client_path(handle, ctx,
657 path,
658 &clientPath)))
660 goto err;
663 status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
664 err:
665 TALLOC_FREE(clientPath);
666 out:
667 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
668 return status;
671 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
672 const char *fname,
673 struct mh_dirinfo_struct **dirInfo)
675 int status = 0;
676 char *clientPath;
677 TALLOC_CTX *ctx;
679 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
681 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
682 if (*dirInfo == NULL)
684 goto err;
687 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
688 if ((*dirInfo)->dirpath == NULL)
690 goto err;
693 if (!is_in_media_files(fname))
695 (*dirInfo)->clientPath = NULL;
696 (*dirInfo)->clientMDBFilename = NULL;
697 (*dirInfo)->clientPMRFilename = NULL;
698 (*dirInfo)->clientCreatingDirname = NULL;
699 (*dirInfo)->isInMediaFiles = False;
700 goto out;
703 (*dirInfo)->isInMediaFiles = True;
705 if (alloc_set_client_dirinfo_path(handle,
706 *dirInfo,
707 &((*dirInfo)->clientMDBFilename),
708 MDB_FILENAME))
710 goto err;
713 if (alloc_set_client_dirinfo_path(handle,
714 *dirInfo,
715 &((*dirInfo)->clientPMRFilename),
716 PMR_FILENAME))
718 goto err;
721 if (alloc_set_client_dirinfo_path(handle,
722 *dirInfo,
723 &((*dirInfo)->clientCreatingDirname),
724 CREATING_DIRNAME))
726 goto err;
729 clientPath = NULL;
730 ctx = talloc_tos();
732 if (alloc_get_client_path(handle, ctx,
733 fname,
734 &clientPath))
736 goto err;
739 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
740 if ((*dirInfo)->clientPath == NULL)
742 goto err;
745 TALLOC_FREE(clientPath);
747 out:
748 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
749 "(*dirInfo)->clientPath '%s'\n",
750 (*dirInfo)->dirpath,
751 (*dirInfo)->clientPath));
752 return status;
754 err:
755 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
756 TALLOC_FREE(*dirInfo);
757 status = -1;
758 errno = ENOMEM;
759 return status;
762 /* Success: return a mh_dirinfo_struct cast as a DIR
763 * Failure: set errno, return NULL
765 static DIR *mh_opendir(vfs_handle_struct *handle,
766 const char *fname,
767 const char *mask,
768 uint32 attr)
770 struct mh_dirinfo_struct *dirInfo;
772 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
774 if (alloc_set_client_dirinfo(handle, fname, &dirInfo))
776 goto err;
779 if (!dirInfo->isInMediaFiles)
781 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
782 fname, mask, attr);
783 } else {
784 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
785 dirInfo->clientPath, mask, attr);
788 if (dirInfo->dirstream == NULL) {
789 goto err;
792 out:
793 /* Success is freed in closedir. */
794 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
795 "dirInfo->clientPath '%s'\n",
796 dirInfo->dirpath,
797 dirInfo->clientPath));
798 return (DIR*)dirInfo;
799 err:
800 /* Failure is freed here. */
801 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
802 TALLOC_FREE(dirInfo);
803 return NULL;
806 static DIR *mh_fdopendir(vfs_handle_struct *handle,
807 files_struct *fsp,
808 const char *mask,
809 uint32 attr)
811 struct mh_dirinfo_struct *dirInfo = NULL;
812 DIR *dirstream;
814 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
815 fsp->fsp_name->base_name));
817 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
818 if (!dirstream)
820 goto err;
823 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
824 &dirInfo))
826 goto err;
829 dirInfo->dirstream = dirstream;
831 if (! dirInfo->isInMediaFiles) {
832 goto out;
835 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
837 goto err;
840 out:
841 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
842 "dirInfo->clientPath '%s', "
843 "fsp->fsp_name->st.st_ex_mtime %s",
844 dirInfo->dirpath,
845 dirInfo->clientPath,
846 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
847 /* Success is freed in closedir. */
848 return (DIR *) dirInfo;
849 err:
850 /* Failure is freed here. */
851 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
852 fsp->fsp_name->base_name));
853 TALLOC_FREE(dirInfo);
854 return NULL;
858 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
859 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
860 * filenames and CREATING_DIRNAME directory, replace this client's
861 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
862 * directory with non suffixed.
864 * Success: return dirent
865 * End of data: return NULL
866 * Failure: set errno, return NULL
868 static struct dirent *mh_readdir(vfs_handle_struct *handle,
869 DIR *dirp,
870 SMB_STRUCT_STAT *sbuf)
872 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
873 struct dirent *d = NULL;
874 int skip;
876 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
878 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
879 "dirInfo->clientPath '%s', "
880 "dirInfo->isInMediaFiles '%s', "
881 "dirInfo->clientMDBFilename '%s', "
882 "dirInfo->clientPMRFilename '%s', "
883 "dirInfo->clientCreatingDirname '%s'\n",
884 dirInfo->dirpath,
885 dirInfo->clientPath,
886 dirInfo->isInMediaFiles ? "True" : "False",
887 dirInfo->clientMDBFilename,
888 dirInfo->clientPMRFilename,
889 dirInfo->clientCreatingDirname));
891 if (! dirInfo->isInMediaFiles)
893 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
894 goto out;
899 const char* dname;
900 bool isAppleDouble;
902 skip = False;
903 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
905 if (d == NULL)
907 break;
910 /* ignore apple double prefix for logic below */
911 if (is_apple_double(d->d_name))
913 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
914 isAppleDouble = True;
916 else
918 dname = d->d_name;
919 isAppleDouble = False;
922 /* skip Avid-special files with no client suffix */
923 if (
924 strcmp(dname, MDB_FILENAME) == 0
926 strcmp(dname, PMR_FILENAME) == 0
928 strcmp(dname, CREATING_DIRNAME) == 0
931 skip = True;
933 /* chop client suffix off this client's suffixed files */
934 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
936 if (isAppleDouble)
938 d->d_name[MDB_FILENAME_LEN
939 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
941 else
943 d->d_name[MDB_FILENAME_LEN] = '\0';
946 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
948 if (isAppleDouble)
950 d->d_name[PMR_FILENAME_LEN
951 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
953 else
955 d->d_name[PMR_FILENAME_LEN] = '\0';
958 else if (strcmp(dname, dirInfo->clientCreatingDirname)
959 == 0)
961 if (isAppleDouble)
963 d->d_name[CREATING_DIRNAME_LEN
964 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
966 else
968 d->d_name[CREATING_DIRNAME_LEN] = '\0';
972 * Anything that starts as an Avid-special file
973 * that's made it this far should be skipped. This
974 * is different from the original behaviour, which
975 * only skipped other client's suffixed files.
977 else if (
978 strncmp(MDB_FILENAME, dname,
979 MDB_FILENAME_LEN) == 0
981 strncmp(PMR_FILENAME, dname,
982 PMR_FILENAME_LEN) == 0
984 strncmp(CREATING_DIRNAME, dname,
985 CREATING_DIRNAME_LEN) == 0
988 skip = True;
991 while (skip);
993 out:
994 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
995 return d;
999 * Success: no success result defined.
1000 * Failure: no failure result defined.
1002 static void mh_seekdir(vfs_handle_struct *handle,
1003 DIR *dirp,
1004 long offset)
1006 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1007 SMB_VFS_NEXT_SEEKDIR(handle,
1008 ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1012 * Success: return long
1013 * Failure: no failure result defined.
1015 static long mh_telldir(vfs_handle_struct *handle,
1016 DIR *dirp)
1018 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1019 return SMB_VFS_NEXT_TELLDIR(handle,
1020 ((mh_dirinfo_struct*)dirp)->dirstream);
1024 * Success: no success result defined.
1025 * Failure: no failure result defined.
1027 static void mh_rewinddir(vfs_handle_struct *handle,
1028 DIR *dirp)
1030 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1031 SMB_VFS_NEXT_REWINDDIR(handle,
1032 ((mh_dirinfo_struct*)dirp)->dirstream);
1036 * Success: return 0
1037 * Failure: set errno, return -1
1039 static int mh_mkdir(vfs_handle_struct *handle,
1040 const char *path,
1041 mode_t mode)
1043 int status;
1044 char *clientPath;
1045 TALLOC_CTX *ctx;
1048 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1050 if (!is_in_media_files(path))
1052 status = SMB_VFS_NEXT_MKDIR(handle, path, mode);
1053 goto out;
1056 clientPath = NULL;
1057 ctx = talloc_tos();
1059 if ((status = alloc_get_client_path(handle, ctx,
1060 path,
1061 &clientPath)))
1063 goto err;
1066 status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
1067 err:
1068 TALLOC_FREE(clientPath);
1069 out:
1070 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1071 return status;
1075 * Success: return 0
1076 * Failure: set errno, return -1
1078 static int mh_rmdir(vfs_handle_struct *handle,
1079 const char *path)
1081 int status;
1082 char *clientPath;
1083 TALLOC_CTX *ctx;
1086 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1088 if (!is_in_media_files(path))
1090 status = SMB_VFS_NEXT_RMDIR(handle, path);
1091 goto out;
1094 clientPath = NULL;
1095 ctx = talloc_tos();
1097 if ((status = alloc_get_client_path(handle, ctx,
1098 path,
1099 &clientPath)))
1101 goto err;
1104 status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
1105 err:
1106 TALLOC_FREE(clientPath);
1107 out:
1108 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1109 return status;
1113 * Success: return 0
1114 * Failure: set errno, return -1
1116 static int mh_closedir(vfs_handle_struct *handle,
1117 DIR *dirp)
1119 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1121 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1122 // Will this talloc_free destroy realdirp?
1123 TALLOC_FREE(dirp);
1125 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1126 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1130 * Success: no success result defined.
1131 * Failure: no failure result defined.
1133 static void mh_init_search_op(vfs_handle_struct *handle,
1134 DIR *dirp)
1136 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1137 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1138 ((mh_dirinfo_struct*)dirp)->dirstream);
1142 * Success: return non-negative file descriptor
1143 * Failure: set errno, return -1
1145 static int mh_open(vfs_handle_struct *handle,
1146 struct smb_filename *smb_fname,
1147 files_struct *fsp,
1148 int flags,
1149 mode_t mode)
1151 int ret;
1152 struct smb_filename *clientFname;
1153 TALLOC_CTX *ctx;
1156 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1157 smb_fname->base_name));
1159 if (!is_in_media_files(smb_fname->base_name))
1161 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1162 mode);
1163 goto out;
1166 clientFname = NULL;
1167 ctx = talloc_tos();
1169 if(alloc_get_client_smb_fname(handle, ctx,
1170 smb_fname,
1171 &clientFname))
1173 ret = -1;
1174 goto err;
1177 // What about fsp->fsp_name?
1178 // We also have to get correct stat info into fsp and smb_fname
1179 // for DB files, don't we?
1181 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1182 "smb_fname->st.st_ex_mtime %s"
1183 " fsp->fsp_name->st.st_ex_mtime %s",
1184 smb_fname->base_name,
1185 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1186 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1188 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1189 err:
1190 TALLOC_FREE(clientFname);
1191 out:
1192 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1193 smb_fname->base_name));
1194 return ret;
1198 * Success: return non-negative file descriptor
1199 * Failure: set errno, return -1
1201 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1202 struct smb_request *req,
1203 uint16_t root_dir_fid,
1204 struct smb_filename *smb_fname,
1205 uint32_t access_mask,
1206 uint32_t share_access,
1207 uint32_t create_disposition,
1208 uint32_t create_options,
1209 uint32_t file_attributes,
1210 uint32_t oplock_request,
1211 uint64_t allocation_size,
1212 uint32_t private_flags,
1213 struct security_descriptor *sd,
1214 struct ea_list *ea_list,
1215 files_struct **result_fsp,
1216 int *pinfo)
1218 NTSTATUS status;
1219 struct smb_filename *clientFname;
1220 TALLOC_CTX *ctx;
1223 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1224 smb_fname->base_name));
1225 if (!is_in_media_files(smb_fname->base_name))
1227 status = SMB_VFS_NEXT_CREATE_FILE(
1228 handle,
1229 req,
1230 root_dir_fid,
1231 smb_fname,
1232 access_mask,
1233 share_access,
1234 create_disposition,
1235 create_options,
1236 file_attributes,
1237 oplock_request,
1238 allocation_size,
1239 private_flags,
1241 ea_list,
1242 result_fsp,
1243 pinfo);
1244 goto out;
1247 clientFname = NULL;
1248 ctx = talloc_tos();
1250 if (alloc_get_client_smb_fname(handle, ctx,
1251 smb_fname,
1252 &clientFname))
1254 status = map_nt_error_from_unix(errno);
1255 goto err;
1258 /* This only creates files, so we don't have to worry about
1259 * our fake directory stat'ing here.
1261 // But we still need to route stat calls for DB files
1262 // properly, right?
1263 status = SMB_VFS_NEXT_CREATE_FILE(
1264 handle,
1265 req,
1266 root_dir_fid,
1267 clientFname,
1268 access_mask,
1269 share_access,
1270 create_disposition,
1271 create_options,
1272 file_attributes,
1273 oplock_request,
1274 allocation_size,
1275 private_flags,
1277 ea_list,
1278 result_fsp,
1279 pinfo);
1280 err:
1281 TALLOC_FREE(clientFname);
1282 out:
1283 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1284 "smb_fname->st.st_ex_mtime %s"
1285 " fsp->fsp_name->st.st_ex_mtime %s",
1286 smb_fname->base_name,
1287 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1288 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1289 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1290 "No fsp time\n"));
1291 return status;
1295 * Success: return 0
1296 * Failure: set errno, return -1
1298 static int mh_rename(vfs_handle_struct *handle,
1299 const struct smb_filename *smb_fname_src,
1300 const struct smb_filename *smb_fname_dst)
1302 int status;
1303 struct smb_filename *srcClientFname;
1304 struct smb_filename *dstClientFname;
1305 TALLOC_CTX *ctx;
1308 DEBUG(MH_INFO_DEBUG, ("Entering with "
1309 "smb_fname_src->base_name '%s', "
1310 "smb_fname_dst->base_name '%s'\n",
1311 smb_fname_src->base_name,
1312 smb_fname_dst->base_name));
1314 if (!is_in_media_files(smb_fname_src->base_name)
1316 !is_in_media_files(smb_fname_dst->base_name))
1318 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1319 smb_fname_dst);
1320 goto out;
1323 srcClientFname = NULL;
1324 dstClientFname = NULL;
1325 ctx = talloc_tos();
1327 if ((status = alloc_get_client_smb_fname(handle, ctx,
1328 smb_fname_src,
1329 &srcClientFname)))
1331 goto err;
1334 if ((status = alloc_get_client_smb_fname(handle, ctx,
1335 smb_fname_dst,
1336 &dstClientFname)))
1338 goto err;
1341 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1342 dstClientFname);
1343 err:
1344 TALLOC_FREE(dstClientFname);
1345 TALLOC_FREE(srcClientFname);
1346 out:
1347 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1348 " smb_fname_dst->base_name '%s'\n",
1349 smb_fname_src->base_name,
1350 smb_fname_dst->base_name));
1351 return status;
1355 * Success: return 0
1356 * Failure: set errno, return -1
1358 static int mh_stat(vfs_handle_struct *handle,
1359 struct smb_filename *smb_fname)
1361 int status = 0;
1362 struct smb_filename *clientFname;
1363 TALLOC_CTX *ctx;
1366 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1367 smb_fname->base_name));
1369 if (!is_in_media_files(smb_fname->base_name))
1371 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1372 goto out;
1375 clientFname = NULL;
1376 ctx = talloc_tos();
1378 if ((status = alloc_get_client_smb_fname(handle, ctx,
1379 smb_fname,
1380 &clientFname)))
1382 goto err;
1384 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1385 clientFname->base_name));
1386 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1388 goto err;
1390 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1392 goto err;
1395 /* Unlike functions with const smb_filename, we have to
1396 * modify smb_fname itself to pass our info back up.
1398 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1399 "from clientFname '%s'\n",
1400 smb_fname->base_name,
1401 clientFname->base_name));
1402 smb_fname->st = clientFname->st;
1403 err:
1404 TALLOC_FREE(clientFname);
1405 out:
1406 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1407 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1408 return status;
1412 * Success: return 0
1413 * Failure: set errno, return -1
1415 static int mh_lstat(vfs_handle_struct *handle,
1416 struct smb_filename *smb_fname)
1418 int status = 0;
1419 struct smb_filename *clientFname;
1420 TALLOC_CTX *ctx;
1422 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1423 smb_fname->base_name));
1425 if (!is_in_media_files(smb_fname->base_name))
1427 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1428 goto out;
1431 clientFname = NULL;
1432 ctx = talloc_tos();
1434 if ((status = alloc_get_client_smb_fname(handle, ctx,
1435 smb_fname,
1436 &clientFname)))
1438 goto err;
1440 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1442 goto err;
1445 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1447 goto err;
1449 /* Unlike functions with const smb_filename, we have to
1450 * modify smb_fname itself to pass our info back up.
1452 smb_fname->st = clientFname->st;
1453 err:
1454 TALLOC_FREE(clientFname);
1455 out:
1456 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1457 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1458 return status;
1462 * Success: return 0
1463 * Failure: set errno, return -1
1465 static int mh_fstat(vfs_handle_struct *handle,
1466 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1468 int status = 0;
1470 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1471 "'%s'\n", fsp_str_dbg(fsp)));
1473 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1475 goto out;
1478 if (fsp->fsp_name == NULL
1479 || !is_in_media_files(fsp->fsp_name->base_name))
1481 goto out;
1484 if ((status = mh_stat(handle, fsp->fsp_name)))
1486 goto out;
1489 *sbuf = fsp->fsp_name->st;
1490 out:
1491 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1492 "%s",
1493 fsp->fsp_name != NULL ?
1494 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1495 "0"));
1496 return status;
1500 * Success: return 0
1501 * Failure: set errno, return -1
1503 static int mh_unlink(vfs_handle_struct *handle,
1504 const struct smb_filename *smb_fname)
1506 int status;
1507 struct smb_filename *clientFname;
1508 TALLOC_CTX *ctx;
1510 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1511 if (!is_in_media_files(smb_fname->base_name))
1513 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1514 goto out;
1517 clientFname = NULL;
1518 ctx = talloc_tos();
1520 if ((status = alloc_get_client_smb_fname(handle, ctx,
1521 smb_fname,
1522 &clientFname)))
1524 goto err;
1527 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1528 err:
1529 TALLOC_FREE(clientFname);
1530 out:
1531 return status;
1535 * Success: return 0
1536 * Failure: set errno, return -1
1538 static int mh_chmod(vfs_handle_struct *handle,
1539 const char *path,
1540 mode_t mode)
1542 int status;
1543 char *clientPath;
1544 TALLOC_CTX *ctx;
1546 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1547 if (!is_in_media_files(path))
1549 status = SMB_VFS_NEXT_CHMOD(handle, path, mode);
1550 goto out;
1553 clientPath = NULL;
1554 ctx = talloc_tos();
1556 if ((status = alloc_get_client_path(handle, ctx,
1557 path,
1558 &clientPath)))
1560 goto err;
1563 status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
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_chown(vfs_handle_struct *handle,
1575 const char *path,
1576 uid_t uid,
1577 gid_t gid)
1579 int status;
1580 char *clientPath;
1581 TALLOC_CTX *ctx;
1583 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1584 if (!is_in_media_files(path))
1586 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1587 goto out;
1590 clientPath = NULL;
1591 ctx = talloc_tos();
1593 if ((status = alloc_get_client_path(handle, ctx,
1594 path,
1595 &clientPath)))
1597 goto err;
1600 status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1601 err:
1602 TALLOC_FREE(clientPath);
1603 out:
1604 return status;
1608 * Success: return 0
1609 * Failure: set errno, return -1
1611 static int mh_lchown(vfs_handle_struct *handle,
1612 const char *path,
1613 uid_t uid,
1614 gid_t gid)
1616 int status;
1617 char *clientPath;
1618 TALLOC_CTX *ctx;
1620 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1621 if (!is_in_media_files(path))
1623 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1624 goto out;
1627 clientPath = NULL;
1628 ctx = talloc_tos();
1630 if ((status = alloc_get_client_path(handle, ctx,
1631 path,
1632 &clientPath)))
1634 goto err;
1637 status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1638 err:
1639 TALLOC_FREE(clientPath);
1640 out:
1641 return status;
1645 * Success: return 0
1646 * Failure: set errno, return -1
1648 static int mh_chdir(vfs_handle_struct *handle,
1649 const char *path)
1651 int status;
1652 char *clientPath;
1653 TALLOC_CTX *ctx;
1655 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1656 if (!is_in_media_files(path))
1658 status = SMB_VFS_NEXT_CHDIR(handle, path);
1659 goto out;
1662 clientPath = NULL;
1663 ctx = talloc_tos();
1665 if ((status = alloc_get_client_path(handle, ctx,
1666 path,
1667 &clientPath)))
1669 goto err;
1672 status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1673 err:
1674 TALLOC_FREE(clientPath);
1675 out:
1676 return status;
1680 * Success: return 0
1681 * Failure: set errno, return -1
1683 static int mh_ntimes(vfs_handle_struct *handle,
1684 const struct smb_filename *smb_fname,
1685 struct smb_file_time *ft)
1687 int status;
1688 struct smb_filename *clientFname;
1689 TALLOC_CTX *ctx;
1692 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1693 if (!is_in_media_files(smb_fname->base_name))
1695 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1696 goto out;
1699 clientFname = NULL;
1700 ctx = talloc_tos();
1702 if ((status = alloc_get_client_smb_fname(handle, ctx,
1703 smb_fname,
1704 &clientFname)))
1706 goto err;
1709 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1710 err:
1711 TALLOC_FREE(clientFname);
1712 out:
1713 return status;
1717 * Success: return 0
1718 * Failure: set errno, return -1
1720 static int mh_symlink(vfs_handle_struct *handle,
1721 const char *oldpath,
1722 const char *newpath)
1724 int status;
1725 char *oldClientPath;
1726 char *newClientPath;
1727 TALLOC_CTX *ctx;
1729 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1730 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1732 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1733 goto out;
1736 oldClientPath = NULL;
1737 newClientPath = NULL;
1738 ctx = talloc_tos();
1740 if ((status = alloc_get_client_path(handle, ctx,
1741 oldpath,
1742 &oldClientPath)))
1744 goto err;
1747 if ((status = alloc_get_client_path(handle, ctx,
1748 newpath,
1749 &newClientPath)))
1751 goto err;
1754 status = SMB_VFS_NEXT_SYMLINK(handle,
1755 oldClientPath,
1756 newClientPath);
1758 err:
1759 TALLOC_FREE(newClientPath);
1760 TALLOC_FREE(oldClientPath);
1761 out:
1762 return status;
1766 * Success: return byte count
1767 * Failure: set errno, return -1
1769 static int mh_readlink(vfs_handle_struct *handle,
1770 const char *path,
1771 char *buf,
1772 size_t bufsiz)
1774 int status;
1775 char *clientPath;
1776 TALLOC_CTX *ctx;
1778 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1779 if (!is_in_media_files(path))
1781 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1782 goto out;
1785 clientPath = NULL;
1786 ctx = talloc_tos();
1788 if ((status = alloc_get_client_path(handle, ctx,
1789 path,
1790 &clientPath)))
1792 goto err;
1795 status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1796 err:
1797 TALLOC_FREE(clientPath);
1798 out:
1799 return status;
1803 * Success: return 0
1804 * Failure: set errno, return -1
1806 static int mh_link(vfs_handle_struct *handle,
1807 const char *oldpath,
1808 const char *newpath)
1810 int status;
1811 char *oldClientPath;
1812 char *newClientPath;
1813 TALLOC_CTX *ctx;
1815 DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1816 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1818 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1819 goto out;
1822 oldClientPath = NULL;
1823 newClientPath = NULL;
1824 ctx = talloc_tos();
1826 if ((status = alloc_get_client_path(handle, ctx,
1827 oldpath,
1828 &oldClientPath)))
1830 goto err;
1833 if ((status = alloc_get_client_path(handle, ctx,
1834 newpath,
1835 &newClientPath)))
1837 goto err;
1840 status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1841 err:
1842 TALLOC_FREE(newClientPath);
1843 TALLOC_FREE(oldClientPath);
1844 out:
1845 return status;
1849 * Success: return 0
1850 * Failure: set errno, return -1
1852 static int mh_mknod(vfs_handle_struct *handle,
1853 const char *pathname,
1854 mode_t mode,
1855 SMB_DEV_T dev)
1857 int status;
1858 char *clientPath;
1859 TALLOC_CTX *ctx;
1861 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1862 if (!is_in_media_files(pathname))
1864 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1865 goto out;
1868 clientPath = NULL;
1869 ctx = talloc_tos();
1871 if ((status = alloc_get_client_path(handle, ctx,
1872 pathname,
1873 &clientPath)))
1875 goto err;
1878 status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1879 err:
1880 TALLOC_FREE(clientPath);
1881 out:
1882 return status;
1886 * Success: return path pointer
1887 * Failure: set errno, return NULL pointer
1889 static char *mh_realpath(vfs_handle_struct *handle,
1890 const char *path)
1892 char *buf;
1893 char *clientPath;
1894 TALLOC_CTX *ctx;
1896 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1897 if (!is_in_media_files(path))
1899 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1900 goto out;
1903 clientPath = NULL;
1904 ctx = talloc_tos();
1906 if (alloc_get_client_path(handle, ctx,
1907 path,
1908 &clientPath))
1910 buf = NULL;
1911 goto err;
1914 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1915 err:
1916 TALLOC_FREE(clientPath);
1917 out:
1918 return buf;
1922 * Success: return 0
1923 * Failure: set errno, return -1
1925 static int mh_chflags(vfs_handle_struct *handle,
1926 const char *path,
1927 unsigned int flags)
1929 int status;
1930 char *clientPath;
1931 TALLOC_CTX *ctx;
1933 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1934 if (!is_in_media_files(path))
1936 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1937 goto out;
1940 clientPath = NULL;
1941 ctx = talloc_tos();
1943 if ((status = alloc_get_client_path(handle, ctx,
1944 path,
1945 &clientPath)))
1947 goto err;
1950 status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1951 err:
1952 TALLOC_FREE(clientPath);
1953 out:
1954 return status;
1958 * Success: return NT_STATUS_OK
1959 * Failure: return NT status error
1961 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1962 struct files_struct *fsp,
1963 const char *fname,
1964 TALLOC_CTX *ctx,
1965 unsigned int *num_streams,
1966 struct stream_struct **streams)
1968 NTSTATUS status;
1969 char *clientPath;
1970 TALLOC_CTX *mem_ctx;
1972 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1973 if (!is_in_media_files(fname))
1975 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1976 ctx, num_streams, streams);
1977 goto out;
1980 clientPath = NULL;
1981 mem_ctx = talloc_tos();
1983 if (alloc_get_client_path(handle, mem_ctx,
1984 fname,
1985 &clientPath))
1987 status = map_nt_error_from_unix(errno);
1988 goto err;
1991 /* This only works on files, so we don't have to worry about
1992 * our fake directory stat'ing here.
1994 // But what does this function do, exactly? Does it need
1995 // extra modifications for the Avid stuff?
1996 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
1997 ctx, num_streams, streams);
1998 err:
1999 TALLOC_FREE(clientPath);
2000 out:
2001 return status;
2004 /* Ignoring get_real_filename function because the default
2005 * doesn't do anything.
2009 * Success: return NT_STATUS_OK
2010 * Failure: return NT status error
2011 * In this case, "name" is a path.
2013 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2014 const char *name,
2015 uint32 security_info,
2016 TALLOC_CTX *mem_ctx,
2017 struct security_descriptor **ppdesc)
2019 NTSTATUS status;
2020 char *clientPath;
2021 TALLOC_CTX *ctx;
2023 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2024 if (!is_in_media_files(name))
2026 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name,
2027 security_info,
2028 mem_ctx, ppdesc);
2029 goto out;
2032 clientPath = NULL;
2033 ctx = talloc_tos();
2035 if (alloc_get_client_path(handle, ctx,
2036 name,
2037 &clientPath))
2039 status = map_nt_error_from_unix(errno);
2040 goto err;
2043 status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
2044 security_info,
2045 mem_ctx, ppdesc);
2046 err:
2047 TALLOC_FREE(clientPath);
2048 out:
2049 return status;
2053 * Success: return 0
2054 * Failure: set errno, return -1
2056 static int mh_chmod_acl(vfs_handle_struct *handle,
2057 const char *path,
2058 mode_t mode)
2060 int status;
2061 char *clientPath;
2062 TALLOC_CTX *ctx;
2064 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2065 if (!is_in_media_files(path))
2067 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2068 goto out;
2071 clientPath = NULL;
2072 ctx = talloc_tos();
2074 if ((status = alloc_get_client_path(handle, ctx,
2075 path,
2076 &clientPath)))
2078 goto err;
2081 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2082 err:
2083 TALLOC_FREE(clientPath);
2084 out:
2085 return status;
2089 * Success: return acl pointer
2090 * Failure: set errno, return NULL
2092 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2093 const char *path_p,
2094 SMB_ACL_TYPE_T type,
2095 TALLOC_CTX *mem_ctx)
2097 SMB_ACL_T ret;
2098 char *clientPath;
2099 TALLOC_CTX *ctx;
2101 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2102 if (!is_in_media_files(path_p))
2104 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2105 goto out;
2108 clientPath = NULL;
2109 ctx = talloc_tos();
2111 if (alloc_get_client_path(handle, ctx,
2112 path_p,
2113 &clientPath))
2115 ret = NULL;
2116 goto err;
2119 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2120 err:
2121 TALLOC_FREE(clientPath);
2122 out:
2123 return ret;
2127 * Success: return 0
2128 * Failure: set errno, return -1
2129 * In this case, "name" is a path.
2131 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2132 const char *name,
2133 SMB_ACL_TYPE_T acltype,
2134 SMB_ACL_T theacl)
2136 int status;
2137 char *clientPath;
2138 TALLOC_CTX *ctx;
2140 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2141 if (!is_in_media_files(name))
2143 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2144 acltype, theacl);
2145 goto out;
2148 clientPath = NULL;
2149 ctx = talloc_tos();
2151 if ((status = alloc_get_client_path(handle, ctx,
2152 name,
2153 &clientPath)))
2155 goto err;
2158 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2159 acltype, theacl);
2160 err:
2161 TALLOC_FREE(clientPath);
2162 out:
2163 return status;
2167 * Success: return 0
2168 * Failure: set errno, return -1
2170 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2171 const char *path)
2173 int status;
2174 char *clientPath;
2175 TALLOC_CTX *ctx;
2177 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2178 if (!is_in_media_files(path))
2180 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2181 path);
2182 goto out;
2185 clientPath = NULL;
2186 ctx = talloc_tos();
2188 if ((status = alloc_get_client_path(handle, ctx,
2189 path,
2190 &clientPath)))
2192 goto err;
2195 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2196 err:
2197 TALLOC_FREE(clientPath);
2198 out:
2199 return status;
2203 * Success: return positive number
2204 * Failure: set errno, return -1
2205 * In this case, "name" is an attr name.
2207 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2208 const char *path,
2209 const char *name,
2210 void *value,
2211 size_t size)
2213 ssize_t ret;
2214 char *clientPath;
2215 TALLOC_CTX *ctx;
2217 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2218 if (!is_in_media_files(path))
2220 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2221 size);
2222 goto out;
2225 clientPath = NULL;
2226 ctx = talloc_tos();
2228 if (alloc_get_client_path(handle, ctx,
2229 path,
2230 &clientPath))
2232 ret = -1;
2233 goto err;
2236 ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2237 err:
2238 TALLOC_FREE(clientPath);
2239 out:
2240 return ret;
2244 * Success: return positive number
2245 * Failure: set errno, return -1
2247 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2248 const char *path,
2249 char *list,
2250 size_t size)
2252 ssize_t ret;
2253 char *clientPath;
2254 TALLOC_CTX *ctx;
2256 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2257 if (!is_in_media_files(path))
2259 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2260 goto out;
2263 clientPath = NULL;
2264 ctx = talloc_tos();
2266 if (alloc_get_client_path(handle, ctx,
2267 path,
2268 &clientPath))
2270 ret = -1;
2271 goto err;
2274 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2275 err:
2276 TALLOC_FREE(clientPath);
2277 out:
2278 return ret;
2282 * Success: return 0
2283 * Failure: set errno, return -1
2284 * In this case, "name" is an attr name.
2286 static int mh_removexattr(struct vfs_handle_struct *handle,
2287 const char *path,
2288 const char *name)
2290 int status;
2291 char *clientPath;
2292 TALLOC_CTX *ctx;
2294 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2295 if (!is_in_media_files(path))
2297 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2298 goto out;
2301 clientPath = NULL;
2302 ctx = talloc_tos();
2304 if ((status = alloc_get_client_path(handle, ctx,
2305 path,
2306 &clientPath)))
2308 goto err;
2311 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2312 err:
2313 TALLOC_FREE(clientPath);
2314 out:
2315 return status;
2319 * Success: return 0
2320 * Failure: set errno, return -1
2321 * In this case, "name" is an attr name.
2323 static int mh_setxattr(struct vfs_handle_struct *handle,
2324 const char *path,
2325 const char *name,
2326 const void *value,
2327 size_t size,
2328 int flags)
2330 int status;
2331 char *clientPath;
2332 TALLOC_CTX *ctx;
2334 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2335 if (!is_in_media_files(path))
2337 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2338 size, flags);
2339 goto out;
2342 clientPath = NULL;
2343 ctx = talloc_tos();
2345 if ((status = alloc_get_client_path(handle, ctx,
2346 path,
2347 &clientPath)))
2349 goto err;
2352 status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2353 size, flags);
2354 err:
2355 TALLOC_FREE(clientPath);
2356 out:
2357 return status;
2361 * Success: return true
2362 * Failure: set errno, return false
2364 static bool mh_is_offline(struct vfs_handle_struct *handle,
2365 const struct smb_filename *fname,
2366 SMB_STRUCT_STAT *sbuf)
2368 // check if sbuf is modified further down the chain.
2369 bool ret;
2370 struct smb_filename *clientFname;
2371 TALLOC_CTX *ctx;
2373 DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2374 if (!is_in_media_files(fname->base_name))
2376 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2377 goto out;
2380 clientFname = NULL;
2381 ctx = talloc_tos();
2383 if(alloc_get_client_smb_fname(handle, ctx,
2384 fname,
2385 &clientFname))
2387 ret = -1;
2388 goto err;
2391 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2392 err:
2393 TALLOC_FREE(clientFname);
2394 out:
2395 return ret;
2399 * Success: return 0 (?)
2400 * Failure: set errno, return -1
2402 static int mh_set_offline(struct vfs_handle_struct *handle,
2403 const struct smb_filename *fname)
2405 int status;
2406 struct smb_filename *clientFname;
2407 TALLOC_CTX *ctx;
2409 DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2410 if (!is_in_media_files(fname->base_name))
2412 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2413 goto out;
2416 clientFname = NULL;
2417 ctx = talloc_tos();
2419 if ((status = alloc_get_client_smb_fname(handle, ctx,
2420 fname,
2421 &clientFname)))
2423 goto err;
2426 status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2427 err:
2428 TALLOC_FREE(clientFname);
2429 out:
2430 return status;
2433 /* VFS operations structure */
2435 static struct vfs_fn_pointers vfs_mh_fns = {
2436 /* Disk operations */
2438 .statvfs_fn = mh_statvfs,
2440 /* Directory operations */
2442 .opendir_fn = mh_opendir,
2443 .fdopendir_fn = mh_fdopendir,
2444 .readdir_fn = mh_readdir,
2445 .seekdir_fn = mh_seekdir,
2446 .telldir_fn = mh_telldir,
2447 .rewind_dir_fn = mh_rewinddir,
2448 .mkdir_fn = mh_mkdir,
2449 .rmdir_fn = mh_rmdir,
2450 .closedir_fn = mh_closedir,
2451 .init_search_op_fn = mh_init_search_op,
2453 /* File operations */
2455 .open_fn = mh_open,
2456 .create_file_fn = mh_create_file,
2457 .rename_fn = mh_rename,
2458 .stat_fn = mh_stat,
2459 .lstat_fn = mh_lstat,
2460 .fstat_fn = mh_fstat,
2461 .unlink_fn = mh_unlink,
2462 .chmod_fn = mh_chmod,
2463 .chown_fn = mh_chown,
2464 .lchown_fn = mh_lchown,
2465 .chdir_fn = mh_chdir,
2466 .ntimes_fn = mh_ntimes,
2467 .symlink_fn = mh_symlink,
2468 .readlink_fn = mh_readlink,
2469 .link_fn = mh_link,
2470 .mknod_fn = mh_mknod,
2471 .realpath_fn = mh_realpath,
2472 .chflags_fn = mh_chflags,
2473 .streaminfo_fn = mh_streaminfo,
2475 /* NT ACL operations. */
2477 .get_nt_acl_fn = mh_get_nt_acl,
2479 /* POSIX ACL operations. */
2481 .chmod_acl_fn = mh_chmod_acl,
2483 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2484 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2485 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2487 /* EA operations. */
2488 .getxattr_fn = mh_getxattr,
2489 .listxattr_fn = mh_listxattr,
2490 .removexattr_fn = mh_removexattr,
2491 .setxattr_fn = mh_setxattr,
2493 /* aio operations */
2495 /* offline operations */
2496 .is_offline_fn = mh_is_offline,
2497 .set_offline_fn = mh_set_offline
2500 NTSTATUS vfs_media_harmony_init(void);
2501 NTSTATUS vfs_media_harmony_init(void)
2503 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2504 "media_harmony", &vfs_mh_fns);
2505 if (!NT_STATUS_IS_OK(ret))
2507 goto out;
2510 vfs_mh_debug_level = debug_add_class("media_harmony");
2512 if (vfs_mh_debug_level == -1) {
2513 vfs_mh_debug_level = DBGC_VFS;
2514 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2515 "debugging class.\n"));
2516 } else {
2517 DEBUG(3, ("media_harmony_init: Debug class number of "
2518 "'media_harmony': %d\n",
2519 vfs_mh_debug_level));
2522 out:
2523 return ret;