utils: Fix up 14a533680245
[samba4-gss.git] / source3 / modules / vfs_media_harmony.c
blob10406f556fb8cd29d8518b04192e79be0a222448
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 struct smb_filename *smb_fname,
636 struct vfs_statvfs_struct *statbuf)
638 int status;
639 struct smb_filename *clientFname = NULL;
641 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n",
642 smb_fname->base_name));
644 if (!is_in_media_files(smb_fname->base_name))
646 status = SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
647 goto out;
650 status = alloc_get_client_smb_fname(handle,
651 talloc_tos(),
652 smb_fname,
653 &clientFname);
654 if (status != 0) {
655 goto err;
658 status = SMB_VFS_NEXT_STATVFS(handle, clientFname, statbuf);
659 err:
660 TALLOC_FREE(clientFname);
661 out:
662 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n",
663 smb_fname->base_name));
664 return status;
667 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
668 const char *fname,
669 struct mh_dirinfo_struct **dirInfo)
671 int status = 0;
672 char *clientPath;
673 TALLOC_CTX *ctx;
675 DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
677 *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
678 if (*dirInfo == NULL)
680 goto err;
683 (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
684 if ((*dirInfo)->dirpath == NULL)
686 goto err;
689 if (!is_in_media_files(fname))
691 (*dirInfo)->clientPath = NULL;
692 (*dirInfo)->clientMDBFilename = NULL;
693 (*dirInfo)->clientPMRFilename = NULL;
694 (*dirInfo)->clientCreatingDirname = NULL;
695 (*dirInfo)->isInMediaFiles = False;
696 goto out;
699 (*dirInfo)->isInMediaFiles = True;
701 if (alloc_set_client_dirinfo_path(handle,
702 *dirInfo,
703 &((*dirInfo)->clientMDBFilename),
704 MDB_FILENAME))
706 goto err;
709 if (alloc_set_client_dirinfo_path(handle,
710 *dirInfo,
711 &((*dirInfo)->clientPMRFilename),
712 PMR_FILENAME))
714 goto err;
717 if (alloc_set_client_dirinfo_path(handle,
718 *dirInfo,
719 &((*dirInfo)->clientCreatingDirname),
720 CREATING_DIRNAME))
722 goto err;
725 clientPath = NULL;
726 ctx = talloc_tos();
728 if (alloc_get_client_path(handle, ctx,
729 fname,
730 &clientPath))
732 goto err;
735 (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
736 if ((*dirInfo)->clientPath == NULL)
738 goto err;
741 TALLOC_FREE(clientPath);
743 out:
744 DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
745 "(*dirInfo)->clientPath '%s'\n",
746 (*dirInfo)->dirpath,
747 (*dirInfo)->clientPath));
748 return status;
750 err:
751 DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
752 TALLOC_FREE(*dirInfo);
753 status = -1;
754 errno = ENOMEM;
755 return status;
758 static DIR *mh_fdopendir(vfs_handle_struct *handle,
759 files_struct *fsp,
760 const char *mask,
761 uint32_t attr)
763 struct mh_dirinfo_struct *dirInfo = NULL;
764 DIR *dirstream;
766 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
767 fsp->fsp_name->base_name));
769 dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
770 if (!dirstream)
772 goto err;
775 if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
776 &dirInfo))
778 goto err;
781 dirInfo->dirstream = dirstream;
783 if (! dirInfo->isInMediaFiles) {
784 goto out;
787 if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
789 goto err;
792 out:
793 DEBUG(MH_INFO_DEBUG, ("Leaving with dirInfo->dirpath '%s', "
794 "dirInfo->clientPath '%s', "
795 "fsp->fsp_name->st.st_ex_mtime %s",
796 dirInfo->dirpath,
797 dirInfo->clientPath,
798 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
799 /* Success is freed in closedir. */
800 return (DIR *) dirInfo;
801 err:
802 /* Failure is freed here. */
803 DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
804 fsp->fsp_name->base_name));
805 TALLOC_FREE(dirInfo);
806 return NULL;
810 * skip MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
811 * directory, skip other client's suffixed MDB_FILENAME and PMR_FILENAME
812 * filenames and CREATING_DIRNAME directory, replace this client's
813 * suffixed MDB_FILENAME and PMR_FILENAME filenames and CREATING_DIRNAME
814 * directory with non suffixed.
816 * Success: return dirent
817 * End of data: return NULL
818 * Failure: set errno, return NULL
820 static struct dirent *
821 mh_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp)
823 mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
824 struct dirent *d = NULL;
825 int skip;
827 DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
829 DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
830 "dirInfo->clientPath '%s', "
831 "dirInfo->isInMediaFiles '%s', "
832 "dirInfo->clientMDBFilename '%s', "
833 "dirInfo->clientPMRFilename '%s', "
834 "dirInfo->clientCreatingDirname '%s'\n",
835 dirInfo->dirpath,
836 dirInfo->clientPath,
837 dirInfo->isInMediaFiles ? "True" : "False",
838 dirInfo->clientMDBFilename,
839 dirInfo->clientPMRFilename,
840 dirInfo->clientCreatingDirname));
842 if (! dirInfo->isInMediaFiles)
844 d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream);
845 goto out;
850 const char* dname;
851 bool isAppleDouble;
853 skip = False;
854 d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream);
856 if (d == NULL)
858 break;
861 /* ignore apple double prefix for logic below */
862 if (is_apple_double(d->d_name))
864 dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
865 isAppleDouble = True;
867 else
869 dname = d->d_name;
870 isAppleDouble = False;
873 /* skip Avid-special files with no client suffix */
874 if (
875 strcmp(dname, MDB_FILENAME) == 0
877 strcmp(dname, PMR_FILENAME) == 0
879 strcmp(dname, CREATING_DIRNAME) == 0
882 skip = True;
884 /* chop client suffix off this client's suffixed files */
885 else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
887 if (isAppleDouble)
889 d->d_name[MDB_FILENAME_LEN
890 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
892 else
894 d->d_name[MDB_FILENAME_LEN] = '\0';
897 else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
899 if (isAppleDouble)
901 d->d_name[PMR_FILENAME_LEN
902 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
904 else
906 d->d_name[PMR_FILENAME_LEN] = '\0';
909 else if (strcmp(dname, dirInfo->clientCreatingDirname)
910 == 0)
912 if (isAppleDouble)
914 d->d_name[CREATING_DIRNAME_LEN
915 + APPLE_DOUBLE_PREFIX_LEN] = '\0';
917 else
919 d->d_name[CREATING_DIRNAME_LEN] = '\0';
923 * Anything that starts as an Avid-special file
924 * that's made it this far should be skipped. This
925 * is different from the original behaviour, which
926 * only skipped other client's suffixed files.
928 else if (
929 strncmp(MDB_FILENAME, dname,
930 MDB_FILENAME_LEN) == 0
932 strncmp(PMR_FILENAME, dname,
933 PMR_FILENAME_LEN) == 0
935 strncmp(CREATING_DIRNAME, dname,
936 CREATING_DIRNAME_LEN) == 0
939 skip = True;
942 while (skip);
944 out:
945 DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
946 return d;
950 * Success: no success result defined.
951 * Failure: no failure result defined.
953 static void mh_rewinddir(vfs_handle_struct *handle,
954 DIR *dirp)
956 DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
957 SMB_VFS_NEXT_REWINDDIR(handle,
958 ((mh_dirinfo_struct*)dirp)->dirstream);
962 * Success: return 0
963 * Failure: set errno, return -1
965 static int mh_mkdirat(vfs_handle_struct *handle,
966 struct files_struct *dirfsp,
967 const struct smb_filename *smb_fname,
968 mode_t mode)
970 int status;
971 struct smb_filename *clientFname = NULL;
972 const char *path = smb_fname->base_name;
973 struct smb_filename *full_fname = NULL;
975 DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
977 if (!is_in_media_files(path)) {
978 status = SMB_VFS_NEXT_MKDIRAT(handle,
979 dirfsp,
980 smb_fname,
981 mode);
982 goto out;
985 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
986 dirfsp,
987 smb_fname);
988 if (full_fname == NULL) {
989 return -1;
992 status = alloc_get_client_smb_fname(handle,
993 talloc_tos(),
994 full_fname,
995 &clientFname);
996 if (status != 0) {
997 goto err;
1000 status = SMB_VFS_NEXT_MKDIRAT(handle,
1001 handle->conn->cwd_fsp,
1002 clientFname,
1003 mode);
1004 err:
1005 TALLOC_FREE(full_fname);
1006 TALLOC_FREE(clientFname);
1007 out:
1008 DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1009 return status;
1013 * Success: return 0
1014 * Failure: set errno, return -1
1016 static int mh_closedir(vfs_handle_struct *handle,
1017 DIR *dirp)
1019 DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1021 DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1022 // Will this talloc_free destroy realdirp?
1023 TALLOC_FREE(dirp);
1025 DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1026 return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1030 * Success: return non-negative file descriptor
1031 * Failure: set errno, return -1
1033 static int mh_openat(struct vfs_handle_struct *handle,
1034 const struct files_struct *dirfsp,
1035 const struct smb_filename *smb_fname,
1036 files_struct *fsp,
1037 const struct vfs_open_how *how)
1039 int ret;
1040 struct smb_filename *clientFname;
1041 TALLOC_CTX *ctx;
1043 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1044 smb_fname->base_name));
1046 if (!is_in_media_files(smb_fname->base_name)) {
1047 ret = SMB_VFS_NEXT_OPENAT(handle,
1048 dirfsp,
1049 smb_fname,
1050 fsp,
1051 how);
1052 goto out;
1055 clientFname = NULL;
1056 ctx = talloc_tos();
1058 if (alloc_get_client_smb_fname(handle, ctx, smb_fname, &clientFname)) {
1059 ret = -1;
1060 goto err;
1064 * What about fsp->fsp_name? We also have to get correct stat info into
1065 * fsp and smb_fname for DB files, don't we?
1068 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1069 "smb_fname->st.st_ex_mtime %s"
1070 " fsp->fsp_name->st.st_ex_mtime %s",
1071 smb_fname->base_name,
1072 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1073 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1075 ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, clientFname, fsp, how);
1076 err:
1077 TALLOC_FREE(clientFname);
1078 out:
1079 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1080 smb_fname->base_name));
1081 return ret;
1085 * Success: return non-negative file descriptor
1086 * Failure: set errno, return -1
1088 static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1089 struct smb_request *req,
1090 struct files_struct *dirfsp,
1091 struct smb_filename *smb_fname,
1092 uint32_t access_mask,
1093 uint32_t share_access,
1094 uint32_t create_disposition,
1095 uint32_t create_options,
1096 uint32_t file_attributes,
1097 uint32_t oplock_request,
1098 const struct smb2_lease *lease,
1099 uint64_t allocation_size,
1100 uint32_t private_flags,
1101 struct security_descriptor *sd,
1102 struct ea_list *ea_list,
1103 files_struct **result_fsp,
1104 int *pinfo,
1105 const struct smb2_create_blobs *in_context_blobs,
1106 struct smb2_create_blobs *out_context_blobs)
1108 NTSTATUS status;
1109 struct smb_filename *clientFname;
1110 TALLOC_CTX *ctx;
1113 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1114 smb_fname->base_name));
1115 if (!is_in_media_files(smb_fname->base_name))
1117 status = SMB_VFS_NEXT_CREATE_FILE(
1118 handle,
1119 req,
1120 dirfsp,
1121 smb_fname,
1122 access_mask,
1123 share_access,
1124 create_disposition,
1125 create_options,
1126 file_attributes,
1127 oplock_request,
1128 lease,
1129 allocation_size,
1130 private_flags,
1132 ea_list,
1133 result_fsp,
1134 pinfo,
1135 in_context_blobs,
1136 out_context_blobs);
1137 goto out;
1140 clientFname = NULL;
1141 ctx = talloc_tos();
1143 if (alloc_get_client_smb_fname(handle, ctx,
1144 smb_fname,
1145 &clientFname))
1147 status = map_nt_error_from_unix(errno);
1148 goto err;
1151 /* This only creates files, so we don't have to worry about
1152 * our fake directory stat'ing here.
1154 // But we still need to route stat calls for DB files
1155 // properly, right?
1156 status = SMB_VFS_NEXT_CREATE_FILE(
1157 handle,
1158 req,
1159 dirfsp,
1160 clientFname,
1161 access_mask,
1162 share_access,
1163 create_disposition,
1164 create_options,
1165 file_attributes,
1166 oplock_request,
1167 lease,
1168 allocation_size,
1169 private_flags,
1171 ea_list,
1172 result_fsp,
1173 pinfo,
1174 in_context_blobs,
1175 out_context_blobs);
1176 err:
1177 TALLOC_FREE(clientFname);
1178 out:
1179 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1180 "smb_fname->st.st_ex_mtime %s"
1181 " fsp->fsp_name->st.st_ex_mtime %s",
1182 smb_fname->base_name,
1183 ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1184 (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1185 ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1186 "No fsp time\n"));
1187 return status;
1191 * Success: return 0
1192 * Failure: set errno, return -1
1194 static int mh_renameat(vfs_handle_struct *handle,
1195 files_struct *srcfsp,
1196 const struct smb_filename *smb_fname_src,
1197 files_struct *dstfsp,
1198 const struct smb_filename *smb_fname_dst,
1199 const struct vfs_rename_how *how)
1201 int status = -1;
1202 struct smb_filename *full_fname_src = NULL;
1203 struct smb_filename *full_fname_dst = NULL;
1204 struct smb_filename *srcClientFname = NULL;
1205 struct smb_filename *dstClientFname = NULL;
1207 DEBUG(MH_INFO_DEBUG, ("Entering with "
1208 "smb_fname_src->base_name '%s', "
1209 "smb_fname_dst->base_name '%s'\n",
1210 smb_fname_src->base_name,
1211 smb_fname_dst->base_name));
1213 if (!is_in_media_files(smb_fname_src->base_name)
1215 !is_in_media_files(smb_fname_dst->base_name))
1217 status = SMB_VFS_NEXT_RENAMEAT(handle,
1218 srcfsp,
1219 smb_fname_src,
1220 dstfsp,
1221 smb_fname_dst,
1222 how);
1223 goto out;
1226 full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
1227 srcfsp,
1228 smb_fname_src);
1229 if (full_fname_src == NULL) {
1230 errno = ENOMEM;
1231 goto out;
1233 full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
1234 dstfsp,
1235 smb_fname_dst);
1236 if (full_fname_dst == NULL) {
1237 errno = ENOMEM;
1238 goto out;
1241 if ((status = alloc_get_client_smb_fname(handle,
1242 talloc_tos(),
1243 full_fname_src,
1244 &srcClientFname)))
1246 goto err;
1249 if ((status = alloc_get_client_smb_fname(handle,
1250 talloc_tos(),
1251 full_fname_dst,
1252 &dstClientFname)))
1254 goto err;
1257 status = SMB_VFS_NEXT_RENAMEAT(handle,
1258 srcfsp->conn->cwd_fsp,
1259 srcClientFname,
1260 dstfsp->conn->cwd_fsp,
1261 dstClientFname,
1262 how);
1263 err:
1264 TALLOC_FREE(full_fname_src);
1265 TALLOC_FREE(full_fname_dst);
1266 TALLOC_FREE(dstClientFname);
1267 TALLOC_FREE(srcClientFname);
1268 out:
1269 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1270 " smb_fname_dst->base_name '%s'\n",
1271 smb_fname_src->base_name,
1272 smb_fname_dst->base_name));
1273 return status;
1277 * Success: return 0
1278 * Failure: set errno, return -1
1280 static int mh_stat(vfs_handle_struct *handle,
1281 struct smb_filename *smb_fname)
1283 int status = 0;
1284 struct smb_filename *clientFname;
1285 TALLOC_CTX *ctx;
1288 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1289 smb_fname->base_name));
1291 if (!is_in_media_files(smb_fname->base_name))
1293 status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1294 goto out;
1297 clientFname = NULL;
1298 ctx = talloc_tos();
1300 if ((status = alloc_get_client_smb_fname(handle, ctx,
1301 smb_fname,
1302 &clientFname)))
1304 goto err;
1306 DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1307 clientFname->base_name));
1308 if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1310 goto err;
1312 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1314 goto err;
1317 /* Unlike functions with const smb_filename, we have to
1318 * modify smb_fname itself to pass our info back up.
1320 DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1321 "from clientFname '%s'\n",
1322 smb_fname->base_name,
1323 clientFname->base_name));
1324 smb_fname->st = clientFname->st;
1325 err:
1326 TALLOC_FREE(clientFname);
1327 out:
1328 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1329 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1330 return status;
1334 * Success: return 0
1335 * Failure: set errno, return -1
1337 static int mh_lstat(vfs_handle_struct *handle,
1338 struct smb_filename *smb_fname)
1340 int status = 0;
1341 struct smb_filename *clientFname;
1342 TALLOC_CTX *ctx;
1344 DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1345 smb_fname->base_name));
1347 if (!is_in_media_files(smb_fname->base_name))
1349 status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1350 goto out;
1353 clientFname = NULL;
1354 ctx = talloc_tos();
1356 if ((status = alloc_get_client_smb_fname(handle, ctx,
1357 smb_fname,
1358 &clientFname)))
1360 goto err;
1362 if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1364 goto err;
1367 if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1369 goto err;
1371 /* Unlike functions with const smb_filename, we have to
1372 * modify smb_fname itself to pass our info back up.
1374 smb_fname->st = clientFname->st;
1375 err:
1376 TALLOC_FREE(clientFname);
1377 out:
1378 DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1379 ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1380 return status;
1384 * Success: return 0
1385 * Failure: set errno, return -1
1387 static int mh_fstat(vfs_handle_struct *handle,
1388 files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1390 int status = 0;
1392 DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1393 "'%s'\n", fsp_str_dbg(fsp)));
1395 if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1397 goto out;
1400 if (fsp->fsp_name == NULL
1401 || !is_in_media_files(fsp->fsp_name->base_name))
1403 goto out;
1406 if ((status = mh_stat(handle, fsp->fsp_name)))
1408 goto out;
1411 *sbuf = fsp->fsp_name->st;
1412 out:
1413 DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1414 "%s",
1415 fsp->fsp_name != NULL ?
1416 ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1417 "0"));
1418 return status;
1422 * Success: return 0
1423 * Failure: set errno, return -1
1425 static int mh_unlinkat(vfs_handle_struct *handle,
1426 struct files_struct *dirfsp,
1427 const struct smb_filename *smb_fname,
1428 int flags)
1430 int status;
1431 struct smb_filename *full_fname = NULL;
1432 struct smb_filename *clientFname;
1433 TALLOC_CTX *ctx;
1435 DEBUG(MH_INFO_DEBUG, ("Entering mh_unlinkat\n"));
1436 if (!is_in_media_files(smb_fname->base_name)) {
1437 status = SMB_VFS_NEXT_UNLINKAT(handle,
1438 dirfsp,
1439 smb_fname,
1440 flags);
1441 goto out;
1444 clientFname = NULL;
1445 ctx = talloc_tos();
1447 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1448 dirfsp,
1449 smb_fname);
1450 if (full_fname == NULL) {
1451 return -1;
1454 if ((status = alloc_get_client_smb_fname(handle, ctx,
1455 full_fname,
1456 &clientFname))) {
1457 goto err;
1460 status = SMB_VFS_NEXT_UNLINKAT(handle,
1461 dirfsp->conn->cwd_fsp,
1462 clientFname,
1463 flags);
1464 err:
1465 TALLOC_FREE(full_fname);
1466 TALLOC_FREE(clientFname);
1467 out:
1468 return status;
1472 * Success: return 0
1473 * Failure: set errno, return -1
1475 static int mh_lchown(vfs_handle_struct *handle,
1476 const struct smb_filename *smb_fname,
1477 uid_t uid,
1478 gid_t gid)
1480 int status;
1481 struct smb_filename *clientFname = NULL;
1483 DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1484 if (!is_in_media_files(smb_fname->base_name))
1486 status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1487 goto out;
1490 status = alloc_get_client_smb_fname(handle,
1491 talloc_tos(),
1492 smb_fname,
1493 &clientFname);
1494 if (status != 0) {
1495 goto err;
1498 status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1499 err:
1500 TALLOC_FREE(clientFname);
1501 out:
1502 return status;
1506 * Success: return 0
1507 * Failure: set errno, return -1
1509 static int mh_chdir(vfs_handle_struct *handle,
1510 const struct smb_filename *smb_fname)
1512 int status;
1513 struct smb_filename *clientFname = NULL;
1515 DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1516 if (!is_in_media_files(smb_fname->base_name)) {
1517 status = SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1518 goto out;
1521 status = alloc_get_client_smb_fname(handle,
1522 talloc_tos(),
1523 smb_fname,
1524 &clientFname);
1525 if (status != 0) {
1526 goto err;
1529 status = SMB_VFS_NEXT_CHDIR(handle, clientFname);
1530 err:
1531 TALLOC_FREE(clientFname);
1532 out:
1533 return status;
1537 * Success: return 0
1538 * Failure: set errno, return -1
1541 static int mh_symlinkat(vfs_handle_struct *handle,
1542 const struct smb_filename *link_contents,
1543 struct files_struct *dirfsp,
1544 const struct smb_filename *new_smb_fname)
1546 int status = -1;
1547 struct smb_filename *full_fname = NULL;
1548 struct smb_filename *new_link_target = NULL;
1549 struct smb_filename *newclientFname = NULL;
1551 DEBUG(MH_INFO_DEBUG, ("Entering mh_symlinkat\n"));
1553 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1554 dirfsp,
1555 new_smb_fname);
1556 if (full_fname == NULL) {
1557 status = -1;
1558 goto err;
1561 if (!is_in_media_files(link_contents->base_name) &&
1562 !is_in_media_files(full_fname->base_name)) {
1563 status = SMB_VFS_NEXT_SYMLINKAT(handle,
1564 link_contents,
1565 dirfsp,
1566 new_smb_fname);
1567 goto out;
1570 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1571 link_contents,
1572 &new_link_target))) {
1573 goto err;
1575 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1576 full_fname,
1577 &newclientFname))) {
1578 goto err;
1581 status = SMB_VFS_NEXT_SYMLINKAT(handle,
1582 new_link_target,
1583 handle->conn->cwd_fsp,
1584 newclientFname);
1585 err:
1586 TALLOC_FREE(new_link_target);
1587 TALLOC_FREE(newclientFname);
1588 out:
1589 TALLOC_FREE(full_fname);
1590 return status;
1594 * Success: return byte count
1595 * Failure: set errno, return -1
1597 static int mh_readlinkat(vfs_handle_struct *handle,
1598 const struct files_struct *dirfsp,
1599 const struct smb_filename *smb_fname,
1600 char *buf,
1601 size_t bufsiz)
1603 int status;
1604 struct smb_filename *full_fname = NULL;
1605 struct smb_filename *clientFname = NULL;
1607 DEBUG(MH_INFO_DEBUG, ("Entering mh_readlinkat\n"));
1608 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1609 dirfsp,
1610 smb_fname);
1611 if (full_fname == NULL) {
1612 status = -1;
1613 goto err;
1616 if (!is_in_media_files(full_fname->base_name)) {
1617 status = SMB_VFS_NEXT_READLINKAT(handle,
1618 dirfsp,
1619 smb_fname,
1620 buf,
1621 bufsiz);
1622 goto out;
1625 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1626 full_fname,
1627 &clientFname))) {
1628 goto err;
1631 status = SMB_VFS_NEXT_READLINKAT(handle,
1632 handle->conn->cwd_fsp,
1633 clientFname,
1634 buf,
1635 bufsiz);
1637 err:
1638 TALLOC_FREE(clientFname);
1639 out:
1640 TALLOC_FREE(full_fname);
1641 return status;
1645 * Success: return 0
1646 * Failure: set errno, return -1
1648 static int mh_linkat(vfs_handle_struct *handle,
1649 files_struct *srcfsp,
1650 const struct smb_filename *old_smb_fname,
1651 files_struct *dstfsp,
1652 const struct smb_filename *new_smb_fname,
1653 int flags)
1655 int status;
1656 struct smb_filename *old_full_fname = NULL;
1657 struct smb_filename *oldclientFname = NULL;
1658 struct smb_filename *new_full_fname = NULL;
1659 struct smb_filename *newclientFname = NULL;
1661 DEBUG(MH_INFO_DEBUG, ("Entering mh_linkat\n"));
1663 old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1664 srcfsp,
1665 old_smb_fname);
1666 if (old_full_fname == NULL) {
1667 status = -1;
1668 goto err;
1671 new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1672 dstfsp,
1673 new_smb_fname);
1674 if (new_full_fname == NULL) {
1675 status = -1;
1676 goto err;
1679 if (!is_in_media_files(old_full_fname->base_name) &&
1680 !is_in_media_files(new_full_fname->base_name)) {
1681 TALLOC_FREE(old_full_fname);
1682 TALLOC_FREE(new_full_fname);
1684 status = SMB_VFS_NEXT_LINKAT(handle,
1685 srcfsp,
1686 old_smb_fname,
1687 dstfsp,
1688 new_smb_fname,
1689 flags);
1690 goto out;
1693 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1694 old_full_fname,
1695 &oldclientFname))) {
1696 goto err;
1698 if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1699 new_full_fname,
1700 &newclientFname))) {
1701 goto err;
1704 status = SMB_VFS_NEXT_LINKAT(handle,
1705 handle->conn->cwd_fsp,
1706 oldclientFname,
1707 handle->conn->cwd_fsp,
1708 newclientFname,
1709 flags);
1711 err:
1712 TALLOC_FREE(old_full_fname);
1713 TALLOC_FREE(new_full_fname);
1714 TALLOC_FREE(newclientFname);
1715 TALLOC_FREE(oldclientFname);
1716 out:
1717 return status;
1721 * Success: return 0
1722 * Failure: set errno, return -1
1724 static int mh_mknodat(vfs_handle_struct *handle,
1725 files_struct *dirfsp,
1726 const struct smb_filename *smb_fname,
1727 mode_t mode,
1728 SMB_DEV_T dev)
1730 int status;
1731 struct smb_filename *full_fname = NULL;
1732 struct smb_filename *clientFname = NULL;
1733 TALLOC_CTX *ctx;
1735 DEBUG(MH_INFO_DEBUG, ("Entering mh_mknodat\n"));
1737 full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1738 dirfsp,
1739 smb_fname);
1740 if (full_fname == NULL) {
1741 status = -1;
1742 goto err;
1745 if (!is_in_media_files(full_fname->base_name)) {
1746 status = SMB_VFS_NEXT_MKNODAT(handle,
1747 dirfsp,
1748 smb_fname,
1749 mode,
1750 dev);
1751 goto out;
1754 ctx = talloc_tos();
1756 if ((status = alloc_get_client_smb_fname(handle, ctx,
1757 full_fname,
1758 &clientFname))) {
1759 goto err;
1762 status = SMB_VFS_NEXT_MKNODAT(handle,
1763 handle->conn->cwd_fsp,
1764 clientFname,
1765 mode,
1766 dev);
1768 err:
1769 TALLOC_FREE(clientFname);
1770 out:
1771 TALLOC_FREE(full_fname);
1772 return status;
1776 * Success: return path pointer
1777 * Failure: set errno, return NULL pointer
1779 static struct smb_filename *mh_realpath(vfs_handle_struct *handle,
1780 TALLOC_CTX *ctx,
1781 const struct smb_filename *smb_fname)
1783 struct smb_filename *result_fname = NULL;
1784 struct smb_filename *clientFname = NULL;
1786 DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1787 if (!is_in_media_files(smb_fname->base_name)) {
1788 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1791 if (alloc_get_client_smb_fname(handle, ctx,
1792 smb_fname,
1793 &clientFname) != 0) {
1794 goto err;
1797 result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, clientFname);
1798 err:
1799 TALLOC_FREE(clientFname);
1800 return result_fname;
1803 /* Ignoring get_real_filename function because the default
1804 * doesn't do anything.
1808 * Success: return 0
1809 * Failure: set errno, return -1
1810 * In this case, "name" is an attr name.
1813 /* VFS operations structure */
1815 static struct vfs_fn_pointers vfs_mh_fns = {
1816 /* Disk operations */
1818 .statvfs_fn = mh_statvfs,
1820 /* Directory operations */
1822 .fdopendir_fn = mh_fdopendir,
1823 .readdir_fn = mh_readdir,
1824 .rewind_dir_fn = mh_rewinddir,
1825 .mkdirat_fn = mh_mkdirat,
1826 .closedir_fn = mh_closedir,
1828 /* File operations */
1830 .openat_fn = mh_openat,
1831 .create_file_fn = mh_create_file,
1832 .renameat_fn = mh_renameat,
1833 .stat_fn = mh_stat,
1834 .lstat_fn = mh_lstat,
1835 .fstat_fn = mh_fstat,
1836 .unlinkat_fn = mh_unlinkat,
1837 .lchown_fn = mh_lchown,
1838 .chdir_fn = mh_chdir,
1839 .symlinkat_fn = mh_symlinkat,
1840 .readlinkat_fn = mh_readlinkat,
1841 .linkat_fn = mh_linkat,
1842 .mknodat_fn = mh_mknodat,
1843 .realpath_fn = mh_realpath,
1845 /* EA operations. */
1846 .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1847 .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1849 /* aio operations */
1852 static_decl_vfs;
1853 NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
1855 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1856 "media_harmony", &vfs_mh_fns);
1857 if (!NT_STATUS_IS_OK(ret))
1859 goto out;
1862 vfs_mh_debug_level = debug_add_class("media_harmony");
1864 if (vfs_mh_debug_level == -1) {
1865 vfs_mh_debug_level = DBGC_VFS;
1866 DEBUG(1, ("media_harmony_init: Couldn't register custom "
1867 "debugging class.\n"));
1868 } else {
1869 DEBUG(3, ("media_harmony_init: Debug class number of "
1870 "'media_harmony': %d\n",
1871 vfs_mh_debug_level));
1874 out:
1875 return ret;