s3: VFS: Change SMB_VFS_LINK to use const struct smb_filename * instead of const...
[Samba.git] / source3 / modules / vfs_media_harmony.c
blob2659b29c498e6f86cc2a0f6e2b13ce2e8f260ee4
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 struct smb_filename *smb_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",
770 smb_fname->base_name));
772 if (alloc_set_client_dirinfo(handle, smb_fname->base_name, &dirInfo))
774 goto err;
777 if (!dirInfo->isInMediaFiles)
779 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
780 smb_fname, mask, attr);
781 } else {
782 struct smb_filename *smb_fname_clientpath =
783 synthetic_smb_fname(talloc_tos(),
784 dirInfo->clientPath,
785 NULL,
786 NULL,
787 smb_fname->flags);
788 if (smb_fname_clientpath == NULL) {
789 goto err;
792 dirInfo->dirstream = SMB_VFS_NEXT_OPENDIR(handle,
793 smb_fname_clientpath, mask, attr);
794 TALLOC_FREE(smb_fname_clientpath);
797 if (dirInfo->dirstream == NULL) {
798 goto err;
801 /* Success is freed in closedir. */
802 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
803 "dirInfo->clientPath '%s'\n",
804 dirInfo->dirpath,
805 dirInfo->clientPath));
806 return (DIR*)dirInfo;
807 err:
808 /* Failure is freed here. */
809 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n",
810 smb_fname->base_name));
811 TALLOC_FREE(dirInfo);
812 return NULL;
815 static DIR *mh_fdopendir(vfs_handle_struct *handle,
816 files_struct *fsp,
817 const char *mask,
818 uint32_t attr)
820 struct mh_dirinfo_struct *dirInfo = NULL;
821 DIR *dirstream;
823 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
824 fsp->fsp_name->base_name));
826 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
827 if (!dirstream)
829 goto err;
832 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
833 &dirInfo))
835 goto err;
838 dirInfo->dirstream = dirstream;
840 if (! dirInfo->isInMediaFiles) {
841 goto out;
844 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
846 goto err;
849 out:
850 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
851 "dirInfo->clientPath '%s', "
852 "fsp->fsp_name->st.st_ex_mtime %s",
853 dirInfo->dirpath,
854 dirInfo->clientPath,
855 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
856 /* Success is freed in closedir. */
857 return (DIR *) dirInfo;
858 err:
859 /* Failure is freed here. */
860 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
861 fsp->fsp_name->base_name));
862 TALLOC_FREE(dirInfo);
863 return NULL;
867 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
868 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
869 * filenames and CREATING_DIRNAME directory, replace this client's
870 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
871 * directory with non suffixed.
873 * Success: return dirent
874 * End of data: return NULL
875 * Failure: set errno, return NULL
877 static struct dirent *mh_readdir(vfs_handle_struct *handle,
878 DIR *dirp,
879 SMB_STRUCT_STAT *sbuf)
881 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
882 struct dirent *d = NULL;
883 int skip;
885 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
887 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
888 "dirInfo->clientPath '%s', "
889 "dirInfo->isInMediaFiles '%s', "
890 "dirInfo->clientMDBFilename '%s', "
891 "dirInfo->clientPMRFilename '%s', "
892 "dirInfo->clientCreatingDirname '%s'\n",
893 dirInfo->dirpath,
894 dirInfo->clientPath,
895 dirInfo->isInMediaFiles ? "True" : "False",
896 dirInfo->clientMDBFilename,
897 dirInfo->clientPMRFilename,
898 dirInfo->clientCreatingDirname));
900 if (! dirInfo->isInMediaFiles)
902 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
903 goto out;
908 const char* dname;
909 bool isAppleDouble;
911 skip = False;
912 d = SMB_VFS_NEXT_READDIR(handle, dirInfo->dirstream, sbuf);
914 if (d == NULL)
916 break;
919 /* ignore apple double prefix for logic below */
920 if (is_apple_double(d->d_name))
922 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
923 isAppleDouble = True;
925 else
927 dname = d->d_name;
928 isAppleDouble = False;
931 /* skip Avid-special files with no client suffix */
932 if (
933 strcmp(dname, MDB_FILENAME) == 0
935 strcmp(dname, PMR_FILENAME) == 0
937 strcmp(dname, CREATING_DIRNAME) == 0
940 skip = True;
942 /* chop client suffix off this client's suffixed files */
943 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
945 if (isAppleDouble)
947 d->d_name[MDB_FILENAME_LEN
948 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
950 else
952 d->d_name[MDB_FILENAME_LEN] = '\0';
955 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
957 if (isAppleDouble)
959 d->d_name[PMR_FILENAME_LEN
960 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
962 else
964 d->d_name[PMR_FILENAME_LEN] = '\0';
967 else if (strcmp(dname, dirInfo->clientCreatingDirname)
968 == 0)
970 if (isAppleDouble)
972 d->d_name[CREATING_DIRNAME_LEN
973 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
975 else
977 d->d_name[CREATING_DIRNAME_LEN] = '\0';
981 * Anything that starts as an Avid-special file
982 * that's made it this far should be skipped. This
983 * is different from the original behaviour, which
984 * only skipped other client's suffixed files.
986 else if (
987 strncmp(MDB_FILENAME, dname,
988 MDB_FILENAME_LEN) == 0
990 strncmp(PMR_FILENAME, dname,
991 PMR_FILENAME_LEN) == 0
993 strncmp(CREATING_DIRNAME, dname,
994 CREATING_DIRNAME_LEN) == 0
997 skip = True;
1000 while (skip);
1002 out:
1003 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
1004 return d;
1008 * Success: no success result defined.
1009 * Failure: no failure result defined.
1011 static void mh_seekdir(vfs_handle_struct *handle,
1012 DIR *dirp,
1013 long offset)
1015 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
1016 SMB_VFS_NEXT_SEEKDIR(handle,
1017 ((mh_dirinfo_struct*)dirp)->dirstream, offset);
1021 * Success: return long
1022 * Failure: no failure result defined.
1024 static long mh_telldir(vfs_handle_struct *handle,
1025 DIR *dirp)
1027 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
1028 return SMB_VFS_NEXT_TELLDIR(handle,
1029 ((mh_dirinfo_struct*)dirp)->dirstream);
1033 * Success: no success result defined.
1034 * Failure: no failure result defined.
1036 static void mh_rewinddir(vfs_handle_struct *handle,
1037 DIR *dirp)
1039 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
1040 SMB_VFS_NEXT_REWINDDIR(handle,
1041 ((mh_dirinfo_struct*)dirp)->dirstream);
1045 * Success: return 0
1046 * Failure: set errno, return -1
1048 static int mh_mkdir(vfs_handle_struct *handle,
1049 const struct smb_filename *smb_fname,
1050 mode_t mode)
1052 int status;
1053 struct smb_filename *clientFname = NULL;
1054 const char *path = smb_fname->base_name;
1056 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1058 if (!is_in_media_files(path))
1060 status = SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1061 goto out;
1064 status = alloc_get_client_smb_fname(handle,
1065 talloc_tos(),
1066 smb_fname,
1067 &clientFname);
1068 if (status != 0) {
1069 goto err;
1072 status = SMB_VFS_NEXT_MKDIR(handle, clientFname, mode);
1073 err:
1074 TALLOC_FREE(clientFname);
1075 out:
1076 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1077 return status;
1081 * Success: return 0
1082 * Failure: set errno, return -1
1084 static int mh_rmdir(vfs_handle_struct *handle,
1085 const struct smb_filename *smb_fname)
1087 int status;
1088 struct smb_filename *clientFname = NULL;
1089 const char *path = smb_fname->base_name;
1091 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1093 if (!is_in_media_files(path))
1095 status = SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1096 goto out;
1099 status = alloc_get_client_smb_fname(handle,
1100 talloc_tos(),
1101 smb_fname,
1102 &clientFname);
1103 if (status != 0) {
1104 goto err;
1107 status = SMB_VFS_NEXT_RMDIR(handle, clientFname);
1108 err:
1109 TALLOC_FREE(clientFname);
1110 out:
1111 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1112 return status;
1116 * Success: return 0
1117 * Failure: set errno, return -1
1119 static int mh_closedir(vfs_handle_struct *handle,
1120 DIR *dirp)
1122 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1124 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1125 // Will this talloc_free destroy realdirp?
1126 TALLOC_FREE(dirp);
1128 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1129 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1133 * Success: no success result defined.
1134 * Failure: no failure result defined.
1136 static void mh_init_search_op(vfs_handle_struct *handle,
1137 DIR *dirp)
1139 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_init_search_op\n"));
1140 SMB_VFS_NEXT_INIT_SEARCH_OP(handle,
1141 ((mh_dirinfo_struct*)dirp)->dirstream);
1145 * Success: return non-negative file descriptor
1146 * Failure: set errno, return -1
1148 static int mh_open(vfs_handle_struct *handle,
1149 struct smb_filename *smb_fname,
1150 files_struct *fsp,
1151 int flags,
1152 mode_t mode)
1154 int ret;
1155 struct smb_filename *clientFname;
1156 TALLOC_CTX *ctx;
1159 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1160 smb_fname->base_name));
1162 if (!is_in_media_files(smb_fname->base_name))
1164 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags,
1165 mode);
1166 goto out;
1169 clientFname = NULL;
1170 ctx = talloc_tos();
1172 if(alloc_get_client_smb_fname(handle, ctx,
1173 smb_fname,
1174 &clientFname))
1176 ret = -1;
1177 goto err;
1180 // What about fsp->fsp_name?
1181 // We also have to get correct stat info into fsp and smb_fname
1182 // for DB files, don't we?
1184 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1185 "smb_fname->st.st_ex_mtime %s"
1186 " fsp->fsp_name->st.st_ex_mtime %s",
1187 smb_fname->base_name,
1188 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1189 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1191 ret = SMB_VFS_NEXT_OPEN(handle, clientFname, fsp, flags, mode);
1192 err:
1193 TALLOC_FREE(clientFname);
1194 out:
1195 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1196 smb_fname->base_name));
1197 return ret;
1201 * Success: return non-negative file descriptor
1202 * Failure: set errno, return -1
1204 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1205 struct smb_request *req,
1206 uint16_t root_dir_fid,
1207 struct smb_filename *smb_fname,
1208 uint32_t access_mask,
1209 uint32_t share_access,
1210 uint32_t create_disposition,
1211 uint32_t create_options,
1212 uint32_t file_attributes,
1213 uint32_t oplock_request,
1214 struct smb2_lease *lease,
1215 uint64_t allocation_size,
1216 uint32_t private_flags,
1217 struct security_descriptor *sd,
1218 struct ea_list *ea_list,
1219 files_struct **result_fsp,
1220 int *pinfo,
1221 const struct smb2_create_blobs *in_context_blobs,
1222 struct smb2_create_blobs *out_context_blobs)
1224 NTSTATUS status;
1225 struct smb_filename *clientFname;
1226 TALLOC_CTX *ctx;
1229 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1230 smb_fname->base_name));
1231 if (!is_in_media_files(smb_fname->base_name))
1233 status = SMB_VFS_NEXT_CREATE_FILE(
1234 handle,
1235 req,
1236 root_dir_fid,
1237 smb_fname,
1238 access_mask,
1239 share_access,
1240 create_disposition,
1241 create_options,
1242 file_attributes,
1243 oplock_request,
1244 lease,
1245 allocation_size,
1246 private_flags,
1248 ea_list,
1249 result_fsp,
1250 pinfo,
1251 in_context_blobs,
1252 out_context_blobs);
1253 goto out;
1256 clientFname = NULL;
1257 ctx = talloc_tos();
1259 if (alloc_get_client_smb_fname(handle, ctx,
1260 smb_fname,
1261 &clientFname))
1263 status = map_nt_error_from_unix(errno);
1264 goto err;
1267 /* This only creates files, so we don't have to worry about
1268 * our fake directory stat'ing here.
1270 // But we still need to route stat calls for DB files
1271 // properly, right?
1272 status = SMB_VFS_NEXT_CREATE_FILE(
1273 handle,
1274 req,
1275 root_dir_fid,
1276 clientFname,
1277 access_mask,
1278 share_access,
1279 create_disposition,
1280 create_options,
1281 file_attributes,
1282 oplock_request,
1283 lease,
1284 allocation_size,
1285 private_flags,
1287 ea_list,
1288 result_fsp,
1289 pinfo,
1290 in_context_blobs,
1291 out_context_blobs);
1292 err:
1293 TALLOC_FREE(clientFname);
1294 out:
1295 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1296 "smb_fname->st.st_ex_mtime %s"
1297 " fsp->fsp_name->st.st_ex_mtime %s",
1298 smb_fname->base_name,
1299 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1300 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1301 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1302 "No fsp time\n"));
1303 return status;
1307 * Success: return 0
1308 * Failure: set errno, return -1
1310 static int mh_rename(vfs_handle_struct *handle,
1311 const struct smb_filename *smb_fname_src,
1312 const struct smb_filename *smb_fname_dst)
1314 int status;
1315 struct smb_filename *srcClientFname;
1316 struct smb_filename *dstClientFname;
1317 TALLOC_CTX *ctx;
1320 DEBUG(MH_INFO_DEBUG, ("Entering with "
1321 "smb_fname_src->base_name '%s', "
1322 "smb_fname_dst->base_name '%s'\n",
1323 smb_fname_src->base_name,
1324 smb_fname_dst->base_name));
1326 if (!is_in_media_files(smb_fname_src->base_name)
1328 !is_in_media_files(smb_fname_dst->base_name))
1330 status = SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
1331 smb_fname_dst);
1332 goto out;
1335 srcClientFname = NULL;
1336 dstClientFname = NULL;
1337 ctx = talloc_tos();
1339 if ((status = alloc_get_client_smb_fname(handle, ctx,
1340 smb_fname_src,
1341 &srcClientFname)))
1343 goto err;
1346 if ((status = alloc_get_client_smb_fname(handle, ctx,
1347 smb_fname_dst,
1348 &dstClientFname)))
1350 goto err;
1353 status = SMB_VFS_NEXT_RENAME(handle, srcClientFname,
1354 dstClientFname);
1355 err:
1356 TALLOC_FREE(dstClientFname);
1357 TALLOC_FREE(srcClientFname);
1358 out:
1359 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1360 " smb_fname_dst->base_name '%s'\n",
1361 smb_fname_src->base_name,
1362 smb_fname_dst->base_name));
1363 return status;
1367 * Success: return 0
1368 * Failure: set errno, return -1
1370 static int mh_stat(vfs_handle_struct *handle,
1371 struct smb_filename *smb_fname)
1373 int status = 0;
1374 struct smb_filename *clientFname;
1375 TALLOC_CTX *ctx;
1378 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1379 smb_fname->base_name));
1381 if (!is_in_media_files(smb_fname->base_name))
1383 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1384 goto out;
1387 clientFname = NULL;
1388 ctx = talloc_tos();
1390 if ((status = alloc_get_client_smb_fname(handle, ctx,
1391 smb_fname,
1392 &clientFname)))
1394 goto err;
1396 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1397 clientFname->base_name));
1398 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1400 goto err;
1402 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1404 goto err;
1407 /* Unlike functions with const smb_filename, we have to
1408 * modify smb_fname itself to pass our info back up.
1410 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1411 "from clientFname '%s'\n",
1412 smb_fname->base_name,
1413 clientFname->base_name));
1414 smb_fname->st = clientFname->st;
1415 err:
1416 TALLOC_FREE(clientFname);
1417 out:
1418 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1419 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1420 return status;
1424 * Success: return 0
1425 * Failure: set errno, return -1
1427 static int mh_lstat(vfs_handle_struct *handle,
1428 struct smb_filename *smb_fname)
1430 int status = 0;
1431 struct smb_filename *clientFname;
1432 TALLOC_CTX *ctx;
1434 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1435 smb_fname->base_name));
1437 if (!is_in_media_files(smb_fname->base_name))
1439 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1440 goto out;
1443 clientFname = NULL;
1444 ctx = talloc_tos();
1446 if ((status = alloc_get_client_smb_fname(handle, ctx,
1447 smb_fname,
1448 &clientFname)))
1450 goto err;
1452 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1454 goto err;
1457 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1459 goto err;
1461 /* Unlike functions with const smb_filename, we have to
1462 * modify smb_fname itself to pass our info back up.
1464 smb_fname->st = clientFname->st;
1465 err:
1466 TALLOC_FREE(clientFname);
1467 out:
1468 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1469 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1470 return status;
1474 * Success: return 0
1475 * Failure: set errno, return -1
1477 static int mh_fstat(vfs_handle_struct *handle,
1478 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1480 int status = 0;
1482 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1483 "'%s'\n", fsp_str_dbg(fsp)));
1485 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1487 goto out;
1490 if (fsp->fsp_name == NULL
1491 || !is_in_media_files(fsp->fsp_name->base_name))
1493 goto out;
1496 if ((status = mh_stat(handle, fsp->fsp_name)))
1498 goto out;
1501 *sbuf = fsp->fsp_name->st;
1502 out:
1503 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1504 "%s",
1505 fsp->fsp_name != NULL ?
1506 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1507 "0"));
1508 return status;
1512 * Success: return 0
1513 * Failure: set errno, return -1
1515 static int mh_unlink(vfs_handle_struct *handle,
1516 const struct smb_filename *smb_fname)
1518 int status;
1519 struct smb_filename *clientFname;
1520 TALLOC_CTX *ctx;
1522 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlink\n"));
1523 if (!is_in_media_files(smb_fname->base_name))
1525 status = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1526 goto out;
1529 clientFname = NULL;
1530 ctx = talloc_tos();
1532 if ((status = alloc_get_client_smb_fname(handle, ctx,
1533 smb_fname,
1534 &clientFname)))
1536 goto err;
1539 status = SMB_VFS_NEXT_UNLINK(handle, clientFname);
1540 err:
1541 TALLOC_FREE(clientFname);
1542 out:
1543 return status;
1547 * Success: return 0
1548 * Failure: set errno, return -1
1550 static int mh_chmod(vfs_handle_struct *handle,
1551 const struct smb_filename *smb_fname,
1552 mode_t mode)
1554 int status;
1555 struct smb_filename *clientFname = NULL;
1557 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod\n"));
1558 if (!is_in_media_files(smb_fname->base_name))
1560 status = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1561 goto out;
1564 status = alloc_get_client_smb_fname(handle,
1565 talloc_tos(),
1566 smb_fname,
1567 &clientFname);
1568 if (status != 0) {
1569 goto err;
1572 status = SMB_VFS_NEXT_CHMOD(handle, clientFname, mode);
1573 err:
1574 TALLOC_FREE(clientFname);
1575 out:
1576 return status;
1580 * Success: return 0
1581 * Failure: set errno, return -1
1583 static int mh_chown(vfs_handle_struct *handle,
1584 const struct smb_filename *smb_fname,
1585 uid_t uid,
1586 gid_t gid)
1588 int status;
1589 struct smb_filename *clientFname = NULL;
1591 DEBUG(MH_INFO_DEBUG, ("Entering mh_chown\n"));
1592 if (!is_in_media_files(smb_fname->base_name))
1594 status = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1595 goto out;
1598 status = alloc_get_client_smb_fname(handle,
1599 talloc_tos(),
1600 smb_fname,
1601 &clientFname);
1602 if (status != 0) {
1603 goto err;
1606 status = SMB_VFS_NEXT_CHOWN(handle, clientFname, uid, gid);
1607 err:
1608 TALLOC_FREE(clientFname);
1609 out:
1610 return status;
1614 * Success: return 0
1615 * Failure: set errno, return -1
1617 static int mh_lchown(vfs_handle_struct *handle,
1618 const struct smb_filename *smb_fname,
1619 uid_t uid,
1620 gid_t gid)
1622 int status;
1623 struct smb_filename *clientFname = NULL;
1625 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1626 if (!is_in_media_files(smb_fname->base_name))
1628 status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1629 goto out;
1632 status = alloc_get_client_smb_fname(handle,
1633 talloc_tos(),
1634 smb_fname,
1635 &clientFname);
1636 if (status != 0) {
1637 goto err;
1640 status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1641 err:
1642 TALLOC_FREE(clientFname);
1643 out:
1644 return status;
1648 * Success: return 0
1649 * Failure: set errno, return -1
1651 static int mh_chdir(vfs_handle_struct *handle,
1652 const char *path)
1654 int status;
1655 char *clientPath;
1656 TALLOC_CTX *ctx;
1658 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1659 if (!is_in_media_files(path))
1661 status = SMB_VFS_NEXT_CHDIR(handle, path);
1662 goto out;
1665 clientPath = NULL;
1666 ctx = talloc_tos();
1668 if ((status = alloc_get_client_path(handle, ctx,
1669 path,
1670 &clientPath)))
1672 goto err;
1675 status = SMB_VFS_NEXT_CHDIR(handle, clientPath);
1676 err:
1677 TALLOC_FREE(clientPath);
1678 out:
1679 return status;
1683 * Success: return 0
1684 * Failure: set errno, return -1
1686 static int mh_ntimes(vfs_handle_struct *handle,
1687 const struct smb_filename *smb_fname,
1688 struct smb_file_time *ft)
1690 int status;
1691 struct smb_filename *clientFname;
1692 TALLOC_CTX *ctx;
1695 DEBUG(MH_INFO_DEBUG, ("Entering mh_ntimes\n"));
1696 if (!is_in_media_files(smb_fname->base_name))
1698 status = SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1699 goto out;
1702 clientFname = NULL;
1703 ctx = talloc_tos();
1705 if ((status = alloc_get_client_smb_fname(handle, ctx,
1706 smb_fname,
1707 &clientFname)))
1709 goto err;
1712 status = SMB_VFS_NEXT_NTIMES(handle, clientFname, ft);
1713 err:
1714 TALLOC_FREE(clientFname);
1715 out:
1716 return status;
1720 * Success: return 0
1721 * Failure: set errno, return -1
1723 static int mh_symlink(vfs_handle_struct *handle,
1724 const char *oldpath,
1725 const char *newpath)
1727 int status;
1728 char *oldClientPath;
1729 char *newClientPath;
1730 TALLOC_CTX *ctx;
1732 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n"));
1733 if (!is_in_media_files(oldpath) && !is_in_media_files(newpath))
1735 status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath);
1736 goto out;
1739 oldClientPath = NULL;
1740 newClientPath = NULL;
1741 ctx = talloc_tos();
1743 if ((status = alloc_get_client_path(handle, ctx,
1744 oldpath,
1745 &oldClientPath)))
1747 goto err;
1750 if ((status = alloc_get_client_path(handle, ctx,
1751 newpath,
1752 &newClientPath)))
1754 goto err;
1757 status = SMB_VFS_NEXT_SYMLINK(handle,
1758 oldClientPath,
1759 newClientPath);
1761 err:
1762 TALLOC_FREE(newClientPath);
1763 TALLOC_FREE(oldClientPath);
1764 out:
1765 return status;
1769 * Success: return byte count
1770 * Failure: set errno, return -1
1772 static int mh_readlink(vfs_handle_struct *handle,
1773 const char *path,
1774 char *buf,
1775 size_t bufsiz)
1777 int status;
1778 char *clientPath;
1779 TALLOC_CTX *ctx;
1781 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlink\n"));
1782 if (!is_in_media_files(path))
1784 status = SMB_VFS_NEXT_READLINK(handle, path, buf, bufsiz);
1785 goto out;
1788 clientPath = NULL;
1789 ctx = talloc_tos();
1791 if ((status = alloc_get_client_path(handle, ctx,
1792 path,
1793 &clientPath)))
1795 goto err;
1798 status = SMB_VFS_NEXT_READLINK(handle, clientPath, buf, bufsiz);
1799 err:
1800 TALLOC_FREE(clientPath);
1801 out:
1802 return status;
1806 * Success: return 0
1807 * Failure: set errno, return -1
1809 static int mh_link(vfs_handle_struct *handle,
1810 const struct smb_filename *old_smb_fname,
1811 const struct smb_filename *new_smb_fname)
1813 int status;
1814 struct smb_filename *oldclientFname = NULL;
1815 struct smb_filename *newclientFname = NULL;
1817 DEBUG(MH_INFO_DEBUG, ("Entering mh_link\n"));
1818 if (!is_in_media_files(old_smb_fname->base_name) &&
1819 !is_in_media_files(new_smb_fname->base_name)) {
1820 status = SMB_VFS_NEXT_LINK(handle,
1821 old_smb_fname,
1822 new_smb_fname);
1823 goto out;
1826 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1827 old_smb_fname,
1828 &oldclientFname))) {
1829 goto err;
1831 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1832 new_smb_fname,
1833 &newclientFname))) {
1834 goto err;
1837 status = SMB_VFS_NEXT_LINK(handle, oldclientFname, newclientFname);
1838 err:
1839 TALLOC_FREE(newclientFname);
1840 TALLOC_FREE(oldclientFname);
1841 out:
1842 return status;
1846 * Success: return 0
1847 * Failure: set errno, return -1
1849 static int mh_mknod(vfs_handle_struct *handle,
1850 const struct smb_filename *smb_fname,
1851 mode_t mode,
1852 SMB_DEV_T dev)
1854 int status;
1855 struct smb_filename *clientFname = NULL;
1856 TALLOC_CTX *ctx;
1858 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknod\n"));
1859 if (!is_in_media_files(smb_fname->base_name)) {
1860 status = SMB_VFS_NEXT_MKNOD(handle, smb_fname, mode, dev);
1861 goto out;
1864 ctx = talloc_tos();
1866 if ((status = alloc_get_client_smb_fname(handle, ctx,
1867 smb_fname,
1868 &clientFname))) {
1869 goto err;
1872 status = SMB_VFS_NEXT_MKNOD(handle, clientFname, mode, dev);
1873 err:
1874 TALLOC_FREE(clientFname);
1875 out:
1876 return status;
1880 * Success: return path pointer
1881 * Failure: set errno, return NULL pointer
1883 static char *mh_realpath(vfs_handle_struct *handle,
1884 const char *path)
1886 char *buf;
1887 char *clientPath;
1888 TALLOC_CTX *ctx;
1890 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1891 if (!is_in_media_files(path))
1893 buf = SMB_VFS_NEXT_REALPATH(handle, path);
1894 goto out;
1897 clientPath = NULL;
1898 ctx = talloc_tos();
1900 if (alloc_get_client_path(handle, ctx,
1901 path,
1902 &clientPath))
1904 buf = NULL;
1905 goto err;
1908 buf = SMB_VFS_NEXT_REALPATH(handle, clientPath);
1909 err:
1910 TALLOC_FREE(clientPath);
1911 out:
1912 return buf;
1916 * Success: return 0
1917 * Failure: set errno, return -1
1919 static int mh_chflags(vfs_handle_struct *handle,
1920 const struct smb_filename *smb_fname,
1921 unsigned int flags)
1923 int status;
1924 struct smb_filename *clientFname = NULL;
1925 TALLOC_CTX *ctx;
1927 DEBUG(MH_INFO_DEBUG, ("Entering mh_chflags\n"));
1928 if (!is_in_media_files(smb_fname->base_name)) {
1929 status = SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
1930 goto out;
1933 ctx = talloc_tos();
1935 if ((status = alloc_get_client_smb_fname(handle, ctx,
1936 smb_fname,
1937 &clientFname))) {
1938 goto err;
1941 status = SMB_VFS_NEXT_CHFLAGS(handle, clientFname, flags);
1942 err:
1943 TALLOC_FREE(clientFname);
1944 out:
1945 return status;
1949 * Success: return NT_STATUS_OK
1950 * Failure: return NT status error
1952 static NTSTATUS mh_streaminfo(struct vfs_handle_struct *handle,
1953 struct files_struct *fsp,
1954 const struct smb_filename *smb_fname,
1955 TALLOC_CTX *ctx,
1956 unsigned int *num_streams,
1957 struct stream_struct **streams)
1959 NTSTATUS status;
1960 int ret;
1961 struct smb_filename *clientFname = NULL;
1963 DEBUG(MH_INFO_DEBUG, ("Entering mh_streaminfo\n"));
1964 if (!is_in_media_files(smb_fname->base_name)) {
1965 status = SMB_VFS_NEXT_STREAMINFO(handle,
1966 fsp,
1967 smb_fname,
1968 ctx,
1969 num_streams,
1970 streams);
1971 goto out;
1974 ret = alloc_get_client_smb_fname(handle,
1975 talloc_tos(),
1976 smb_fname,
1977 &clientFname);
1978 if (ret != 0) {
1979 status = NT_STATUS_NO_MEMORY;
1980 goto err;
1983 /* This only works on files, so we don't have to worry about
1984 * our fake directory stat'ing here.
1986 status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, clientFname,
1987 ctx, num_streams, streams);
1988 err:
1989 TALLOC_FREE(clientFname);
1990 out:
1991 return status;
1994 /* Ignoring get_real_filename function because the default
1995 * doesn't do anything.
1999 * Success: return NT_STATUS_OK
2000 * Failure: return NT status error
2001 * In this case, "name" is a path.
2003 static NTSTATUS mh_get_nt_acl(vfs_handle_struct *handle,
2004 const struct smb_filename *smb_fname,
2005 uint32_t security_info,
2006 TALLOC_CTX *mem_ctx,
2007 struct security_descriptor **ppdesc)
2009 NTSTATUS status;
2010 char *clientPath;
2011 struct smb_filename *client_smb_fname = NULL;
2012 TALLOC_CTX *ctx;
2014 DEBUG(MH_INFO_DEBUG, ("Entering mh_get_nt_acl\n"));
2015 if (!is_in_media_files(smb_fname->base_name))
2017 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname,
2018 security_info,
2019 mem_ctx, ppdesc);
2020 goto out;
2023 clientPath = NULL;
2024 ctx = talloc_tos();
2026 if (alloc_get_client_path(handle, ctx,
2027 smb_fname->base_name,
2028 &clientPath))
2030 status = map_nt_error_from_unix(errno);
2031 goto err;
2034 client_smb_fname = synthetic_smb_fname(talloc_tos(),
2035 clientPath,
2036 NULL,
2037 NULL,
2038 smb_fname->flags);
2039 if (client_smb_fname == NULL) {
2040 TALLOC_FREE(clientPath);
2041 return NT_STATUS_NO_MEMORY;
2044 status = SMB_VFS_NEXT_GET_NT_ACL(handle, client_smb_fname,
2045 security_info,
2046 mem_ctx, ppdesc);
2047 err:
2048 TALLOC_FREE(clientPath);
2049 TALLOC_FREE(client_smb_fname);
2050 out:
2051 return status;
2055 * Success: return 0
2056 * Failure: set errno, return -1
2058 static int mh_chmod_acl(vfs_handle_struct *handle,
2059 const struct smb_filename *smb_fname,
2060 mode_t mode)
2062 int status;
2063 struct smb_filename *clientFname = NULL;
2065 DEBUG(MH_INFO_DEBUG, ("Entering mh_chmod_acl\n"));
2066 if (!is_in_media_files(smb_fname->base_name))
2068 status = SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2069 goto out;
2072 status = alloc_get_client_smb_fname(handle,
2073 talloc_tos(),
2074 smb_fname,
2075 &clientFname);
2076 if (status != 0) {
2077 goto err;
2080 status = SMB_VFS_NEXT_CHMOD_ACL(handle, clientFname, mode);
2081 err:
2082 TALLOC_FREE(clientFname);
2083 out:
2084 return status;
2088 * Success: return acl pointer
2089 * Failure: set errno, return NULL
2091 static SMB_ACL_T mh_sys_acl_get_file(vfs_handle_struct *handle,
2092 const struct smb_filename *smb_fname,
2093 SMB_ACL_TYPE_T type,
2094 TALLOC_CTX *mem_ctx)
2096 SMB_ACL_T ret;
2097 int status;
2098 struct smb_filename *clientFname = NULL;
2100 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_get_file\n"));
2101 if (!is_in_media_files(smb_fname->base_name)) {
2102 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, smb_fname,
2103 type, mem_ctx);
2104 goto out;
2107 status = alloc_get_client_smb_fname(handle,
2108 talloc_tos(),
2109 smb_fname,
2110 &clientFname);
2111 if (status != 0) {
2112 ret = (SMB_ACL_T)NULL;
2113 goto err;
2116 ret = SMB_VFS_NEXT_SYS_ACL_GET_FILE(handle, clientFname, type, mem_ctx);
2117 err:
2118 TALLOC_FREE(clientFname);
2119 out:
2120 return ret;
2124 * Success: return 0
2125 * Failure: set errno, return -1
2126 * In this case, "name" is a path.
2128 static int mh_sys_acl_set_file(vfs_handle_struct *handle,
2129 const struct smb_filename *smb_fname,
2130 SMB_ACL_TYPE_T acltype,
2131 SMB_ACL_T theacl)
2133 int status;
2134 struct smb_filename *clientFname = NULL;
2136 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_set_file\n"));
2137 if (!is_in_media_files(smb_fname->base_name)) {
2138 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, smb_fname,
2139 acltype, theacl);
2140 goto out;
2143 status = alloc_get_client_smb_fname(handle,
2144 talloc_tos(),
2145 smb_fname,
2146 &clientFname);
2147 if (status != 0) {
2148 goto err;
2151 status = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle, clientFname,
2152 acltype, theacl);
2153 err:
2154 TALLOC_FREE(clientFname);
2155 out:
2156 return status;
2160 * Success: return 0
2161 * Failure: set errno, return -1
2163 static int mh_sys_acl_delete_def_file(vfs_handle_struct *handle,
2164 const struct smb_filename *smb_fname)
2166 int status;
2167 struct smb_filename *clientFname = NULL;
2169 DEBUG(MH_INFO_DEBUG, ("Entering mh_sys_acl_delete_def_file\n"));
2170 if (!is_in_media_files(smb_fname->base_name)) {
2171 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle,
2172 smb_fname);
2173 goto out;
2176 status = alloc_get_client_smb_fname(handle,
2177 talloc_tos(),
2178 smb_fname,
2179 &clientFname);
2180 if (status != 0) {
2181 goto err;
2183 status = SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FILE(handle, clientFname);
2184 err:
2185 TALLOC_FREE(clientFname);
2186 out:
2187 return status;
2191 * Success: return positive number
2192 * Failure: set errno, return -1
2193 * In this case, "name" is an attr name.
2195 static ssize_t mh_getxattr(struct vfs_handle_struct *handle,
2196 const struct smb_filename *smb_fname,
2197 const char *name,
2198 void *value,
2199 size_t size)
2201 int status;
2202 struct smb_filename *clientFname = NULL;
2203 ssize_t ret;
2205 DEBUG(MH_INFO_DEBUG, ("Entering mh_getxattr\n"));
2206 if (!is_in_media_files(smb_fname->base_name)) {
2207 ret = SMB_VFS_NEXT_GETXATTR(handle, smb_fname,
2208 name, value, size);
2209 goto out;
2212 status = alloc_get_client_smb_fname(handle,
2213 talloc_tos(),
2214 smb_fname,
2215 &clientFname);
2216 if (status != 0) {
2217 ret = -1;
2218 goto err;
2220 ret = SMB_VFS_NEXT_GETXATTR(handle, clientFname, name, value, size);
2221 err:
2222 TALLOC_FREE(clientFname);
2223 out:
2224 return ret;
2228 * Success: return positive number
2229 * Failure: set errno, return -1
2231 static ssize_t mh_listxattr(struct vfs_handle_struct *handle,
2232 const struct smb_filename *smb_fname,
2233 char *list,
2234 size_t size)
2236 ssize_t ret;
2237 struct smb_filename *clientFname = NULL;
2238 int status;
2240 DEBUG(MH_INFO_DEBUG, ("Entering mh_listxattr\n"));
2241 if (!is_in_media_files(smb_fname->base_name)) {
2242 ret = SMB_VFS_NEXT_LISTXATTR(handle, smb_fname, list, size);
2243 goto out;
2246 status = alloc_get_client_smb_fname(handle,
2247 talloc_tos(),
2248 smb_fname,
2249 &clientFname);
2250 if (status != 0) {
2251 ret = -1;
2252 goto err;
2255 ret = SMB_VFS_NEXT_LISTXATTR(handle, clientFname, list, size);
2256 err:
2257 TALLOC_FREE(clientFname);
2258 out:
2259 return ret;
2263 * Success: return 0
2264 * Failure: set errno, return -1
2265 * In this case, "name" is an attr name.
2267 static int mh_removexattr(struct vfs_handle_struct *handle,
2268 const struct smb_filename *smb_fname,
2269 const char *name)
2271 int status;
2272 struct smb_filename *clientFname = NULL;
2274 DEBUG(MH_INFO_DEBUG, ("Entering mh_removexattr\n"));
2275 if (!is_in_media_files(smb_fname->base_name)) {
2276 status = SMB_VFS_NEXT_REMOVEXATTR(handle, smb_fname, name);
2277 goto out;
2280 status = alloc_get_client_smb_fname(handle,
2281 talloc_tos(),
2282 smb_fname,
2283 &clientFname);
2284 if (status != 0) {
2285 goto err;
2287 status = SMB_VFS_NEXT_REMOVEXATTR(handle, clientFname, name);
2288 err:
2289 TALLOC_FREE(clientFname);
2290 out:
2291 return status;
2295 * Success: return 0
2296 * Failure: set errno, return -1
2297 * In this case, "name" is an attr name.
2299 static int mh_setxattr(struct vfs_handle_struct *handle,
2300 const struct smb_filename *smb_fname,
2301 const char *name,
2302 const void *value,
2303 size_t size,
2304 int flags)
2306 int status;
2307 struct smb_filename *clientFname = NULL;
2309 DEBUG(MH_INFO_DEBUG, ("Entering mh_setxattr\n"));
2310 if (!is_in_media_files(smb_fname->base_name)) {
2311 status = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, name, value,
2312 size, flags);
2313 goto out;
2316 status = alloc_get_client_smb_fname(handle,
2317 talloc_tos(),
2318 smb_fname,
2319 &clientFname);
2320 if (status != 0) {
2321 goto err;
2323 status = SMB_VFS_NEXT_SETXATTR(handle, clientFname, name, value,
2324 size, flags);
2325 err:
2326 TALLOC_FREE(clientFname);
2327 out:
2328 return status;
2331 /* VFS operations structure */
2333 static struct vfs_fn_pointers vfs_mh_fns = {
2334 /* Disk operations */
2336 .statvfs_fn = mh_statvfs,
2338 /* Directory operations */
2340 .opendir_fn = mh_opendir,
2341 .fdopendir_fn = mh_fdopendir,
2342 .readdir_fn = mh_readdir,
2343 .seekdir_fn = mh_seekdir,
2344 .telldir_fn = mh_telldir,
2345 .rewind_dir_fn = mh_rewinddir,
2346 .mkdir_fn = mh_mkdir,
2347 .rmdir_fn = mh_rmdir,
2348 .closedir_fn = mh_closedir,
2349 .init_search_op_fn = mh_init_search_op,
2351 /* File operations */
2353 .open_fn = mh_open,
2354 .create_file_fn = mh_create_file,
2355 .rename_fn = mh_rename,
2356 .stat_fn = mh_stat,
2357 .lstat_fn = mh_lstat,
2358 .fstat_fn = mh_fstat,
2359 .unlink_fn = mh_unlink,
2360 .chmod_fn = mh_chmod,
2361 .chown_fn = mh_chown,
2362 .lchown_fn = mh_lchown,
2363 .chdir_fn = mh_chdir,
2364 .ntimes_fn = mh_ntimes,
2365 .symlink_fn = mh_symlink,
2366 .readlink_fn = mh_readlink,
2367 .link_fn = mh_link,
2368 .mknod_fn = mh_mknod,
2369 .realpath_fn = mh_realpath,
2370 .chflags_fn = mh_chflags,
2371 .streaminfo_fn = mh_streaminfo,
2373 /* NT ACL operations. */
2375 .get_nt_acl_fn = mh_get_nt_acl,
2377 /* POSIX ACL operations. */
2379 .chmod_acl_fn = mh_chmod_acl,
2381 .sys_acl_get_file_fn = mh_sys_acl_get_file,
2382 .sys_acl_set_file_fn = mh_sys_acl_set_file,
2383 .sys_acl_delete_def_file_fn = mh_sys_acl_delete_def_file,
2385 /* EA operations. */
2386 .getxattr_fn = mh_getxattr,
2387 .listxattr_fn = mh_listxattr,
2388 .removexattr_fn = mh_removexattr,
2389 .setxattr_fn = mh_setxattr,
2391 /* aio operations */
2394 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *);
2395 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
2397 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2398 "media_harmony", &vfs_mh_fns);
2399 if (!NT_STATUS_IS_OK(ret))
2401 goto out;
2404 vfs_mh_debug_level = debug_add_class("media_harmony");
2406 if (vfs_mh_debug_level == -1) {
2407 vfs_mh_debug_level = DBGC_VFS;
2408 DEBUG(1, ("media_harmony_init: Couldn't register custom "
2409 "debugging class.\n"));
2410 } else {
2411 DEBUG(3, ("media_harmony_init: Debug class number of "
2412 "'media_harmony': %d\n",
2413 vfs_mh_debug_level));
2416 out:
2417 return ret;