libcli/smb: add support for SMB >= 3.1.1 io priorities
[Samba.git] / source3 / modules / vfs_media_harmony.c
blobd960fae9fc54fec7810d96b87f4550e89f9798e2
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* MDB_FILENAME = "msmMMOB.mdb";
97 static const size_t MDB_FILENAME_LEN = 11;
98 static const char* PMR_FILENAME = "msmFMID.pmr";
99 static const size_t PMR_FILENAME_LEN = 11;
100 static const char* CREATING_DIRNAME = "Creating";
101 static const size_t CREATING_DIRNAME_LEN = 8;
102 static const char* AVID_MEDIAFILES_DIRNAME = "Avid MediaFiles";
103 static const size_t AVID_MEDIAFILES_DIRNAME_LEN = 15;
104 static const char* OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
105 static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
106 static const char* APPLE_DOUBLE_PREFIX = "._";
107 static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
108 static const char* AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
109 static const size_t AVID_MXF_DIRNAME_LEN = 19;
111 static int vfs_mh_debug_level = DBGC_VFS;
113 /* supplements the directory list stream */
114 typedef struct mh_dirinfo_struct
116 DIR* dirstream;
117 char *dirpath;
118 char *clientPath;
119 bool isInMediaFiles;
120 char *clientMDBFilename;
121 char *clientPMRFilename;
122 char *clientCreatingDirname;
123 } mh_dirinfo_struct;
126 /* Add "_<ip address>_<user name>" suffix to path or filename.
128 * Success: return 0
129 * Failure: set errno, path NULL, return -1
131 static int alloc_append_client_suffix(vfs_handle_struct *handle,
132 char **path)
134 int status = 0;
135 char *raddr = NULL;
137 DEBUG(MH_INFO_DEBUG, ("Entering with *path '%s'\n", *path));
139 raddr = tsocket_address_inet_addr_string(
140 handle->conn->sconn->remote_address, talloc_tos());
141 if (raddr == NULL)
143 errno = ENOMEM;
144 status = -1;
145 goto err;
148 /* talloc_asprintf_append uses talloc_realloc, which
149 * frees original 'path' memory so we don't have to.
151 *path = talloc_asprintf_append(*path, "_%s_%s",
152 raddr,
153 handle->conn->session_info->unix_info->sanitized_username);
154 if (*path == NULL)
156 DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
157 "out of memory\n"));
158 errno = ENOMEM;
159 status = -1;
160 goto err;
162 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
163 err:
164 TALLOC_FREE(raddr);
165 return status;
169 /* Returns True if the file or directory begins with the appledouble
170 * prefix.
172 static bool is_apple_double(const char* fname)
174 bool ret = False;
176 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
178 if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
179 == 0)
181 ret = True;
183 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
184 ret == True ? "True" : "False"));
185 return ret;
188 static bool starts_with_media_dir(const char* media_dirname,
189 size_t media_dirname_len, const char* path)
191 bool ret = False;
192 const char *path_start;
194 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
195 "path '%s'\n", media_dirname, path));
197 /* Sometimes Samba gives us "./OMFI MediaFiles". */
198 if (strncmp(path, "./", 2) == 0)
200 path_start = &path[2];
202 else {
203 path_start = path;
206 if (strncmp(media_dirname, path_start, media_dirname_len) == 0
209 path_start[media_dirname_len] == '\0'
211 path_start[media_dirname_len] == '/'
215 ret = True;
218 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
219 ret == True ? "True" : "False"));
220 return ret;
224 * Returns True if the file or directory referenced by the path is below
225 * the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME directory
226 * The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME are assumed to
227 * be in the root directory, which is generally a safe assumption
228 * in the fixed-path world of Avid.
230 static bool is_in_media_files(const char* path)
232 bool ret = False;
234 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
236 if (
237 starts_with_media_dir(AVID_MEDIAFILES_DIRNAME,
238 AVID_MEDIAFILES_DIRNAME_LEN, path)
240 starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
241 OMFI_MEDIAFILES_DIRNAME_LEN, path)
244 ret = True;
246 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
247 ret == True ? "True" : "False"));
248 return ret;
252 * Returns depth of path under media directory. Deals with the
253 * occasional ..../. and ..../.. paths that get passed to stat.
255 * Assumes is_in_media_files has already been called and has returned
256 * true for the path; if it hasn't, this function will likely crash
257 * and burn.
259 * Not foolproof; something like "Avid MediaFiles/MXF/../foo/1"
260 * would fool it. Haven't seen paths like that getting to the
261 * stat function yet, so ignoring that possibility for now.
263 static int depth_from_media_dir(const char* media_dirname,
264 size_t media_dirname_len, const char* path)
266 int transition_count = 0;
267 const char *path_start;
268 const char *pathPtr;
270 DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
271 "path '%s'\n", media_dirname, path));
273 /* Sometimes Samba gives us "./OMFI MediaFiles". */
274 if (strncmp(path, "./", 2) == 0)
276 path_start = &path[2];
278 else {
279 path_start = path;
282 if (path_start[media_dirname_len] == '\0')
284 goto out;
287 pathPtr = &path_start[media_dirname_len + 1];
289 while(1)
291 if (*pathPtr == '\0' || *pathPtr == '/')
293 if (
294 *(pathPtr - 1) == '.'
296 *(pathPtr - 2) == '.'
298 *(pathPtr - 3) == '/'
301 transition_count--;
303 else if (
306 *(pathPtr - 1) == '/'
309 *(pathPtr - 1) == '.'
311 *(pathPtr - 2) == '/'
316 transition_count++;
319 if (*pathPtr == '\0')
321 break;
323 pathPtr++;
326 DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
327 transition_count));
328 out:
329 return transition_count;
332 /* Identifies MDB and PMR files at end of path. */
333 static bool is_avid_database(
334 char *path,
335 size_t path_len,
336 const char *avid_db_filename,
337 const size_t avid_db_filename_len)
339 bool ret = False;
341 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s', "
342 "avid_db_filename '%s', "
343 "path_len '%i', "
344 "avid_db_filename_len '%i'\n",
345 path, avid_db_filename,
346 (int)path_len, (int)avid_db_filename_len));
348 if (
349 path_len > avid_db_filename_len
351 strcmp(&path[path_len - avid_db_filename_len],
352 avid_db_filename) == 0
355 path[path_len - avid_db_filename_len - 1] == '/'
357 (path_len > avid_db_filename_len
358 + APPLE_DOUBLE_PREFIX_LEN
360 path[path_len - avid_db_filename_len
361 - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
363 is_apple_double(&path[path_len
364 - avid_db_filename_len
365 - APPLE_DOUBLE_PREFIX_LEN]))
369 ret = True;
371 DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
372 ret == True ? "True" : "False"));
373 return ret;
377 /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
378 * CREATING_SUBDIRNAME.
380 * Caller must free newPath.
382 * Success: return 0
383 * Failure: set errno, newPath NULL, return -1
385 static int alloc_get_client_path(vfs_handle_struct *handle,
386 TALLOC_CTX *ctx,
387 const char *path,
388 char **newPath)
390 /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
391 * directory in path - potentially in middle of path
392 * - with suffixed name.
394 int status = 0;
395 char* pathPtr;
396 size_t intermPathLen;
398 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
400 *newPath = talloc_strdup(ctx, path);
401 if (*newPath == NULL)
403 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
404 errno = ENOMEM;
405 status = -1;
406 goto out;
408 DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
409 if (
410 (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
413 *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
415 *(pathPtr + CREATING_DIRNAME_LEN) == '/'
419 (pathPtr - path > 0
421 *(pathPtr - 1) == '/')
423 (pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
425 *(pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1) == '/'
427 is_apple_double(pathPtr - APPLE_DOUBLE_PREFIX_LEN))
431 /* Insert client suffix into path. */
432 (*newPath)[pathPtr - path + CREATING_DIRNAME_LEN] = '\0';
433 DEBUG(MH_INFO_DEBUG, ("newPath #2 %s\n", *newPath));
435 if ((status = alloc_append_client_suffix(handle, newPath)))
437 goto out;
440 DEBUG(MH_INFO_DEBUG, ("newPath #3 %s\n", *newPath));
441 *newPath = talloc_strdup_append(*newPath,
442 pathPtr + CREATING_DIRNAME_LEN);
443 if (*newPath == NULL)
445 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path "
446 "ENOMEM #2\n"));
447 errno = ENOMEM;
448 status = -1;
449 goto out;
451 DEBUG(MH_INFO_DEBUG, ("newPath #4 %s\n", *newPath));
454 /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
455 * or /._PMR_FILENAME at newPath end with suffixed name.
457 intermPathLen = strlen(*newPath);
458 if (
459 is_avid_database(*newPath, intermPathLen,
460 MDB_FILENAME, MDB_FILENAME_LEN)
462 is_avid_database(*newPath, intermPathLen,
463 PMR_FILENAME, PMR_FILENAME_LEN)
466 DEBUG(MH_INFO_DEBUG, ("newPath #5 %s\n", *newPath));
467 if ((status = alloc_append_client_suffix(handle, newPath)))
469 goto out;
471 DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
473 out:
474 /* newPath must be freed in caller. */
475 DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
476 return status;
480 * Success: return 0
481 * Failure: set errno, return -1
483 static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
484 TALLOC_CTX *ctx,
485 const struct smb_filename *smb_fname,
486 struct smb_filename **clientFname)
488 int status = 0;
490 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
491 smb_fname->base_name));
493 *clientFname = cp_smb_filename(ctx, smb_fname);
494 if ((*clientFname) == NULL) {
495 DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
496 "NTERR\n"));
497 errno = ENOMEM;
498 status = -1;
499 goto err;
501 if ((status = alloc_get_client_path(handle, ctx,
502 smb_fname->base_name,
503 &(*clientFname)->base_name)))
505 goto err;
507 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
508 "'%s'\n", (*clientFname)->base_name));
509 err:
510 return status;
515 * Success: return 0
516 * Failure: set errno, return -1
518 static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
519 TALLOC_CTX *ctx,
520 char **path,
521 const char *avid_db_filename)
523 int status = 0;
525 DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
526 avid_db_filename));
528 if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
530 DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
531 "ENOMEM\n"));
532 errno = ENOMEM;
533 status = -1;
534 goto err;
536 if ((status = alloc_append_client_suffix(handle, path)))
538 goto err;
540 DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
541 err:
542 return status;
546 * Replace mtime on clientFname with mtime from client-suffixed
547 * equivalent, if it exists.
549 * Success: return 0
550 * Failure: set errno, return -1
552 static int set_fake_mtime(vfs_handle_struct *handle,
553 TALLOC_CTX *ctx,
554 struct smb_filename **clientFname,
555 int (*statFn)(const char *, SMB_STRUCT_STAT *, bool))
557 int status = 0;
558 char *statPath;
559 SMB_STRUCT_STAT fakeStat;
560 int copy_len;
562 DEBUG(MH_INFO_DEBUG, ("Entering with (*clientFname)->base_name "
563 "'%s', (*clientFname)->st.st_ex_mtime %s",
564 (*clientFname)->base_name,
565 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
567 if (
568 depth_from_media_dir(AVID_MXF_DIRNAME,
569 AVID_MXF_DIRNAME_LEN,
570 (*clientFname)->base_name)
571 != 1
573 depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
574 OMFI_MEDIAFILES_DIRNAME_LEN,
575 (*clientFname)->base_name)
576 != 0
579 goto out;
582 copy_len = strlen((*clientFname)->base_name);
584 /* Hack to deal with occasional "Avid MediaFiles/MXF/1/." paths.
585 * We know we're under a media dir, so paths are at least 2 chars
586 * long.
588 if ((*clientFname)->base_name[copy_len - 1] == '.' &&
589 (*clientFname)->base_name[copy_len - 2] == '/')
591 copy_len -= 2;
594 if (((statPath = talloc_strndup(ctx,
595 (*clientFname)->base_name, copy_len)) == NULL))
597 errno = ENOMEM;
598 status = -1;
599 goto err;
601 if ((status = alloc_append_client_suffix(handle, &statPath)))
603 goto err;
606 DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
607 if (statFn(statPath, &fakeStat,
608 lp_fake_directory_create_times(SNUM(handle->conn))))
610 /* This can fail for legitimate reasons - i.e. the
611 * fakeStat directory doesn't exist, which is okay
612 * - so we don't set status. But if it does fail,
613 * we need to skip over the mtime assignment.
615 goto err;
618 DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
619 (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
620 err:
621 TALLOC_FREE(statPath);
622 out:
623 DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
624 "'%s', (*clientFname)->st.st_ex_mtime %s",
625 (*clientFname)->base_name,
626 ctime(&((*clientFname)->st.st_ex_mtime.tv_sec))));
627 return status;
631 * Success: return 0
632 * Failure: set errno, return -1
634 static int mh_statvfs(struct vfs_handle_struct *handle,
635 const char *path,
636 struct vfs_statvfs_struct *statbuf)
638 int status;
639 char *clientPath;
640 TALLOC_CTX *ctx;
642 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
644 if (!is_in_media_files(path))
646 status = SMB_VFS_NEXT_STATVFS(handle, path, statbuf);
647 goto out;
650 clientPath = NULL;
651 ctx = talloc_tos();
653 if ((status = alloc_get_client_path(handle, ctx,
654 path,
655 &clientPath)))
657 goto err;
660 status = SMB_VFS_NEXT_STATVFS(handle, clientPath, statbuf);
661 err:
662 TALLOC_FREE(clientPath);
663 out:
664 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
665 return status;
668 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
669 const char *fname,
670 struct mh_dirinfo_struct **dirInfo)
672 int status = 0;
673 char *clientPath;
674 TALLOC_CTX *ctx;
676 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
678 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
679 if (*dirInfo == NULL)
681 goto err;
684 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
685 if ((*dirInfo)->dirpath == NULL)
687 goto err;
690 if (!is_in_media_files(fname))
692 (*dirInfo)->clientPath = NULL;
693 (*dirInfo)->clientMDBFilename = NULL;
694 (*dirInfo)->clientPMRFilename = NULL;
695 (*dirInfo)->clientCreatingDirname = NULL;
696 (*dirInfo)->isInMediaFiles = False;
697 goto out;
700 (*dirInfo)->isInMediaFiles = True;
702 if (alloc_set_client_dirinfo_path(handle,
703 *dirInfo,
704 &((*dirInfo)->clientMDBFilename),
705 MDB_FILENAME))
707 goto err;
710 if (alloc_set_client_dirinfo_path(handle,
711 *dirInfo,
712 &((*dirInfo)->clientPMRFilename),
713 PMR_FILENAME))
715 goto err;
718 if (alloc_set_client_dirinfo_path(handle,
719 *dirInfo,
720 &((*dirInfo)->clientCreatingDirname),
721 CREATING_DIRNAME))
723 goto err;
726 clientPath = NULL;
727 ctx = talloc_tos();
729 if (alloc_get_client_path(handle, ctx,
730 fname,
731 &clientPath))
733 goto err;
736 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
737 if ((*dirInfo)->clientPath == NULL)
739 goto err;
742 TALLOC_FREE(clientPath);
744 out:
745 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
746 "(*dirInfo)->clientPath '%s'\n",
747 (*dirInfo)->dirpath,
748 (*dirInfo)->clientPath));
749 return status;
751 err:
752 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
753 TALLOC_FREE(*dirInfo);
754 status = -1;
755 errno = ENOMEM;
756 return status;
759 /* Success: return a mh_dirinfo_struct cast as a DIR
760 * Failure: set errno, return NULL
762 static DIR *mh_opendir(vfs_handle_struct *handle,
763 const char *fname,
764 const char *mask,
765 uint32_t attr)
767 struct mh_dirinfo_struct *dirInfo;
769 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
771 if (alloc_set_client_dirinfo(handle, fname, &dirInfo))
773 goto err;
776 if (!dirInfo->isInMediaFiles)
778 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
779 fname, mask, attr);
780 } else {
781 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
782 dirInfo->clientPath, mask, attr);
785 if (dirInfo->dirstream == NULL) {
786 goto err;
789 /* Success is freed in closedir. */
790 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
791 "dirInfo->clientPath '%s'\n",
792 dirInfo->dirpath,
793 dirInfo->clientPath));
794 return (DIR*)dirInfo;
795 err:
796 /* Failure is freed here. */
797 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
798 TALLOC_FREE(dirInfo);
799 return NULL;
802 static DIR *mh_fdopendir(vfs_handle_struct *handle,
803 files_struct *fsp,
804 const char *mask,
805 uint32_t attr)
807 struct mh_dirinfo_struct *dirInfo = NULL;
808 DIR *dirstream;
810 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
811 fsp->fsp_name->base_name));
813 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
814 if (!dirstream)
816 goto err;
819 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
820 &dirInfo))
822 goto err;
825 dirInfo->dirstream = dirstream;
827 if (! dirInfo->isInMediaFiles) {
828 goto out;
831 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
833 goto err;
836 out:
837 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
838 "dirInfo->clientPath '%s', "
839 "fsp->fsp_name->st.st_ex_mtime %s",
840 dirInfo->dirpath,
841 dirInfo->clientPath,
842 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
843 /* Success is freed in closedir. */
844 return (DIR *) dirInfo;
845 err:
846 /* Failure is freed here. */
847 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
848 fsp->fsp_name->base_name));
849 TALLOC_FREE(dirInfo);
850 return NULL;
854 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
855 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
856 * filenames and CREATING_DIRNAME directory, replace this client's
857 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
858 * directory with non suffixed.
860 * Success: return dirent
861 * End of data: return NULL
862 * Failure: set errno, return NULL
864 static struct dirent *mh_readdir(vfs_handle_struct *handle,
865 DIR *dirp,
866 SMB_STRUCT_STAT *sbuf)
868 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
869 struct dirent *d = NULL;
870 int skip;
872 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
874 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
875 "dirInfo->clientPath '%s', "
876 "dirInfo->isInMediaFiles '%s', "
877 "dirInfo->clientMDBFilename '%s', "
878 "dirInfo->clientPMRFilename '%s', "
879 "dirInfo->clientCreatingDirname '%s'\n",
880 dirInfo->dirpath,
881 dirInfo->clientPath,
882 dirInfo->isInMediaFiles ? "True" : "False",
883 dirInfo->clientMDBFilename,
884 dirInfo->clientPMRFilename,
885 dirInfo->clientCreatingDirname));
887 if (! dirInfo->isInMediaFiles)
889 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
890 goto out;
895 const char* dname;
896 bool isAppleDouble;
898 skip = False;
899 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
901 if (d == NULL)
903 break;
906 /* ignore apple double prefix for logic below */
907 if (is_apple_double(d->d_name))
909 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
910 isAppleDouble = True;
912 else
914 dname = d->d_name;
915 isAppleDouble = False;
918 /* skip Avid-special files with no client suffix */
919 if (
920 strcmp(dname, MDB_FILENAME) == 0
922 strcmp(dname, PMR_FILENAME) == 0
924 strcmp(dname, CREATING_DIRNAME) == 0
927 skip = True;
929 /* chop client suffix off this client's suffixed files */
930 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
932 if (isAppleDouble)
934 d->d_name[MDB_FILENAME_LEN
935 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
937 else
939 d->d_name[MDB_FILENAME_LEN] = '\0';
942 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
944 if (isAppleDouble)
946 d->d_name[PMR_FILENAME_LEN
947 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
949 else
951 d->d_name[PMR_FILENAME_LEN] = '\0';
954 else if (strcmp(dname, dirInfo->clientCreatingDirname)
955 == 0)
957 if (isAppleDouble)
959 d->d_name[CREATING_DIRNAME_LEN
960 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
962 else
964 d->d_name[CREATING_DIRNAME_LEN] = '\0';
968 * Anything that starts as an Avid-special file
969 * that's made it this far should be skipped. This
970 * is different from the original behaviour, which
971 * only skipped other client's suffixed files.
973 else if (
974 strncmp(MDB_FILENAME, dname,
975 MDB_FILENAME_LEN) == 0
977 strncmp(PMR_FILENAME, dname,
978 PMR_FILENAME_LEN) == 0
980 strncmp(CREATING_DIRNAME, dname,
981 CREATING_DIRNAME_LEN) == 0
984 skip = True;
987 while (skip);
989 out:
990 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
991 return d;
995 * Success: no success result defined.
996 * Failure: no failure result defined.
998 static void mh_seekdir(vfs_handle_struct *handle,
999 DIR *dirp,
1000 long offset)
1002 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1003 SMB_VFS_NEXT_SEEKDIR(handle,
1004 ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1008 * Success: return long
1009 * Failure: no failure result defined.
1011 static long mh_telldir(vfs_handle_struct *handle,
1012 DIR *dirp)
1014 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1015 return SMB_VFS_NEXT_TELLDIR(handle,
1016 ((mh_dirinfo_struct*)dirp)->dirstream);
1020 * Success: no success result defined.
1021 * Failure: no failure result defined.
1023 static void mh_rewinddir(vfs_handle_struct *handle,
1024 DIR *dirp)
1026 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1027 SMB_VFS_NEXT_REWINDDIR(handle,
1028 ((mh_dirinfo_struct*)dirp)->dirstream);
1032 * Success: return 0
1033 * Failure: set errno, return -1
1035 static int mh_mkdir(vfs_handle_struct *handle,
1036 const char *path,
1037 mode_t mode)
1039 int status;
1040 char *clientPath;
1041 TALLOC_CTX *ctx;
1044 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1046 if (!is_in_media_files(path))
1048 status = SMB_VFS_NEXT_MKDIR(handle, path, mode);
1049 goto out;
1052 clientPath = NULL;
1053 ctx = talloc_tos();
1055 if ((status = alloc_get_client_path(handle, ctx,
1056 path,
1057 &clientPath)))
1059 goto err;
1062 status = SMB_VFS_NEXT_MKDIR(handle, clientPath, mode);
1063 err:
1064 TALLOC_FREE(clientPath);
1065 out:
1066 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1067 return status;
1071 * Success: return 0
1072 * Failure: set errno, return -1
1074 static int mh_rmdir(vfs_handle_struct *handle,
1075 const char *path)
1077 int status;
1078 char *clientPath;
1079 TALLOC_CTX *ctx;
1082 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1084 if (!is_in_media_files(path))
1086 status = SMB_VFS_NEXT_RMDIR(handle, path);
1087 goto out;
1090 clientPath = NULL;
1091 ctx = talloc_tos();
1093 if ((status = alloc_get_client_path(handle, ctx,
1094 path,
1095 &clientPath)))
1097 goto err;
1100 status = SMB_VFS_NEXT_RMDIR(handle, clientPath);
1101 err:
1102 TALLOC_FREE(clientPath);
1103 out:
1104 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1105 return status;
1109 * Success: return 0
1110 * Failure: set errno, return -1
1112 static int mh_closedir(vfs_handle_struct *handle,
1113 DIR *dirp)
1115 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1117 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1118 // Will this talloc_free destroy realdirp?
1119 TALLOC_FREE(dirp);
1121 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1122 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1126 * Success: no success result defined.
1127 * Failure: no failure result defined.
1129 static void mh_init_search_op(vfs_handle_struct *handle,
1130 DIR *dirp)
1132 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1133 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1134 ((mh_dirinfo_struct*)dirp)->dirstream);
1138 * Success: return non-negative file descriptor
1139 * Failure: set errno, return -1
1141 static int mh_open(vfs_handle_struct *handle,
1142 struct smb_filename *smb_fname,
1143 files_struct *fsp,
1144 int flags,
1145 mode_t mode)
1147 int ret;
1148 struct smb_filename *clientFname;
1149 TALLOC_CTX *ctx;
1152 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1153 smb_fname->base_name));
1155 if (!is_in_media_files(smb_fname->base_name))
1157 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1158 mode);
1159 goto out;
1162 clientFname = NULL;
1163 ctx = talloc_tos();
1165 if(alloc_get_client_smb_fname(handle, ctx,
1166 smb_fname,
1167 &clientFname))
1169 ret = -1;
1170 goto err;
1173 // What about fsp->fsp_name?
1174 // We also have to get correct stat info into fsp and smb_fname
1175 // for DB files, don't we?
1177 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1178 "smb_fname->st.st_ex_mtime %s"
1179 " fsp->fsp_name->st.st_ex_mtime %s",
1180 smb_fname->base_name,
1181 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1182 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1184 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1185 err:
1186 TALLOC_FREE(clientFname);
1187 out:
1188 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1189 smb_fname->base_name));
1190 return ret;
1194 * Success: return non-negative file descriptor
1195 * Failure: set errno, return -1
1197 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1198 struct smb_request *req,
1199 uint16_t root_dir_fid,
1200 struct smb_filename *smb_fname,
1201 uint32_t access_mask,
1202 uint32_t share_access,
1203 uint32_t create_disposition,
1204 uint32_t create_options,
1205 uint32_t file_attributes,
1206 uint32_t oplock_request,
1207 struct smb2_lease *lease,
1208 uint64_t allocation_size,
1209 uint32_t private_flags,
1210 struct security_descriptor *sd,
1211 struct ea_list *ea_list,
1212 files_struct **result_fsp,
1213 int *pinfo,
1214 const struct smb2_create_blobs *in_context_blobs,
1215 struct smb2_create_blobs *out_context_blobs)
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 lease,
1238 allocation_size,
1239 private_flags,
1241 ea_list,
1242 result_fsp,
1243 pinfo,
1244 in_context_blobs,
1245 out_context_blobs);
1246 goto out;
1249 clientFname = NULL;
1250 ctx = talloc_tos();
1252 if (alloc_get_client_smb_fname(handle, ctx,
1253 smb_fname,
1254 &clientFname))
1256 status = map_nt_error_from_unix(errno);
1257 goto err;
1260 /* This only creates files, so we don't have to worry about
1261 * our fake directory stat'ing here.
1263 // But we still need to route stat calls for DB files
1264 // properly, right?
1265 status = SMB_VFS_NEXT_CREATE_FILE(
1266 handle,
1267 req,
1268 root_dir_fid,
1269 clientFname,
1270 access_mask,
1271 share_access,
1272 create_disposition,
1273 create_options,
1274 file_attributes,
1275 oplock_request,
1276 lease,
1277 allocation_size,
1278 private_flags,
1280 ea_list,
1281 result_fsp,
1282 pinfo,
1283 in_context_blobs,
1284 out_context_blobs);
1285 err:
1286 TALLOC_FREE(clientFname);
1287 out:
1288 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1289 "smb_fname->st.st_ex_mtime %s"
1290 " fsp->fsp_name->st.st_ex_mtime %s",
1291 smb_fname->base_name,
1292 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1293 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1294 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1295 "No fsp time\n"));
1296 return status;
1300 * Success: return 0
1301 * Failure: set errno, return -1
1303 static int mh_rename(vfs_handle_struct *handle,
1304 const struct smb_filename *smb_fname_src,
1305 const struct smb_filename *smb_fname_dst)
1307 int status;
1308 struct smb_filename *srcClientFname;
1309 struct smb_filename *dstClientFname;
1310 TALLOC_CTX *ctx;
1313 DEBUG(MH_INFO_DEBUG, ("Entering with "
1314 "smb_fname_src->base_name '%s', "
1315 "smb_fname_dst->base_name '%s'\n",
1316 smb_fname_src->base_name,
1317 smb_fname_dst->base_name));
1319 if (!is_in_media_files(smb_fname_src->base_name)
1321 !is_in_media_files(smb_fname_dst->base_name))
1323 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1324 smb_fname_dst);
1325 goto out;
1328 srcClientFname = NULL;
1329 dstClientFname = NULL;
1330 ctx = talloc_tos();
1332 if ((status = alloc_get_client_smb_fname(handle, ctx,
1333 smb_fname_src,
1334 &srcClientFname)))
1336 goto err;
1339 if ((status = alloc_get_client_smb_fname(handle, ctx,
1340 smb_fname_dst,
1341 &dstClientFname)))
1343 goto err;
1346 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1347 dstClientFname);
1348 err:
1349 TALLOC_FREE(dstClientFname);
1350 TALLOC_FREE(srcClientFname);
1351 out:
1352 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1353 " smb_fname_dst->base_name '%s'\n",
1354 smb_fname_src->base_name,
1355 smb_fname_dst->base_name));
1356 return status;
1360 * Success: return 0
1361 * Failure: set errno, return -1
1363 static int mh_stat(vfs_handle_struct *handle,
1364 struct smb_filename *smb_fname)
1366 int status = 0;
1367 struct smb_filename *clientFname;
1368 TALLOC_CTX *ctx;
1371 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1372 smb_fname->base_name));
1374 if (!is_in_media_files(smb_fname->base_name))
1376 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1377 goto out;
1380 clientFname = NULL;
1381 ctx = talloc_tos();
1383 if ((status = alloc_get_client_smb_fname(handle, ctx,
1384 smb_fname,
1385 &clientFname)))
1387 goto err;
1389 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1390 clientFname->base_name));
1391 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1393 goto err;
1395 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1397 goto err;
1400 /* Unlike functions with const smb_filename, we have to
1401 * modify smb_fname itself to pass our info back up.
1403 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1404 "from clientFname '%s'\n",
1405 smb_fname->base_name,
1406 clientFname->base_name));
1407 smb_fname->st = clientFname->st;
1408 err:
1409 TALLOC_FREE(clientFname);
1410 out:
1411 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1412 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1413 return status;
1417 * Success: return 0
1418 * Failure: set errno, return -1
1420 static int mh_lstat(vfs_handle_struct *handle,
1421 struct smb_filename *smb_fname)
1423 int status = 0;
1424 struct smb_filename *clientFname;
1425 TALLOC_CTX *ctx;
1427 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1428 smb_fname->base_name));
1430 if (!is_in_media_files(smb_fname->base_name))
1432 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1433 goto out;
1436 clientFname = NULL;
1437 ctx = talloc_tos();
1439 if ((status = alloc_get_client_smb_fname(handle, ctx,
1440 smb_fname,
1441 &clientFname)))
1443 goto err;
1445 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1447 goto err;
1450 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1452 goto err;
1454 /* Unlike functions with const smb_filename, we have to
1455 * modify smb_fname itself to pass our info back up.
1457 smb_fname->st = clientFname->st;
1458 err:
1459 TALLOC_FREE(clientFname);
1460 out:
1461 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1462 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1463 return status;
1467 * Success: return 0
1468 * Failure: set errno, return -1
1470 static int mh_fstat(vfs_handle_struct *handle,
1471 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1473 int status = 0;
1475 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1476 "'%s'\n", fsp_str_dbg(fsp)));
1478 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1480 goto out;
1483 if (fsp->fsp_name == NULL
1484 || !is_in_media_files(fsp->fsp_name->base_name))
1486 goto out;
1489 if ((status = mh_stat(handle, fsp->fsp_name)))
1491 goto out;
1494 *sbuf = fsp->fsp_name->st;
1495 out:
1496 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1497 "%s",
1498 fsp->fsp_name != NULL ?
1499 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1500 "0"));
1501 return status;
1505 * Success: return 0
1506 * Failure: set errno, return -1
1508 static int mh_unlink(vfs_handle_struct *handle,
1509 const struct smb_filename *smb_fname)
1511 int status;
1512 struct smb_filename *clientFname;
1513 TALLOC_CTX *ctx;
1515 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1516 if (!is_in_media_files(smb_fname->base_name))
1518 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1519 goto out;
1522 clientFname = NULL;
1523 ctx = talloc_tos();
1525 if ((status = alloc_get_client_smb_fname(handle, ctx,
1526 smb_fname,
1527 &clientFname)))
1529 goto err;
1532 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1533 err:
1534 TALLOC_FREE(clientFname);
1535 out:
1536 return status;
1540 * Success: return 0
1541 * Failure: set errno, return -1
1543 static int mh_chmod(vfs_handle_struct *handle,
1544 const char *path,
1545 mode_t mode)
1547 int status;
1548 char *clientPath;
1549 TALLOC_CTX *ctx;
1551 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1552 if (!is_in_media_files(path))
1554 status = SMB_VFS_NEXT_CHMOD(handle, path, mode);
1555 goto out;
1558 clientPath = NULL;
1559 ctx = talloc_tos();
1561 if ((status = alloc_get_client_path(handle, ctx,
1562 path,
1563 &clientPath)))
1565 goto err;
1568 status = SMB_VFS_NEXT_CHMOD(handle, clientPath, mode);
1569 err:
1570 TALLOC_FREE(clientPath);
1571 out:
1572 return status;
1576 * Success: return 0
1577 * Failure: set errno, return -1
1579 static int mh_chown(vfs_handle_struct *handle,
1580 const char *path,
1581 uid_t uid,
1582 gid_t gid)
1584 int status;
1585 char *clientPath;
1586 TALLOC_CTX *ctx;
1588 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1589 if (!is_in_media_files(path))
1591 status = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid);
1592 goto out;
1595 clientPath = NULL;
1596 ctx = talloc_tos();
1598 if ((status = alloc_get_client_path(handle, ctx,
1599 path,
1600 &clientPath)))
1602 goto err;
1605 status = SMB_VFS_NEXT_CHOWN(handle, clientPath, uid, gid);
1606 err:
1607 TALLOC_FREE(clientPath);
1608 out:
1609 return status;
1613 * Success: return 0
1614 * Failure: set errno, return -1
1616 static int mh_lchown(vfs_handle_struct *handle,
1617 const char *path,
1618 uid_t uid,
1619 gid_t gid)
1621 int status;
1622 char *clientPath;
1623 TALLOC_CTX *ctx;
1625 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1626 if (!is_in_media_files(path))
1628 status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid);
1629 goto out;
1632 clientPath = NULL;
1633 ctx = talloc_tos();
1635 if ((status = alloc_get_client_path(handle, ctx,
1636 path,
1637 &clientPath)))
1639 goto err;
1642 status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid);
1643 err:
1644 TALLOC_FREE(clientPath);
1645 out:
1646 return status;
1650 * Success: return 0
1651 * Failure: set errno, return -1
1653 static int mh_chdir(vfs_handle_struct *handle,
1654 const char *path)
1656 int status;
1657 char *clientPath;
1658 TALLOC_CTX *ctx;
1660 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1661 if (!is_in_media_files(path))
1663 status = SMB_VFS_NEXT_CHDIR(handle, path);
1664 goto out;
1667 clientPath = NULL;
1668 ctx = talloc_tos();
1670 if ((status = alloc_get_client_path(handle, ctx,
1671 path,
1672 &clientPath)))
1674 goto err;
1677 status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1678 err:
1679 TALLOC_FREE(clientPath);
1680 out:
1681 return status;
1685 * Success: return 0
1686 * Failure: set errno, return -1
1688 static int mh_ntimes(vfs_handle_struct *handle,
1689 const struct smb_filename *smb_fname,
1690 struct smb_file_time *ft)
1692 int status;
1693 struct smb_filename *clientFname;
1694 TALLOC_CTX *ctx;
1697 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1698 if (!is_in_media_files(smb_fname->base_name))
1700 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1701 goto out;
1704 clientFname = NULL;
1705 ctx = talloc_tos();
1707 if ((status = alloc_get_client_smb_fname(handle, ctx,
1708 smb_fname,
1709 &clientFname)))
1711 goto err;
1714 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1715 err:
1716 TALLOC_FREE(clientFname);
1717 out:
1718 return status;
1722 * Success: return 0
1723 * Failure: set errno, return -1
1725 static int mh_symlink(vfs_handle_struct *handle,
1726 const char *oldpath,
1727 const char *newpath)
1729 int status;
1730 char *oldClientPath;
1731 char *newClientPath;
1732 TALLOC_CTX *ctx;
1734 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1735 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1737 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1738 goto out;
1741 oldClientPath = NULL;
1742 newClientPath = NULL;
1743 ctx = talloc_tos();
1745 if ((status = alloc_get_client_path(handle, ctx,
1746 oldpath,
1747 &oldClientPath)))
1749 goto err;
1752 if ((status = alloc_get_client_path(handle, ctx,
1753 newpath,
1754 &newClientPath)))
1756 goto err;
1759 status = SMB_VFS_NEXT_SYMLINK(handle,
1760 oldClientPath,
1761 newClientPath);
1763 err:
1764 TALLOC_FREE(newClientPath);
1765 TALLOC_FREE(oldClientPath);
1766 out:
1767 return status;
1771 * Success: return byte count
1772 * Failure: set errno, return -1
1774 static int mh_readlink(vfs_handle_struct *handle,
1775 const char *path,
1776 char *buf,
1777 size_t bufsiz)
1779 int status;
1780 char *clientPath;
1781 TALLOC_CTX *ctx;
1783 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1784 if (!is_in_media_files(path))
1786 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1787 goto out;
1790 clientPath = NULL;
1791 ctx = talloc_tos();
1793 if ((status = alloc_get_client_path(handle, ctx,
1794 path,
1795 &clientPath)))
1797 goto err;
1800 status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1801 err:
1802 TALLOC_FREE(clientPath);
1803 out:
1804 return status;
1808 * Success: return 0
1809 * Failure: set errno, return -1
1811 static int mh_link(vfs_handle_struct *handle,
1812 const char *oldpath,
1813 const char *newpath)
1815 int status;
1816 char *oldClientPath;
1817 char *newClientPath;
1818 TALLOC_CTX *ctx;
1820 DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1821 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1823 status = SMB_VFS_NEXT_LINK(handle, oldpath, newpath);
1824 goto out;
1827 oldClientPath = NULL;
1828 newClientPath = NULL;
1829 ctx = talloc_tos();
1831 if ((status = alloc_get_client_path(handle, ctx,
1832 oldpath,
1833 &oldClientPath)))
1835 goto err;
1838 if ((status = alloc_get_client_path(handle, ctx,
1839 newpath,
1840 &newClientPath)))
1842 goto err;
1845 status = SMB_VFS_NEXT_LINK(handle, oldClientPath, newClientPath);
1846 err:
1847 TALLOC_FREE(newClientPath);
1848 TALLOC_FREE(oldClientPath);
1849 out:
1850 return status;
1854 * Success: return 0
1855 * Failure: set errno, return -1
1857 static int mh_mknod(vfs_handle_struct *handle,
1858 const char *pathname,
1859 mode_t mode,
1860 SMB_DEV_T dev)
1862 int status;
1863 char *clientPath;
1864 TALLOC_CTX *ctx;
1866 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1867 if (!is_in_media_files(pathname))
1869 status = SMB_VFS_NEXT_MKNOD(handle, pathname, mode, dev);
1870 goto out;
1873 clientPath = NULL;
1874 ctx = talloc_tos();
1876 if ((status = alloc_get_client_path(handle, ctx,
1877 pathname,
1878 &clientPath)))
1880 goto err;
1883 status = SMB_VFS_NEXT_MKNOD(handle, clientPath, mode, dev);
1884 err:
1885 TALLOC_FREE(clientPath);
1886 out:
1887 return status;
1891 * Success: return path pointer
1892 * Failure: set errno, return NULL pointer
1894 static char *mh_realpath(vfs_handle_struct *handle,
1895 const char *path)
1897 char *buf;
1898 char *clientPath;
1899 TALLOC_CTX *ctx;
1901 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1902 if (!is_in_media_files(path))
1904 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1905 goto out;
1908 clientPath = NULL;
1909 ctx = talloc_tos();
1911 if (alloc_get_client_path(handle, ctx,
1912 path,
1913 &clientPath))
1915 buf = NULL;
1916 goto err;
1919 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1920 err:
1921 TALLOC_FREE(clientPath);
1922 out:
1923 return buf;
1927 * Success: return 0
1928 * Failure: set errno, return -1
1930 static int mh_chflags(vfs_handle_struct *handle,
1931 const char *path,
1932 unsigned int flags)
1934 int status;
1935 char *clientPath;
1936 TALLOC_CTX *ctx;
1938 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1939 if (!is_in_media_files(path))
1941 status = SMB_VFS_NEXT_CHFLAGS(handle, path, flags);
1942 goto out;
1945 clientPath = NULL;
1946 ctx = talloc_tos();
1948 if ((status = alloc_get_client_path(handle, ctx,
1949 path,
1950 &clientPath)))
1952 goto err;
1955 status = SMB_VFS_NEXT_CHFLAGS(handle, clientPath, flags);
1956 err:
1957 TALLOC_FREE(clientPath);
1958 out:
1959 return status;
1963 * Success: return NT_STATUS_OK
1964 * Failure: return NT status error
1966 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1967 struct files_struct *fsp,
1968 const char *fname,
1969 TALLOC_CTX *ctx,
1970 unsigned int *num_streams,
1971 struct stream_struct **streams)
1973 NTSTATUS status;
1974 char *clientPath;
1975 TALLOC_CTX *mem_ctx;
1977 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1978 if (!is_in_media_files(fname))
1980 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname,
1981 ctx, num_streams, streams);
1982 goto out;
1985 clientPath = NULL;
1986 mem_ctx = talloc_tos();
1988 if (alloc_get_client_path(handle, mem_ctx,
1989 fname,
1990 &clientPath))
1992 status = map_nt_error_from_unix(errno);
1993 goto err;
1996 /* This only works on files, so we don't have to worry about
1997 * our fake directory stat'ing here.
1999 // But what does this function do, exactly? Does it need
2000 // extra modifications for the Avid stuff?
2001 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientPath,
2002 ctx, num_streams, streams);
2003 err:
2004 TALLOC_FREE(clientPath);
2005 out:
2006 return status;
2009 /* Ignoring get_real_filename function because the default
2010 * doesn't do anything.
2014 * Success: return NT_STATUS_OK
2015 * Failure: return NT status error
2016 * In this case, "name" is a path.
2018 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2019 const char *name,
2020 uint32_t security_info,
2021 TALLOC_CTX *mem_ctx,
2022 struct security_descriptor **ppdesc)
2024 NTSTATUS status;
2025 char *clientPath;
2026 TALLOC_CTX *ctx;
2028 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2029 if (!is_in_media_files(name))
2031 status = SMB_VFS_NEXT_GET_NT_ACL(handle, name,
2032 security_info,
2033 mem_ctx, ppdesc);
2034 goto out;
2037 clientPath = NULL;
2038 ctx = talloc_tos();
2040 if (alloc_get_client_path(handle, ctx,
2041 name,
2042 &clientPath))
2044 status = map_nt_error_from_unix(errno);
2045 goto err;
2048 status = SMB_VFS_NEXT_GET_NT_ACL(handle, clientPath,
2049 security_info,
2050 mem_ctx, ppdesc);
2051 err:
2052 TALLOC_FREE(clientPath);
2053 out:
2054 return status;
2058 * Success: return 0
2059 * Failure: set errno, return -1
2061 static int mh_chmod_acl(vfs_handle_struct *handle,
2062 const char *path,
2063 mode_t mode)
2065 int status;
2066 char *clientPath;
2067 TALLOC_CTX *ctx;
2069 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2070 if (!is_in_media_files(path))
2072 status = SMB_VFS_NEXT_CHMOD_ACL(handle, path, mode);
2073 goto out;
2076 clientPath = NULL;
2077 ctx = talloc_tos();
2079 if ((status = alloc_get_client_path(handle, ctx,
2080 path,
2081 &clientPath)))
2083 goto err;
2086 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientPath, mode);
2087 err:
2088 TALLOC_FREE(clientPath);
2089 out:
2090 return status;
2094 * Success: return acl pointer
2095 * Failure: set errno, return NULL
2097 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2098 const char *path_p,
2099 SMB_ACL_TYPE_T type,
2100 TALLOC_CTX *mem_ctx)
2102 SMB_ACL_T ret;
2103 char *clientPath;
2104 TALLOC_CTX *ctx;
2106 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2107 if (!is_in_media_files(path_p))
2109 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, path_p, type, mem_ctx);
2110 goto out;
2113 clientPath = NULL;
2114 ctx = talloc_tos();
2116 if (alloc_get_client_path(handle, ctx,
2117 path_p,
2118 &clientPath))
2120 ret = NULL;
2121 goto err;
2124 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientPath, type, mem_ctx);
2125 err:
2126 TALLOC_FREE(clientPath);
2127 out:
2128 return ret;
2132 * Success: return 0
2133 * Failure: set errno, return -1
2134 * In this case, "name" is a path.
2136 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2137 const char *name,
2138 SMB_ACL_TYPE_T acltype,
2139 SMB_ACL_T theacl)
2141 int status;
2142 char *clientPath;
2143 TALLOC_CTX *ctx;
2145 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2146 if (!is_in_media_files(name))
2148 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, name,
2149 acltype, theacl);
2150 goto out;
2153 clientPath = NULL;
2154 ctx = talloc_tos();
2156 if ((status = alloc_get_client_path(handle, ctx,
2157 name,
2158 &clientPath)))
2160 goto err;
2163 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientPath,
2164 acltype, theacl);
2165 err:
2166 TALLOC_FREE(clientPath);
2167 out:
2168 return status;
2172 * Success: return 0
2173 * Failure: set errno, return -1
2175 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2176 const char *path)
2178 int status;
2179 char *clientPath;
2180 TALLOC_CTX *ctx;
2182 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2183 if (!is_in_media_files(path))
2185 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2186 path);
2187 goto out;
2190 clientPath = NULL;
2191 ctx = talloc_tos();
2193 if ((status = alloc_get_client_path(handle, ctx,
2194 path,
2195 &clientPath)))
2197 goto err;
2200 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientPath);
2201 err:
2202 TALLOC_FREE(clientPath);
2203 out:
2204 return status;
2208 * Success: return positive number
2209 * Failure: set errno, return -1
2210 * In this case, "name" is an attr name.
2212 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2213 const char *path,
2214 const char *name,
2215 void *value,
2216 size_t size)
2218 ssize_t ret;
2219 char *clientPath;
2220 TALLOC_CTX *ctx;
2222 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2223 if (!is_in_media_files(path))
2225 ret = SMB_VFS_NEXT_GETXATTR(handle, path, name, value,
2226 size);
2227 goto out;
2230 clientPath = NULL;
2231 ctx = talloc_tos();
2233 if (alloc_get_client_path(handle, ctx,
2234 path,
2235 &clientPath))
2237 ret = -1;
2238 goto err;
2241 ret = SMB_VFS_NEXT_GETXATTR(handle, clientPath, name, value, size);
2242 err:
2243 TALLOC_FREE(clientPath);
2244 out:
2245 return ret;
2249 * Success: return positive number
2250 * Failure: set errno, return -1
2252 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2253 const char *path,
2254 char *list,
2255 size_t size)
2257 ssize_t ret;
2258 char *clientPath;
2259 TALLOC_CTX *ctx;
2261 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2262 if (!is_in_media_files(path))
2264 ret = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
2265 goto out;
2268 clientPath = NULL;
2269 ctx = talloc_tos();
2271 if (alloc_get_client_path(handle, ctx,
2272 path,
2273 &clientPath))
2275 ret = -1;
2276 goto err;
2279 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientPath, list, size);
2280 err:
2281 TALLOC_FREE(clientPath);
2282 out:
2283 return ret;
2287 * Success: return 0
2288 * Failure: set errno, return -1
2289 * In this case, "name" is an attr name.
2291 static int mh_removexattr(struct vfs_handle_struct *handle,
2292 const char *path,
2293 const char *name)
2295 int status;
2296 char *clientPath;
2297 TALLOC_CTX *ctx;
2299 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2300 if (!is_in_media_files(path))
2302 status = SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
2303 goto out;
2306 clientPath = NULL;
2307 ctx = talloc_tos();
2309 if ((status = alloc_get_client_path(handle, ctx,
2310 path,
2311 &clientPath)))
2313 goto err;
2316 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientPath, name);
2317 err:
2318 TALLOC_FREE(clientPath);
2319 out:
2320 return status;
2324 * Success: return 0
2325 * Failure: set errno, return -1
2326 * In this case, "name" is an attr name.
2328 static int mh_setxattr(struct vfs_handle_struct *handle,
2329 const char *path,
2330 const char *name,
2331 const void *value,
2332 size_t size,
2333 int flags)
2335 int status;
2336 char *clientPath;
2337 TALLOC_CTX *ctx;
2339 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2340 if (!is_in_media_files(path))
2342 status = SMB_VFS_NEXT_SETXATTR(handle, path, name, value,
2343 size, flags);
2344 goto out;
2347 clientPath = NULL;
2348 ctx = talloc_tos();
2350 if ((status = alloc_get_client_path(handle, ctx,
2351 path,
2352 &clientPath)))
2354 goto err;
2357 status = SMB_VFS_NEXT_SETXATTR(handle, clientPath, name, value,
2358 size, flags);
2359 err:
2360 TALLOC_FREE(clientPath);
2361 out:
2362 return status;
2366 * Success: return true
2367 * Failure: set errno, return false
2369 static bool mh_is_offline(struct vfs_handle_struct *handle,
2370 const struct smb_filename *fname,
2371 SMB_STRUCT_STAT *sbuf)
2373 // check if sbuf is modified further down the chain.
2374 bool ret;
2375 struct smb_filename *clientFname;
2376 TALLOC_CTX *ctx;
2378 DEBUG(MH_INFO_DEBUG, ("Entering mh_is_offline\n"));
2379 if (!is_in_media_files(fname->base_name))
2381 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, fname, sbuf);
2382 goto out;
2385 clientFname = NULL;
2386 ctx = talloc_tos();
2388 if(alloc_get_client_smb_fname(handle, ctx,
2389 fname,
2390 &clientFname))
2392 ret = -1;
2393 goto err;
2396 ret = SMB_VFS_NEXT_IS_OFFLINE(handle, clientFname, sbuf);
2397 err:
2398 TALLOC_FREE(clientFname);
2399 out:
2400 return ret;
2404 * Success: return 0 (?)
2405 * Failure: set errno, return -1
2407 static int mh_set_offline(struct vfs_handle_struct *handle,
2408 const struct smb_filename *fname)
2410 int status;
2411 struct smb_filename *clientFname;
2412 TALLOC_CTX *ctx;
2414 DEBUG(MH_INFO_DEBUG, ("Entering mh_set_offline\n"));
2415 if (!is_in_media_files(fname->base_name))
2417 status = SMB_VFS_NEXT_SET_OFFLINE(handle, fname);
2418 goto out;
2421 clientFname = NULL;
2422 ctx = talloc_tos();
2424 if ((status = alloc_get_client_smb_fname(handle, ctx,
2425 fname,
2426 &clientFname)))
2428 goto err;
2431 status = SMB_VFS_NEXT_SET_OFFLINE(handle, clientFname);
2432 err:
2433 TALLOC_FREE(clientFname);
2434 out:
2435 return status;
2438 /* VFS operations structure */
2440 static struct vfs_fn_pointers vfs_mh_fns = {
2441 /* Disk operations */
2443 .statvfs_fn = mh_statvfs,
2445 /* Directory operations */
2447 .opendir_fn = mh_opendir,
2448 .fdopendir_fn = mh_fdopendir,
2449 .readdir_fn = mh_readdir,
2450 .seekdir_fn = mh_seekdir,
2451 .telldir_fn = mh_telldir,
2452 .rewind_dir_fn = mh_rewinddir,
2453 .mkdir_fn = mh_mkdir,
2454 .rmdir_fn = mh_rmdir,
2455 .closedir_fn = mh_closedir,
2456 .init_search_op_fn = mh_init_search_op,
2458 /* File operations */
2460 .open_fn = mh_open,
2461 .create_file_fn = mh_create_file,
2462 .rename_fn = mh_rename,
2463 .stat_fn = mh_stat,
2464 .lstat_fn = mh_lstat,
2465 .fstat_fn = mh_fstat,
2466 .unlink_fn = mh_unlink,
2467 .chmod_fn = mh_chmod,
2468 .chown_fn = mh_chown,
2469 .lchown_fn = mh_lchown,
2470 .chdir_fn = mh_chdir,
2471 .ntimes_fn = mh_ntimes,
2472 .symlink_fn = mh_symlink,
2473 .readlink_fn = mh_readlink,
2474 .link_fn = mh_link,
2475 .mknod_fn = mh_mknod,
2476 .realpath_fn = mh_realpath,
2477 .chflags_fn = mh_chflags,
2478 .streaminfo_fn = mh_streaminfo,
2480 /* NT ACL operations. */
2482 .get_nt_acl_fn = mh_get_nt_acl,
2484 /* POSIX ACL operations. */
2486 .chmod_acl_fn = mh_chmod_acl,
2488 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2489 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2490 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2492 /* EA operations. */
2493 .getxattr_fn = mh_getxattr,
2494 .listxattr_fn = mh_listxattr,
2495 .removexattr_fn = mh_removexattr,
2496 .setxattr_fn = mh_setxattr,
2498 /* aio operations */
2500 /* offline operations */
2501 .is_offline_fn = mh_is_offline,
2502 .set_offline_fn = mh_set_offline
2505 NTSTATUS vfs_media_harmony_init(void);
2506 NTSTATUS vfs_media_harmony_init(void)
2508 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2509 "media_harmony", &vfs_mh_fns);
2510 if (!NT_STATUS_IS_OK(ret))
2512 goto out;
2515 vfs_mh_debug_level = debug_add_class("media_harmony");
2517 if (vfs_mh_debug_level == -1) {
2518 vfs_mh_debug_level = DBGC_VFS;
2519 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2520 "debugging class.\n"));
2521 } else {
2522 DEBUG(3, ("media_harmony_init: Debug class number of "
2523 "'media_harmony': %d\n",
2524 vfs_mh_debug_level));
2527 out:
2528 return ret;