Line data Source code
1 : /*
2 : * $Id: media_harmony.c,v 1.1 2007/11/06 10:07:22 stuart_hc Exp $
3 : *
4 : * Samba VFS module supporting multiple AVID clients sharing media.
5 : *
6 : * Copyright (C) 2005 Philip de Nier <philipn@users.sourceforge.net>
7 : * Copyright (C) 2012 Andrew Klaassen <clawsoon@yahoo.com>
8 : *
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.
13 : *
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.
18 : *
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.
23 : */
24 :
25 :
26 : /*
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.
30 : *
31 : * Add this module to the vfs objects option in your Samba share
32 : * configuration.
33 : * eg.
34 : *
35 : * [avid_win]
36 : * path = /video
37 : * vfs objects = media_harmony
38 : * ...
39 : *
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 *):
43 : *
44 : * veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
45 : * delete veto files = yes
46 : *
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.
50 : *
51 : *
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.
60 : *
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.
73 : *
74 : *
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.
82 : *
83 : */
84 :
85 :
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"
92 :
93 : #define MH_INFO_DEBUG 10
94 : #define MH_ERR_DEBUG 0
95 :
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;
110 :
111 : static int vfs_mh_debug_level = DBGC_VFS;
112 :
113 : /* supplements the directory list stream */
114 : typedef struct mh_dirinfo_struct
115 : {
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;
124 :
125 :
126 : /* Add "_<ip address>_<user name>" suffix to path or filename.
127 : *
128 : * Success: return 0
129 : * Failure: set errno, path NULL, return -1
130 : */
131 0 : static int alloc_append_client_suffix(vfs_handle_struct *handle,
132 : char **path)
133 : {
134 0 : int status = 0;
135 0 : char *raddr = NULL;
136 :
137 0 : DEBUG(MH_INFO_DEBUG, ("Entering with *path '%s'\n", *path));
138 :
139 0 : raddr = tsocket_address_inet_addr_string(
140 0 : handle->conn->sconn->remote_address, talloc_tos());
141 0 : if (raddr == NULL)
142 : {
143 0 : errno = ENOMEM;
144 0 : status = -1;
145 0 : goto err;
146 : }
147 :
148 : /* talloc_asprintf_append uses talloc_realloc, which
149 : * frees original 'path' memory so we don't have to.
150 : */
151 0 : *path = talloc_asprintf_append(*path, "_%s_%s",
152 : raddr,
153 0 : handle->conn->session_info->unix_info->sanitized_username);
154 0 : if (*path == NULL)
155 : {
156 0 : DEBUG(MH_ERR_DEBUG, ("alloc_append_client_suffix "
157 : "out of memory\n"));
158 0 : errno = ENOMEM;
159 0 : status = -1;
160 0 : goto err;
161 : }
162 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
163 0 : err:
164 0 : TALLOC_FREE(raddr);
165 0 : return status;
166 : }
167 :
168 :
169 : /* Returns True if the file or directory begins with the appledouble
170 : * prefix.
171 : */
172 0 : static bool is_apple_double(const char* fname)
173 : {
174 0 : bool ret = False;
175 :
176 0 : DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
177 :
178 0 : if (strncmp(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)
179 : == 0)
180 : {
181 0 : ret = True;
182 : }
183 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
184 : ret == True ? "True" : "False"));
185 0 : return ret;
186 : }
187 :
188 0 : static bool starts_with_media_dir(const char* media_dirname,
189 : size_t media_dirname_len, const char* path)
190 : {
191 0 : bool ret = False;
192 : const char *path_start;
193 :
194 0 : DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
195 : "path '%s'\n", media_dirname, path));
196 :
197 : /* Sometimes Samba gives us "./OMFI MediaFiles". */
198 0 : if (strncmp(path, "./", 2) == 0)
199 : {
200 0 : path_start = &path[2];
201 : }
202 : else {
203 0 : path_start = path;
204 : }
205 :
206 0 : if (strncmp(media_dirname, path_start, media_dirname_len) == 0
207 0 : &&
208 : (
209 0 : path_start[media_dirname_len] == '\0'
210 0 : ||
211 0 : path_start[media_dirname_len] == '/'
212 : )
213 : )
214 : {
215 0 : ret = True;
216 : }
217 :
218 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
219 : ret == True ? "True" : "False"));
220 0 : return ret;
221 : }
222 :
223 : /*
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.
229 : */
230 0 : static bool is_in_media_files(const char* path)
231 : {
232 0 : bool ret = False;
233 :
234 0 : DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
235 :
236 0 : if (
237 0 : starts_with_media_dir(AVID_MEDIAFILES_DIRNAME,
238 : AVID_MEDIAFILES_DIRNAME_LEN, path)
239 0 : ||
240 0 : starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
241 : OMFI_MEDIAFILES_DIRNAME_LEN, path)
242 : )
243 : {
244 0 : ret = True;
245 : }
246 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
247 : ret == True ? "True" : "False"));
248 0 : return ret;
249 : }
250 :
251 : /*
252 : * Returns depth of path under media directory. Deals with the
253 : * occasional ..../. and ..../.. paths that get passed to stat.
254 : *
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.
258 : *
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.
262 : */
263 0 : static int depth_from_media_dir(const char* media_dirname,
264 : size_t media_dirname_len, const char* path)
265 : {
266 0 : int transition_count = 0;
267 : const char *path_start;
268 : const char *pathPtr;
269 :
270 0 : DEBUG(MH_INFO_DEBUG, ("Entering with media_dirname '%s' "
271 : "path '%s'\n", media_dirname, path));
272 :
273 : /* Sometimes Samba gives us "./OMFI MediaFiles". */
274 0 : if (strncmp(path, "./", 2) == 0)
275 : {
276 0 : path_start = &path[2];
277 : }
278 : else {
279 0 : path_start = path;
280 : }
281 :
282 0 : if (path_start[media_dirname_len] == '\0')
283 : {
284 0 : goto out;
285 : }
286 :
287 0 : pathPtr = &path_start[media_dirname_len + 1];
288 :
289 : while(1)
290 : {
291 0 : if (*pathPtr == '\0' || *pathPtr == '/')
292 : {
293 0 : if (
294 0 : *(pathPtr - 1) == '.'
295 0 : &&
296 0 : *(pathPtr - 2) == '.'
297 0 : &&
298 0 : *(pathPtr - 3) == '/'
299 : )
300 : {
301 0 : transition_count--;
302 : }
303 0 : else if (
304 0 : !
305 : (
306 0 : *(pathPtr - 1) == '/'
307 : ||
308 : (
309 0 : *(pathPtr - 1) == '.'
310 0 : &&
311 0 : *(pathPtr - 2) == '/'
312 : )
313 : )
314 : )
315 : {
316 0 : transition_count++;
317 : }
318 : }
319 0 : if (*pathPtr == '\0')
320 : {
321 0 : break;
322 : }
323 0 : pathPtr++;
324 : }
325 :
326 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with transition_count '%i'\n",
327 : transition_count));
328 0 : out:
329 0 : return transition_count;
330 : }
331 :
332 : /* Identifies MDB and PMR files at end of path. */
333 0 : 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)
338 : {
339 0 : bool ret = False;
340 :
341 0 : 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));
347 :
348 0 : if (
349 : path_len > avid_db_filename_len
350 0 : &&
351 0 : strcmp(&path[path_len - avid_db_filename_len],
352 : avid_db_filename) == 0
353 0 : &&
354 : (
355 0 : path[path_len - avid_db_filename_len - 1] == '/'
356 0 : ||
357 : (path_len > avid_db_filename_len
358 0 : + APPLE_DOUBLE_PREFIX_LEN
359 0 : &&
360 0 : path[path_len - avid_db_filename_len
361 0 : - APPLE_DOUBLE_PREFIX_LEN - 1] == '/'
362 0 : &&
363 0 : is_apple_double(&path[path_len
364 0 : - avid_db_filename_len
365 0 : - APPLE_DOUBLE_PREFIX_LEN]))
366 : )
367 : )
368 : {
369 0 : ret = True;
370 : }
371 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with ret '%s'\n",
372 : ret == True ? "True" : "False"));
373 0 : return ret;
374 : }
375 :
376 :
377 : /* Add client suffix to paths to MDB_FILENAME, PMR_FILENAME and
378 : * CREATING_SUBDIRNAME.
379 : *
380 : * Caller must free newPath.
381 : *
382 : * Success: return 0
383 : * Failure: set errno, newPath NULL, return -1
384 : */
385 0 : static int alloc_get_client_path(vfs_handle_struct *handle,
386 : TALLOC_CTX *ctx,
387 : const char *path,
388 : char **newPath)
389 : {
390 : /* replace /CREATING_DIRNAME/ or /._CREATING_DIRNAME/
391 : * directory in path - potentially in middle of path
392 : * - with suffixed name.
393 : */
394 0 : int status = 0;
395 : char* pathPtr;
396 : size_t intermPathLen;
397 :
398 0 : DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
399 :
400 0 : *newPath = talloc_strdup(ctx, path);
401 0 : if (*newPath == NULL)
402 : {
403 0 : DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path ENOMEM #1\n"));
404 0 : errno = ENOMEM;
405 0 : status = -1;
406 0 : goto out;
407 : }
408 0 : DEBUG(MH_INFO_DEBUG, ("newPath #1 %s\n", *newPath));
409 0 : if (
410 0 : (pathPtr = strstr(path, CREATING_DIRNAME)) != NULL
411 0 : &&
412 : (
413 0 : *(pathPtr + CREATING_DIRNAME_LEN) == '\0'
414 0 : ||
415 0 : *(pathPtr + CREATING_DIRNAME_LEN) == '/'
416 : )
417 0 : &&
418 : (
419 0 : (pathPtr - path > 0
420 0 : &&
421 0 : *(pathPtr - 1) == '/')
422 0 : ||
423 0 : (pathPtr - path > APPLE_DOUBLE_PREFIX_LEN
424 0 : &&
425 0 : *(pathPtr - APPLE_DOUBLE_PREFIX_LEN - 1) == '/'
426 0 : &&
427 0 : is_apple_double(pathPtr - APPLE_DOUBLE_PREFIX_LEN))
428 : )
429 : )
430 : {
431 : /* Insert client suffix into path. */
432 0 : (*newPath)[pathPtr - path + CREATING_DIRNAME_LEN] = '\0';
433 0 : DEBUG(MH_INFO_DEBUG, ("newPath #2 %s\n", *newPath));
434 :
435 0 : if ((status = alloc_append_client_suffix(handle, newPath)))
436 : {
437 0 : goto out;
438 : }
439 :
440 0 : DEBUG(MH_INFO_DEBUG, ("newPath #3 %s\n", *newPath));
441 0 : *newPath = talloc_strdup_append(*newPath,
442 0 : pathPtr + CREATING_DIRNAME_LEN);
443 0 : if (*newPath == NULL)
444 : {
445 0 : DEBUG(MH_ERR_DEBUG, ("alloc_get_client_path "
446 : "ENOMEM #2\n"));
447 0 : errno = ENOMEM;
448 0 : status = -1;
449 0 : goto out;
450 : }
451 0 : DEBUG(MH_INFO_DEBUG, ("newPath #4 %s\n", *newPath));
452 : }
453 :
454 : /* replace /MDB_FILENAME or /PMR_FILENAME or /._MDB_FILENAME
455 : * or /._PMR_FILENAME at newPath end with suffixed name.
456 : */
457 0 : intermPathLen = strlen(*newPath);
458 0 : if (
459 0 : is_avid_database(*newPath, intermPathLen,
460 : MDB_FILENAME, MDB_FILENAME_LEN)
461 0 : ||
462 0 : is_avid_database(*newPath, intermPathLen,
463 : PMR_FILENAME, PMR_FILENAME_LEN)
464 : )
465 : {
466 0 : DEBUG(MH_INFO_DEBUG, ("newPath #5 %s\n", *newPath));
467 0 : if ((status = alloc_append_client_suffix(handle, newPath)))
468 : {
469 0 : goto out;
470 : }
471 0 : DEBUG(MH_INFO_DEBUG, ("newPath #6 %s\n", *newPath));
472 : }
473 0 : out:
474 : /* newPath must be freed in caller. */
475 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with *newPath '%s'\n", *newPath));
476 0 : return status;
477 : }
478 :
479 : /*
480 : * Success: return 0
481 : * Failure: set errno, return -1
482 : */
483 0 : 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)
487 : {
488 0 : int status = 0;
489 :
490 0 : DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
491 : smb_fname->base_name));
492 :
493 0 : *clientFname = cp_smb_filename(ctx, smb_fname);
494 0 : if ((*clientFname) == NULL) {
495 0 : DEBUG(MH_ERR_DEBUG, ("alloc_get_client_smb_fname "
496 : "NTERR\n"));
497 0 : errno = ENOMEM;
498 0 : status = -1;
499 0 : goto err;
500 : }
501 0 : if ((status = alloc_get_client_path(handle, ctx,
502 0 : smb_fname->base_name,
503 0 : &(*clientFname)->base_name)))
504 : {
505 0 : goto err;
506 : }
507 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with (*clientFname)->base_name "
508 : "'%s'\n", (*clientFname)->base_name));
509 0 : err:
510 0 : return status;
511 : }
512 :
513 :
514 : /*
515 : * Success: return 0
516 : * Failure: set errno, return -1
517 : */
518 0 : 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)
522 : {
523 0 : int status = 0;
524 :
525 0 : DEBUG(MH_INFO_DEBUG, ("Entering with avid_db_filename '%s'\n",
526 : avid_db_filename));
527 :
528 0 : if ((*path = talloc_strdup(ctx, avid_db_filename)) == NULL)
529 : {
530 0 : DEBUG(MH_ERR_DEBUG, ("alloc_set_client_dirinfo_path "
531 : "ENOMEM\n"));
532 0 : errno = ENOMEM;
533 0 : status = -1;
534 0 : goto err;
535 : }
536 0 : if ((status = alloc_append_client_suffix(handle, path)))
537 : {
538 0 : goto err;
539 : }
540 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with *path '%s'\n", *path));
541 0 : err:
542 0 : return status;
543 : }
544 :
545 : /*
546 : * Replace mtime on clientFname with mtime from client-suffixed
547 : * equivalent, if it exists.
548 : *
549 : * Success: return 0
550 : * Failure: set errno, return -1
551 : */
552 0 : 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))
556 : {
557 0 : int status = 0;
558 : char *statPath;
559 : SMB_STRUCT_STAT fakeStat;
560 : int copy_len;
561 :
562 0 : 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))));
566 :
567 0 : if (
568 0 : depth_from_media_dir(AVID_MXF_DIRNAME,
569 : AVID_MXF_DIRNAME_LEN,
570 0 : (*clientFname)->base_name)
571 : != 1
572 0 : &&
573 0 : depth_from_media_dir(OMFI_MEDIAFILES_DIRNAME,
574 : OMFI_MEDIAFILES_DIRNAME_LEN,
575 0 : (*clientFname)->base_name)
576 : != 0
577 : )
578 : {
579 0 : goto out;
580 : }
581 :
582 0 : copy_len = strlen((*clientFname)->base_name);
583 :
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.
587 : */
588 0 : if ((*clientFname)->base_name[copy_len - 1] == '.' &&
589 0 : (*clientFname)->base_name[copy_len - 2] == '/')
590 : {
591 0 : copy_len -= 2;
592 : }
593 :
594 0 : if (((statPath = talloc_strndup(ctx,
595 0 : (*clientFname)->base_name, copy_len)) == NULL))
596 : {
597 0 : errno = ENOMEM;
598 0 : status = -1;
599 0 : goto err;
600 : }
601 0 : if ((status = alloc_append_client_suffix(handle, &statPath)))
602 : {
603 0 : goto err;
604 : }
605 :
606 0 : DEBUG(MH_INFO_DEBUG, ("Fake stat'ing '%s'\n", statPath));
607 0 : if (statFn(statPath, &fakeStat,
608 0 : lp_fake_directory_create_times(SNUM(handle->conn))))
609 : {
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.
614 : */
615 0 : goto err;
616 : }
617 :
618 0 : DEBUG(MH_INFO_DEBUG, ("Setting fake mtime from '%s'\n", statPath));
619 0 : (*clientFname)->st.st_ex_mtime = fakeStat.st_ex_mtime;
620 0 : err:
621 0 : TALLOC_FREE(statPath);
622 0 : out:
623 0 : 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 0 : return status;
628 : }
629 :
630 : /*
631 : * Success: return 0
632 : * Failure: set errno, return -1
633 : */
634 0 : static int mh_statvfs(struct vfs_handle_struct *handle,
635 : const struct smb_filename *smb_fname,
636 : struct vfs_statvfs_struct *statbuf)
637 : {
638 : int status;
639 0 : struct smb_filename *clientFname = NULL;
640 :
641 0 : DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n",
642 : smb_fname->base_name));
643 :
644 0 : if (!is_in_media_files(smb_fname->base_name))
645 : {
646 0 : status = SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
647 0 : goto out;
648 : }
649 :
650 0 : status = alloc_get_client_smb_fname(handle,
651 : talloc_tos(),
652 : smb_fname,
653 : &clientFname);
654 0 : if (status != 0) {
655 0 : goto err;
656 : }
657 :
658 0 : status = SMB_VFS_NEXT_STATVFS(handle, clientFname, statbuf);
659 0 : err:
660 0 : TALLOC_FREE(clientFname);
661 0 : out:
662 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n",
663 : smb_fname->base_name));
664 0 : return status;
665 : }
666 :
667 0 : static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
668 : const char *fname,
669 : struct mh_dirinfo_struct **dirInfo)
670 : {
671 0 : int status = 0;
672 : char *clientPath;
673 : TALLOC_CTX *ctx;
674 :
675 0 : DEBUG(MH_INFO_DEBUG, ("Entering with fname '%s'\n", fname));
676 :
677 0 : *dirInfo = talloc(NULL, struct mh_dirinfo_struct);
678 0 : if (*dirInfo == NULL)
679 : {
680 0 : goto err;
681 : }
682 :
683 0 : (*dirInfo)->dirpath = talloc_strdup(*dirInfo, fname);
684 0 : if ((*dirInfo)->dirpath == NULL)
685 : {
686 0 : goto err;
687 : }
688 :
689 0 : if (!is_in_media_files(fname))
690 : {
691 0 : (*dirInfo)->clientPath = NULL;
692 0 : (*dirInfo)->clientMDBFilename = NULL;
693 0 : (*dirInfo)->clientPMRFilename = NULL;
694 0 : (*dirInfo)->clientCreatingDirname = NULL;
695 0 : (*dirInfo)->isInMediaFiles = False;
696 0 : goto out;
697 : }
698 :
699 0 : (*dirInfo)->isInMediaFiles = True;
700 :
701 0 : if (alloc_set_client_dirinfo_path(handle,
702 : *dirInfo,
703 0 : &((*dirInfo)->clientMDBFilename),
704 : MDB_FILENAME))
705 : {
706 0 : goto err;
707 : }
708 :
709 0 : if (alloc_set_client_dirinfo_path(handle,
710 : *dirInfo,
711 0 : &((*dirInfo)->clientPMRFilename),
712 : PMR_FILENAME))
713 : {
714 0 : goto err;
715 : }
716 :
717 0 : if (alloc_set_client_dirinfo_path(handle,
718 : *dirInfo,
719 0 : &((*dirInfo)->clientCreatingDirname),
720 : CREATING_DIRNAME))
721 : {
722 0 : goto err;
723 : }
724 :
725 0 : clientPath = NULL;
726 0 : ctx = talloc_tos();
727 :
728 0 : if (alloc_get_client_path(handle, ctx,
729 : fname,
730 : &clientPath))
731 : {
732 0 : goto err;
733 : }
734 :
735 0 : (*dirInfo)->clientPath = talloc_strdup(*dirInfo, clientPath);
736 0 : if ((*dirInfo)->clientPath == NULL)
737 : {
738 0 : goto err;
739 : }
740 :
741 0 : TALLOC_FREE(clientPath);
742 :
743 0 : out:
744 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with (*dirInfo)->dirpath '%s', "
745 : "(*dirInfo)->clientPath '%s'\n",
746 : (*dirInfo)->dirpath,
747 : (*dirInfo)->clientPath));
748 0 : return status;
749 :
750 0 : err:
751 0 : DEBUG(MH_ERR_DEBUG, ("Failing with fname '%s'\n", fname));
752 0 : TALLOC_FREE(*dirInfo);
753 0 : status = -1;
754 0 : errno = ENOMEM;
755 0 : return status;
756 : }
757 :
758 0 : static DIR *mh_fdopendir(vfs_handle_struct *handle,
759 : files_struct *fsp,
760 : const char *mask,
761 : uint32_t attr)
762 : {
763 0 : struct mh_dirinfo_struct *dirInfo = NULL;
764 : DIR *dirstream;
765 :
766 0 : DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name '%s'\n",
767 : fsp->fsp_name->base_name));
768 :
769 0 : dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
770 0 : if (!dirstream)
771 : {
772 0 : goto err;
773 : }
774 :
775 0 : if (alloc_set_client_dirinfo(handle, fsp->fsp_name->base_name,
776 : &dirInfo))
777 : {
778 0 : goto err;
779 : }
780 :
781 0 : dirInfo->dirstream = dirstream;
782 :
783 0 : if (! dirInfo->isInMediaFiles) {
784 0 : goto out;
785 : }
786 :
787 0 : if (set_fake_mtime(handle, fsp, &(fsp->fsp_name), sys_stat))
788 : {
789 0 : goto err;
790 : }
791 :
792 0 : out:
793 0 : 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 0 : return (DIR *) dirInfo;
801 0 : err:
802 : /* Failure is freed here. */
803 0 : DEBUG(MH_ERR_DEBUG, ("Failing with fsp->fsp_name->base_name '%s'\n",
804 : fsp->fsp_name->base_name));
805 0 : TALLOC_FREE(dirInfo);
806 0 : return NULL;
807 : }
808 :
809 : /*
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.
815 : *
816 : * Success: return dirent
817 : * End of data: return NULL
818 : * Failure: set errno, return NULL
819 : */
820 0 : static struct dirent *mh_readdir(vfs_handle_struct *handle,
821 : struct files_struct *dirfsp,
822 : DIR *dirp,
823 : SMB_STRUCT_STAT *sbuf)
824 : {
825 0 : mh_dirinfo_struct* dirInfo = (mh_dirinfo_struct*)dirp;
826 0 : struct dirent *d = NULL;
827 : int skip;
828 :
829 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_readdir\n"));
830 :
831 0 : DEBUG(MH_INFO_DEBUG, ("dirInfo->dirpath '%s', "
832 : "dirInfo->clientPath '%s', "
833 : "dirInfo->isInMediaFiles '%s', "
834 : "dirInfo->clientMDBFilename '%s', "
835 : "dirInfo->clientPMRFilename '%s', "
836 : "dirInfo->clientCreatingDirname '%s'\n",
837 : dirInfo->dirpath,
838 : dirInfo->clientPath,
839 : dirInfo->isInMediaFiles ? "True" : "False",
840 : dirInfo->clientMDBFilename,
841 : dirInfo->clientPMRFilename,
842 : dirInfo->clientCreatingDirname));
843 :
844 0 : if (! dirInfo->isInMediaFiles)
845 : {
846 0 : d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream, sbuf);
847 0 : goto out;
848 : }
849 :
850 : do
851 : {
852 : const char* dname;
853 : bool isAppleDouble;
854 :
855 0 : skip = False;
856 0 : d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream, sbuf);
857 :
858 0 : if (d == NULL)
859 : {
860 0 : break;
861 : }
862 :
863 : /* ignore apple double prefix for logic below */
864 0 : if (is_apple_double(d->d_name))
865 : {
866 0 : dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
867 0 : isAppleDouble = True;
868 : }
869 : else
870 : {
871 0 : dname = d->d_name;
872 0 : isAppleDouble = False;
873 : }
874 :
875 : /* skip Avid-special files with no client suffix */
876 0 : if (
877 0 : strcmp(dname, MDB_FILENAME) == 0
878 0 : ||
879 0 : strcmp(dname, PMR_FILENAME) == 0
880 0 : ||
881 0 : strcmp(dname, CREATING_DIRNAME) == 0
882 : )
883 : {
884 0 : skip = True;
885 : }
886 : /* chop client suffix off this client's suffixed files */
887 0 : else if (strcmp(dname, dirInfo->clientMDBFilename) == 0)
888 : {
889 0 : if (isAppleDouble)
890 : {
891 : d->d_name[MDB_FILENAME_LEN
892 0 : + APPLE_DOUBLE_PREFIX_LEN] = '\0';
893 : }
894 : else
895 : {
896 0 : d->d_name[MDB_FILENAME_LEN] = '\0';
897 : }
898 : }
899 0 : else if (strcmp(dname, dirInfo->clientPMRFilename) == 0)
900 : {
901 0 : if (isAppleDouble)
902 : {
903 : d->d_name[PMR_FILENAME_LEN
904 0 : + APPLE_DOUBLE_PREFIX_LEN] = '\0';
905 : }
906 : else
907 : {
908 0 : d->d_name[PMR_FILENAME_LEN] = '\0';
909 : }
910 : }
911 0 : else if (strcmp(dname, dirInfo->clientCreatingDirname)
912 : == 0)
913 : {
914 0 : if (isAppleDouble)
915 : {
916 : d->d_name[CREATING_DIRNAME_LEN
917 0 : + APPLE_DOUBLE_PREFIX_LEN] = '\0';
918 : }
919 : else
920 : {
921 0 : d->d_name[CREATING_DIRNAME_LEN] = '\0';
922 : }
923 : }
924 : /*
925 : * Anything that starts as an Avid-special file
926 : * that's made it this far should be skipped. This
927 : * is different from the original behaviour, which
928 : * only skipped other client's suffixed files.
929 : */
930 0 : else if (
931 0 : strncmp(MDB_FILENAME, dname,
932 : MDB_FILENAME_LEN) == 0
933 0 : ||
934 0 : strncmp(PMR_FILENAME, dname,
935 : PMR_FILENAME_LEN) == 0
936 0 : ||
937 0 : strncmp(CREATING_DIRNAME, dname,
938 : CREATING_DIRNAME_LEN) == 0
939 : )
940 : {
941 0 : skip = True;
942 : }
943 : }
944 0 : while (skip);
945 :
946 0 : out:
947 0 : DEBUG(MH_INFO_DEBUG, ("Leaving mh_readdir\n"));
948 0 : return d;
949 : }
950 :
951 : /*
952 : * Success: no success result defined.
953 : * Failure: no failure result defined.
954 : */
955 0 : static void mh_seekdir(vfs_handle_struct *handle,
956 : DIR *dirp,
957 : long offset)
958 : {
959 0 : DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_seekdir\n"));
960 0 : SMB_VFS_NEXT_SEEKDIR(handle,
961 : ((mh_dirinfo_struct*)dirp)->dirstream, offset);
962 0 : }
963 :
964 : /*
965 : * Success: return long
966 : * Failure: no failure result defined.
967 : */
968 0 : static long mh_telldir(vfs_handle_struct *handle,
969 : DIR *dirp)
970 : {
971 0 : DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_telldir\n"));
972 0 : return SMB_VFS_NEXT_TELLDIR(handle,
973 : ((mh_dirinfo_struct*)dirp)->dirstream);
974 : }
975 :
976 : /*
977 : * Success: no success result defined.
978 : * Failure: no failure result defined.
979 : */
980 0 : static void mh_rewinddir(vfs_handle_struct *handle,
981 : DIR *dirp)
982 : {
983 0 : DEBUG(MH_INFO_DEBUG, ("Entering and leaving mh_rewinddir\n"));
984 0 : SMB_VFS_NEXT_REWINDDIR(handle,
985 : ((mh_dirinfo_struct*)dirp)->dirstream);
986 0 : }
987 :
988 : /*
989 : * Success: return 0
990 : * Failure: set errno, return -1
991 : */
992 0 : static int mh_mkdirat(vfs_handle_struct *handle,
993 : struct files_struct *dirfsp,
994 : const struct smb_filename *smb_fname,
995 : mode_t mode)
996 : {
997 : int status;
998 0 : struct smb_filename *clientFname = NULL;
999 0 : const char *path = smb_fname->base_name;
1000 0 : struct smb_filename *full_fname = NULL;
1001 :
1002 0 : DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n", path));
1003 :
1004 0 : if (!is_in_media_files(path)) {
1005 0 : status = SMB_VFS_NEXT_MKDIRAT(handle,
1006 : dirfsp,
1007 : smb_fname,
1008 : mode);
1009 0 : goto out;
1010 : }
1011 :
1012 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1013 : dirfsp,
1014 : smb_fname);
1015 0 : if (full_fname == NULL) {
1016 0 : return -1;
1017 : }
1018 :
1019 0 : status = alloc_get_client_smb_fname(handle,
1020 : talloc_tos(),
1021 : full_fname,
1022 : &clientFname);
1023 0 : if (status != 0) {
1024 0 : goto err;
1025 : }
1026 :
1027 0 : status = SMB_VFS_NEXT_MKDIRAT(handle,
1028 : handle->conn->cwd_fsp,
1029 : clientFname,
1030 : mode);
1031 0 : err:
1032 0 : TALLOC_FREE(full_fname);
1033 0 : TALLOC_FREE(clientFname);
1034 0 : out:
1035 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n", path));
1036 0 : return status;
1037 : }
1038 :
1039 : /*
1040 : * Success: return 0
1041 : * Failure: set errno, return -1
1042 : */
1043 0 : static int mh_closedir(vfs_handle_struct *handle,
1044 : DIR *dirp)
1045 : {
1046 0 : DIR *realdirp = ((mh_dirinfo_struct*)dirp)->dirstream;
1047 :
1048 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_closedir\n"));
1049 : // Will this talloc_free destroy realdirp?
1050 0 : TALLOC_FREE(dirp);
1051 :
1052 0 : DEBUG(MH_INFO_DEBUG, ("Leaving mh_closedir\n"));
1053 0 : return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
1054 : }
1055 :
1056 : /*
1057 : * Success: return non-negative file descriptor
1058 : * Failure: set errno, return -1
1059 : */
1060 0 : static int mh_openat(struct vfs_handle_struct *handle,
1061 : const struct files_struct *dirfsp,
1062 : const struct smb_filename *smb_fname,
1063 : files_struct *fsp,
1064 : const struct vfs_open_how *how)
1065 : {
1066 : int ret;
1067 : struct smb_filename *clientFname;
1068 : TALLOC_CTX *ctx;
1069 :
1070 0 : DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1071 : smb_fname->base_name));
1072 :
1073 0 : if (!is_in_media_files(smb_fname->base_name)) {
1074 0 : ret = SMB_VFS_NEXT_OPENAT(handle,
1075 : dirfsp,
1076 : smb_fname,
1077 : fsp,
1078 : how);
1079 0 : goto out;
1080 : }
1081 :
1082 0 : clientFname = NULL;
1083 0 : ctx = talloc_tos();
1084 :
1085 0 : if (alloc_get_client_smb_fname(handle, ctx, smb_fname, &clientFname)) {
1086 0 : ret = -1;
1087 0 : goto err;
1088 : }
1089 :
1090 : /*
1091 : * What about fsp->fsp_name? We also have to get correct stat info into
1092 : * fsp and smb_fname for DB files, don't we?
1093 : */
1094 :
1095 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s' "
1096 : "smb_fname->st.st_ex_mtime %s"
1097 : " fsp->fsp_name->st.st_ex_mtime %s",
1098 : smb_fname->base_name,
1099 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1100 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
1101 :
1102 0 : ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, clientFname, fsp, how);
1103 0 : err:
1104 0 : TALLOC_FREE(clientFname);
1105 0 : out:
1106 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'\n",
1107 : smb_fname->base_name));
1108 0 : return ret;
1109 : }
1110 :
1111 : /*
1112 : * Success: return non-negative file descriptor
1113 : * Failure: set errno, return -1
1114 : */
1115 0 : static NTSTATUS mh_create_file(vfs_handle_struct *handle,
1116 : struct smb_request *req,
1117 : struct files_struct *dirfsp,
1118 : struct smb_filename *smb_fname,
1119 : uint32_t access_mask,
1120 : uint32_t share_access,
1121 : uint32_t create_disposition,
1122 : uint32_t create_options,
1123 : uint32_t file_attributes,
1124 : uint32_t oplock_request,
1125 : const struct smb2_lease *lease,
1126 : uint64_t allocation_size,
1127 : uint32_t private_flags,
1128 : struct security_descriptor *sd,
1129 : struct ea_list *ea_list,
1130 : files_struct **result_fsp,
1131 : int *pinfo,
1132 : const struct smb2_create_blobs *in_context_blobs,
1133 : struct smb2_create_blobs *out_context_blobs)
1134 : {
1135 : NTSTATUS status;
1136 : struct smb_filename *clientFname;
1137 : TALLOC_CTX *ctx;
1138 :
1139 :
1140 0 : DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1141 : smb_fname->base_name));
1142 0 : if (!is_in_media_files(smb_fname->base_name))
1143 : {
1144 0 : status = SMB_VFS_NEXT_CREATE_FILE(
1145 : handle,
1146 : req,
1147 : dirfsp,
1148 : smb_fname,
1149 : access_mask,
1150 : share_access,
1151 : create_disposition,
1152 : create_options,
1153 : file_attributes,
1154 : oplock_request,
1155 : lease,
1156 : allocation_size,
1157 : private_flags,
1158 : sd,
1159 : ea_list,
1160 : result_fsp,
1161 : pinfo,
1162 : in_context_blobs,
1163 : out_context_blobs);
1164 0 : goto out;
1165 : }
1166 :
1167 0 : clientFname = NULL;
1168 0 : ctx = talloc_tos();
1169 :
1170 0 : if (alloc_get_client_smb_fname(handle, ctx,
1171 : smb_fname,
1172 : &clientFname))
1173 : {
1174 0 : status = map_nt_error_from_unix(errno);
1175 0 : goto err;
1176 : }
1177 :
1178 : /* This only creates files, so we don't have to worry about
1179 : * our fake directory stat'ing here.
1180 : */
1181 : // But we still need to route stat calls for DB files
1182 : // properly, right?
1183 0 : status = SMB_VFS_NEXT_CREATE_FILE(
1184 : handle,
1185 : req,
1186 : dirfsp,
1187 : clientFname,
1188 : access_mask,
1189 : share_access,
1190 : create_disposition,
1191 : create_options,
1192 : file_attributes,
1193 : oplock_request,
1194 : lease,
1195 : allocation_size,
1196 : private_flags,
1197 : sd,
1198 : ea_list,
1199 : result_fsp,
1200 : pinfo,
1201 : in_context_blobs,
1202 : out_context_blobs);
1203 0 : err:
1204 0 : TALLOC_FREE(clientFname);
1205 0 : out:
1206 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->base_name '%s'"
1207 : "smb_fname->st.st_ex_mtime %s"
1208 : " fsp->fsp_name->st.st_ex_mtime %s",
1209 : smb_fname->base_name,
1210 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
1211 : (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
1212 : ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
1213 : "No fsp time\n"));
1214 0 : return status;
1215 : }
1216 :
1217 : /*
1218 : * Success: return 0
1219 : * Failure: set errno, return -1
1220 : */
1221 0 : static int mh_renameat(vfs_handle_struct *handle,
1222 : files_struct *srcfsp,
1223 : const struct smb_filename *smb_fname_src,
1224 : files_struct *dstfsp,
1225 : const struct smb_filename *smb_fname_dst)
1226 : {
1227 0 : int status = -1;
1228 0 : struct smb_filename *full_fname_src = NULL;
1229 0 : struct smb_filename *full_fname_dst = NULL;
1230 0 : struct smb_filename *srcClientFname = NULL;
1231 0 : struct smb_filename *dstClientFname = NULL;
1232 :
1233 0 : DEBUG(MH_INFO_DEBUG, ("Entering with "
1234 : "smb_fname_src->base_name '%s', "
1235 : "smb_fname_dst->base_name '%s'\n",
1236 : smb_fname_src->base_name,
1237 : smb_fname_dst->base_name));
1238 :
1239 0 : if (!is_in_media_files(smb_fname_src->base_name)
1240 0 : &&
1241 0 : !is_in_media_files(smb_fname_dst->base_name))
1242 : {
1243 0 : status = SMB_VFS_NEXT_RENAMEAT(handle,
1244 : srcfsp,
1245 : smb_fname_src,
1246 : dstfsp,
1247 : smb_fname_dst);
1248 0 : goto out;
1249 : }
1250 :
1251 0 : full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
1252 : srcfsp,
1253 : smb_fname_src);
1254 0 : if (full_fname_src == NULL) {
1255 0 : errno = ENOMEM;
1256 0 : goto out;
1257 : }
1258 0 : full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
1259 : dstfsp,
1260 : smb_fname_dst);
1261 0 : if (full_fname_dst == NULL) {
1262 0 : errno = ENOMEM;
1263 0 : goto out;
1264 : }
1265 :
1266 0 : if ((status = alloc_get_client_smb_fname(handle,
1267 : talloc_tos(),
1268 : full_fname_src,
1269 : &srcClientFname)))
1270 : {
1271 0 : goto err;
1272 : }
1273 :
1274 0 : if ((status = alloc_get_client_smb_fname(handle,
1275 : talloc_tos(),
1276 : full_fname_dst,
1277 : &dstClientFname)))
1278 : {
1279 0 : goto err;
1280 : }
1281 :
1282 0 : status = SMB_VFS_NEXT_RENAMEAT(handle,
1283 : srcfsp->conn->cwd_fsp,
1284 : srcClientFname,
1285 : dstfsp->conn->cwd_fsp,
1286 : dstClientFname);
1287 0 : err:
1288 0 : TALLOC_FREE(full_fname_src);
1289 0 : TALLOC_FREE(full_fname_dst);
1290 0 : TALLOC_FREE(dstClientFname);
1291 0 : TALLOC_FREE(srcClientFname);
1292 0 : out:
1293 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname_src->base_name '%s',"
1294 : " smb_fname_dst->base_name '%s'\n",
1295 : smb_fname_src->base_name,
1296 : smb_fname_dst->base_name));
1297 0 : return status;
1298 : }
1299 :
1300 : /*
1301 : * Success: return 0
1302 : * Failure: set errno, return -1
1303 : */
1304 0 : static int mh_stat(vfs_handle_struct *handle,
1305 : struct smb_filename *smb_fname)
1306 : {
1307 0 : int status = 0;
1308 : struct smb_filename *clientFname;
1309 : TALLOC_CTX *ctx;
1310 :
1311 :
1312 0 : DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1313 : smb_fname->base_name));
1314 :
1315 0 : if (!is_in_media_files(smb_fname->base_name))
1316 : {
1317 0 : status = SMB_VFS_NEXT_STAT(handle, smb_fname);
1318 0 : goto out;
1319 : }
1320 :
1321 0 : clientFname = NULL;
1322 0 : ctx = talloc_tos();
1323 :
1324 0 : if ((status = alloc_get_client_smb_fname(handle, ctx,
1325 : smb_fname,
1326 : &clientFname)))
1327 : {
1328 0 : goto err;
1329 : }
1330 0 : DEBUG(MH_INFO_DEBUG, ("Stat'ing clientFname->base_name '%s'\n",
1331 : clientFname->base_name));
1332 0 : if ((status = SMB_VFS_NEXT_STAT(handle, clientFname)))
1333 : {
1334 0 : goto err;
1335 : }
1336 0 : if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_stat)))
1337 : {
1338 0 : goto err;
1339 : }
1340 :
1341 : /* Unlike functions with const smb_filename, we have to
1342 : * modify smb_fname itself to pass our info back up.
1343 : */
1344 0 : DEBUG(MH_INFO_DEBUG, ("Setting smb_fname '%s' stat "
1345 : "from clientFname '%s'\n",
1346 : smb_fname->base_name,
1347 : clientFname->base_name));
1348 0 : smb_fname->st = clientFname->st;
1349 0 : err:
1350 0 : TALLOC_FREE(clientFname);
1351 0 : out:
1352 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1353 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1354 0 : return status;
1355 : }
1356 :
1357 : /*
1358 : * Success: return 0
1359 : * Failure: set errno, return -1
1360 : */
1361 0 : static int mh_lstat(vfs_handle_struct *handle,
1362 : struct smb_filename *smb_fname)
1363 : {
1364 0 : int status = 0;
1365 : struct smb_filename *clientFname;
1366 : TALLOC_CTX *ctx;
1367 :
1368 0 : DEBUG(MH_INFO_DEBUG, ("Entering with smb_fname->base_name '%s'\n",
1369 : smb_fname->base_name));
1370 :
1371 0 : if (!is_in_media_files(smb_fname->base_name))
1372 : {
1373 0 : status = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1374 0 : goto out;
1375 : }
1376 :
1377 0 : clientFname = NULL;
1378 0 : ctx = talloc_tos();
1379 :
1380 0 : if ((status = alloc_get_client_smb_fname(handle, ctx,
1381 : smb_fname,
1382 : &clientFname)))
1383 : {
1384 0 : goto err;
1385 : }
1386 0 : if ((status = SMB_VFS_NEXT_LSTAT(handle, clientFname)))
1387 : {
1388 0 : goto err;
1389 : }
1390 :
1391 0 : if ((status = set_fake_mtime(handle, ctx, &clientFname, sys_lstat)))
1392 : {
1393 0 : goto err;
1394 : }
1395 : /* Unlike functions with const smb_filename, we have to
1396 : * modify smb_fname itself to pass our info back up.
1397 : */
1398 0 : smb_fname->st = clientFname->st;
1399 0 : err:
1400 0 : TALLOC_FREE(clientFname);
1401 0 : out:
1402 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with smb_fname->st.st_ex_mtime %s",
1403 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1404 0 : return status;
1405 : }
1406 :
1407 : /*
1408 : * Success: return 0
1409 : * Failure: set errno, return -1
1410 : */
1411 0 : static int mh_fstat(vfs_handle_struct *handle,
1412 : files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1413 : {
1414 0 : int status = 0;
1415 :
1416 0 : DEBUG(MH_INFO_DEBUG, ("Entering with fsp->fsp_name->base_name "
1417 : "'%s'\n", fsp_str_dbg(fsp)));
1418 :
1419 0 : if ((status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf)))
1420 : {
1421 0 : goto out;
1422 : }
1423 :
1424 0 : if (fsp->fsp_name == NULL
1425 0 : || !is_in_media_files(fsp->fsp_name->base_name))
1426 : {
1427 : goto out;
1428 : }
1429 :
1430 0 : if ((status = mh_stat(handle, fsp->fsp_name)))
1431 : {
1432 0 : goto out;
1433 : }
1434 :
1435 0 : *sbuf = fsp->fsp_name->st;
1436 0 : out:
1437 0 : DEBUG(MH_INFO_DEBUG, ("Leaving with fsp->fsp_name->st.st_ex_mtime "
1438 : "%s",
1439 : fsp->fsp_name != NULL ?
1440 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) :
1441 : "0"));
1442 0 : return status;
1443 : }
1444 :
1445 : /*
1446 : * Success: return 0
1447 : * Failure: set errno, return -1
1448 : */
1449 0 : static int mh_unlinkat(vfs_handle_struct *handle,
1450 : struct files_struct *dirfsp,
1451 : const struct smb_filename *smb_fname,
1452 : int flags)
1453 : {
1454 : int status;
1455 0 : struct smb_filename *full_fname = NULL;
1456 : struct smb_filename *clientFname;
1457 : TALLOC_CTX *ctx;
1458 :
1459 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_unlinkat\n"));
1460 0 : if (!is_in_media_files(smb_fname->base_name)) {
1461 0 : status = SMB_VFS_NEXT_UNLINKAT(handle,
1462 : dirfsp,
1463 : smb_fname,
1464 : flags);
1465 0 : goto out;
1466 : }
1467 :
1468 0 : clientFname = NULL;
1469 0 : ctx = talloc_tos();
1470 :
1471 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1472 : dirfsp,
1473 : smb_fname);
1474 0 : if (full_fname == NULL) {
1475 0 : return -1;
1476 : }
1477 :
1478 0 : if ((status = alloc_get_client_smb_fname(handle, ctx,
1479 : full_fname,
1480 : &clientFname))) {
1481 0 : goto err;
1482 : }
1483 :
1484 0 : status = SMB_VFS_NEXT_UNLINKAT(handle,
1485 : dirfsp->conn->cwd_fsp,
1486 : clientFname,
1487 : flags);
1488 0 : err:
1489 0 : TALLOC_FREE(full_fname);
1490 0 : TALLOC_FREE(clientFname);
1491 0 : out:
1492 0 : return status;
1493 : }
1494 :
1495 : /*
1496 : * Success: return 0
1497 : * Failure: set errno, return -1
1498 : */
1499 0 : static int mh_lchown(vfs_handle_struct *handle,
1500 : const struct smb_filename *smb_fname,
1501 : uid_t uid,
1502 : gid_t gid)
1503 : {
1504 : int status;
1505 0 : struct smb_filename *clientFname = NULL;
1506 :
1507 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n"));
1508 0 : if (!is_in_media_files(smb_fname->base_name))
1509 : {
1510 0 : status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1511 0 : goto out;
1512 : }
1513 :
1514 0 : status = alloc_get_client_smb_fname(handle,
1515 : talloc_tos(),
1516 : smb_fname,
1517 : &clientFname);
1518 0 : if (status != 0) {
1519 0 : goto err;
1520 : }
1521 :
1522 0 : status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid);
1523 0 : err:
1524 0 : TALLOC_FREE(clientFname);
1525 0 : out:
1526 0 : return status;
1527 : }
1528 :
1529 : /*
1530 : * Success: return 0
1531 : * Failure: set errno, return -1
1532 : */
1533 0 : static int mh_chdir(vfs_handle_struct *handle,
1534 : const struct smb_filename *smb_fname)
1535 : {
1536 : int status;
1537 0 : struct smb_filename *clientFname = NULL;
1538 :
1539 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n"));
1540 0 : if (!is_in_media_files(smb_fname->base_name)) {
1541 0 : status = SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1542 0 : goto out;
1543 : }
1544 :
1545 0 : status = alloc_get_client_smb_fname(handle,
1546 : talloc_tos(),
1547 : smb_fname,
1548 : &clientFname);
1549 0 : if (status != 0) {
1550 0 : goto err;
1551 : }
1552 :
1553 0 : status = SMB_VFS_NEXT_CHDIR(handle, clientFname);
1554 0 : err:
1555 0 : TALLOC_FREE(clientFname);
1556 0 : out:
1557 0 : return status;
1558 : }
1559 :
1560 : /*
1561 : * Success: return 0
1562 : * Failure: set errno, return -1
1563 : */
1564 :
1565 0 : static int mh_symlinkat(vfs_handle_struct *handle,
1566 : const struct smb_filename *link_contents,
1567 : struct files_struct *dirfsp,
1568 : const struct smb_filename *new_smb_fname)
1569 : {
1570 0 : int status = -1;
1571 0 : struct smb_filename *full_fname = NULL;
1572 0 : struct smb_filename *new_link_target = NULL;
1573 0 : struct smb_filename *newclientFname = NULL;
1574 :
1575 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_symlinkat\n"));
1576 :
1577 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1578 : dirfsp,
1579 : new_smb_fname);
1580 0 : if (full_fname == NULL) {
1581 0 : status = -1;
1582 0 : goto err;
1583 : }
1584 :
1585 0 : if (!is_in_media_files(link_contents->base_name) &&
1586 0 : !is_in_media_files(full_fname->base_name)) {
1587 0 : status = SMB_VFS_NEXT_SYMLINKAT(handle,
1588 : link_contents,
1589 : dirfsp,
1590 : new_smb_fname);
1591 0 : goto out;
1592 : }
1593 :
1594 0 : if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1595 : link_contents,
1596 : &new_link_target))) {
1597 0 : goto err;
1598 : }
1599 0 : if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1600 : full_fname,
1601 : &newclientFname))) {
1602 0 : goto err;
1603 : }
1604 :
1605 0 : status = SMB_VFS_NEXT_SYMLINKAT(handle,
1606 : new_link_target,
1607 : handle->conn->cwd_fsp,
1608 : newclientFname);
1609 0 : err:
1610 0 : TALLOC_FREE(new_link_target);
1611 0 : TALLOC_FREE(newclientFname);
1612 0 : out:
1613 0 : TALLOC_FREE(full_fname);
1614 0 : return status;
1615 : }
1616 :
1617 : /*
1618 : * Success: return byte count
1619 : * Failure: set errno, return -1
1620 : */
1621 0 : static int mh_readlinkat(vfs_handle_struct *handle,
1622 : const struct files_struct *dirfsp,
1623 : const struct smb_filename *smb_fname,
1624 : char *buf,
1625 : size_t bufsiz)
1626 : {
1627 : int status;
1628 0 : struct smb_filename *full_fname = NULL;
1629 0 : struct smb_filename *clientFname = NULL;
1630 :
1631 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_readlinkat\n"));
1632 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1633 : dirfsp,
1634 : smb_fname);
1635 0 : if (full_fname == NULL) {
1636 0 : status = -1;
1637 0 : goto err;
1638 : }
1639 :
1640 0 : if (!is_in_media_files(full_fname->base_name)) {
1641 0 : status = SMB_VFS_NEXT_READLINKAT(handle,
1642 : dirfsp,
1643 : smb_fname,
1644 : buf,
1645 : bufsiz);
1646 0 : goto out;
1647 : }
1648 :
1649 0 : if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1650 : full_fname,
1651 : &clientFname))) {
1652 0 : goto err;
1653 : }
1654 :
1655 0 : status = SMB_VFS_NEXT_READLINKAT(handle,
1656 : handle->conn->cwd_fsp,
1657 : clientFname,
1658 : buf,
1659 : bufsiz);
1660 :
1661 0 : err:
1662 0 : TALLOC_FREE(clientFname);
1663 0 : out:
1664 0 : TALLOC_FREE(full_fname);
1665 0 : return status;
1666 : }
1667 :
1668 : /*
1669 : * Success: return 0
1670 : * Failure: set errno, return -1
1671 : */
1672 0 : static int mh_linkat(vfs_handle_struct *handle,
1673 : files_struct *srcfsp,
1674 : const struct smb_filename *old_smb_fname,
1675 : files_struct *dstfsp,
1676 : const struct smb_filename *new_smb_fname,
1677 : int flags)
1678 : {
1679 : int status;
1680 0 : struct smb_filename *old_full_fname = NULL;
1681 0 : struct smb_filename *oldclientFname = NULL;
1682 0 : struct smb_filename *new_full_fname = NULL;
1683 0 : struct smb_filename *newclientFname = NULL;
1684 :
1685 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_linkat\n"));
1686 :
1687 0 : old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1688 : srcfsp,
1689 : old_smb_fname);
1690 0 : if (old_full_fname == NULL) {
1691 0 : status = -1;
1692 0 : goto err;
1693 : }
1694 :
1695 0 : new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1696 : dstfsp,
1697 : new_smb_fname);
1698 0 : if (new_full_fname == NULL) {
1699 0 : status = -1;
1700 0 : goto err;
1701 : }
1702 :
1703 0 : if (!is_in_media_files(old_full_fname->base_name) &&
1704 0 : !is_in_media_files(new_full_fname->base_name)) {
1705 0 : TALLOC_FREE(old_full_fname);
1706 0 : TALLOC_FREE(new_full_fname);
1707 :
1708 0 : status = SMB_VFS_NEXT_LINKAT(handle,
1709 : srcfsp,
1710 : old_smb_fname,
1711 : dstfsp,
1712 : new_smb_fname,
1713 : flags);
1714 0 : goto out;
1715 : }
1716 :
1717 0 : if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1718 : old_full_fname,
1719 : &oldclientFname))) {
1720 0 : goto err;
1721 : }
1722 0 : if ((status = alloc_get_client_smb_fname(handle, talloc_tos(),
1723 : new_full_fname,
1724 : &newclientFname))) {
1725 0 : goto err;
1726 : }
1727 :
1728 0 : status = SMB_VFS_NEXT_LINKAT(handle,
1729 : handle->conn->cwd_fsp,
1730 : oldclientFname,
1731 : handle->conn->cwd_fsp,
1732 : newclientFname,
1733 : flags);
1734 :
1735 0 : err:
1736 0 : TALLOC_FREE(old_full_fname);
1737 0 : TALLOC_FREE(new_full_fname);
1738 0 : TALLOC_FREE(newclientFname);
1739 0 : TALLOC_FREE(oldclientFname);
1740 0 : out:
1741 0 : return status;
1742 : }
1743 :
1744 : /*
1745 : * Success: return 0
1746 : * Failure: set errno, return -1
1747 : */
1748 0 : static int mh_mknodat(vfs_handle_struct *handle,
1749 : files_struct *dirfsp,
1750 : const struct smb_filename *smb_fname,
1751 : mode_t mode,
1752 : SMB_DEV_T dev)
1753 : {
1754 : int status;
1755 0 : struct smb_filename *full_fname = NULL;
1756 0 : struct smb_filename *clientFname = NULL;
1757 : TALLOC_CTX *ctx;
1758 :
1759 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_mknodat\n"));
1760 :
1761 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1762 : dirfsp,
1763 : smb_fname);
1764 0 : if (full_fname == NULL) {
1765 0 : status = -1;
1766 0 : goto err;
1767 : }
1768 :
1769 0 : if (!is_in_media_files(full_fname->base_name)) {
1770 0 : status = SMB_VFS_NEXT_MKNODAT(handle,
1771 : dirfsp,
1772 : smb_fname,
1773 : mode,
1774 : dev);
1775 0 : goto out;
1776 : }
1777 :
1778 0 : ctx = talloc_tos();
1779 :
1780 0 : if ((status = alloc_get_client_smb_fname(handle, ctx,
1781 : full_fname,
1782 : &clientFname))) {
1783 0 : goto err;
1784 : }
1785 :
1786 0 : status = SMB_VFS_NEXT_MKNODAT(handle,
1787 : handle->conn->cwd_fsp,
1788 : clientFname,
1789 : mode,
1790 : dev);
1791 :
1792 0 : err:
1793 0 : TALLOC_FREE(clientFname);
1794 0 : out:
1795 0 : TALLOC_FREE(full_fname);
1796 0 : return status;
1797 : }
1798 :
1799 : /*
1800 : * Success: return path pointer
1801 : * Failure: set errno, return NULL pointer
1802 : */
1803 0 : static struct smb_filename *mh_realpath(vfs_handle_struct *handle,
1804 : TALLOC_CTX *ctx,
1805 : const struct smb_filename *smb_fname)
1806 : {
1807 0 : struct smb_filename *result_fname = NULL;
1808 0 : struct smb_filename *clientFname = NULL;
1809 :
1810 0 : DEBUG(MH_INFO_DEBUG, ("Entering mh_realpath\n"));
1811 0 : if (!is_in_media_files(smb_fname->base_name)) {
1812 0 : return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1813 : }
1814 :
1815 0 : if (alloc_get_client_smb_fname(handle, ctx,
1816 : smb_fname,
1817 : &clientFname) != 0) {
1818 0 : goto err;
1819 : }
1820 :
1821 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, clientFname);
1822 0 : err:
1823 0 : TALLOC_FREE(clientFname);
1824 0 : return result_fname;
1825 : }
1826 :
1827 : /* Ignoring get_real_filename function because the default
1828 : * doesn't do anything.
1829 : */
1830 :
1831 : /*
1832 : * Success: return 0
1833 : * Failure: set errno, return -1
1834 : * In this case, "name" is an attr name.
1835 : */
1836 :
1837 : /* VFS operations structure */
1838 :
1839 : static struct vfs_fn_pointers vfs_mh_fns = {
1840 : /* Disk operations */
1841 :
1842 : .statvfs_fn = mh_statvfs,
1843 :
1844 : /* Directory operations */
1845 :
1846 : .fdopendir_fn = mh_fdopendir,
1847 : .readdir_fn = mh_readdir,
1848 : .seekdir_fn = mh_seekdir,
1849 : .telldir_fn = mh_telldir,
1850 : .rewind_dir_fn = mh_rewinddir,
1851 : .mkdirat_fn = mh_mkdirat,
1852 : .closedir_fn = mh_closedir,
1853 :
1854 : /* File operations */
1855 :
1856 : .openat_fn = mh_openat,
1857 : .create_file_fn = mh_create_file,
1858 : .renameat_fn = mh_renameat,
1859 : .stat_fn = mh_stat,
1860 : .lstat_fn = mh_lstat,
1861 : .fstat_fn = mh_fstat,
1862 : .unlinkat_fn = mh_unlinkat,
1863 : .lchown_fn = mh_lchown,
1864 : .chdir_fn = mh_chdir,
1865 : .symlinkat_fn = mh_symlinkat,
1866 : .readlinkat_fn = mh_readlinkat,
1867 : .linkat_fn = mh_linkat,
1868 : .mknodat_fn = mh_mknodat,
1869 : .realpath_fn = mh_realpath,
1870 :
1871 : /* EA operations. */
1872 : .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1873 : .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1874 :
1875 : /* aio operations */
1876 : };
1877 :
1878 : static_decl_vfs;
1879 26 : NTSTATUS vfs_media_harmony_init(TALLOC_CTX *ctx)
1880 : {
1881 26 : NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1882 : "media_harmony", &vfs_mh_fns);
1883 26 : if (!NT_STATUS_IS_OK(ret))
1884 : {
1885 0 : goto out;
1886 : }
1887 :
1888 26 : vfs_mh_debug_level = debug_add_class("media_harmony");
1889 :
1890 26 : if (vfs_mh_debug_level == -1) {
1891 0 : vfs_mh_debug_level = DBGC_VFS;
1892 0 : DEBUG(1, ("media_harmony_init: Couldn't register custom "
1893 : "debugging class.\n"));
1894 : } else {
1895 26 : DEBUG(3, ("media_harmony_init: Debug class number of "
1896 : "'media_harmony': %d\n",
1897 : vfs_mh_debug_level));
1898 : }
1899 :
1900 26 : out:
1901 26 : return ret;
1902 : }
|