Line data Source code
1 : /*
2 : * Samba VFS module supporting multiple AVID clients sharing media.
3 : *
4 : * Copyright (C) 2005 Philip de Nier <philipn@users.sourceforge.net>
5 : * Copyright (C) 2012 Andrew Klaassen <clawsoon@yahoo.com>
6 : * Copyright (C) 2013 Milos Lukacek
7 : * Copyright (C) 2013 Ralph Boehme <slow@samba.org>
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 : * Unityed Media is a Samba VFS module that allows multiple AVID
27 : * clients to share media.
28 : *
29 : * Add this module to the vfs objects option in your Samba share
30 : * configuration.
31 : * eg.
32 : *
33 : * [avid_win]
34 : * path = /video
35 : * vfs objects = unityed_media
36 : * ...
37 : *
38 : * It is recommended that you separate out Samba shares for Mac
39 : * and Windows clients, and add the following options to the shares
40 : * for Windows clients (NOTE: replace @ with *):
41 : *
42 : * veto files = /.DS_Store/._@/.Trash@/.Spotlight@/.hidden/.hotfiles@/.vol/
43 : * delete veto files = yes
44 : *
45 : * This prevents hidden files from Mac clients interfering with Windows
46 : * clients. If you find any more problem hidden files then add them to
47 : * the list.
48 : *
49 : * Notes:
50 : * This module is designed to work with AVID editing applications that
51 : * look in the Avid MediaFiles or OMFI MediaFiles directory for media.
52 : * It is not designed to work as expected in all circumstances for
53 : * general use.
54 : */
55 :
56 :
57 : #include "includes.h"
58 : #include "system/filesys.h"
59 : #include "smbd/smbd.h"
60 : #include "../smbd/globals.h"
61 : #include "auth.h"
62 : #include "../lib/tsocket/tsocket.h"
63 : #include "lib/util/smb_strtox.h"
64 : #include <libgen.h>
65 : #include "source3/lib/substitute.h"
66 :
67 : #define UM_PARAM_TYPE_NAME "unityed_media"
68 :
69 : static const char *AVID_MXF_DIRNAME = "Avid MediaFiles/MXF";
70 : static const size_t AVID_MXF_DIRNAME_LEN = 19;
71 : static const char *OMFI_MEDIAFILES_DIRNAME = "OMFI MediaFiles";
72 : static const size_t OMFI_MEDIAFILES_DIRNAME_LEN = 15;
73 : static const char *APPLE_DOUBLE_PREFIX = "._";
74 : static const size_t APPLE_DOUBLE_PREFIX_LEN = 2;
75 : static int vfs_um_debug_level = DBGC_VFS;
76 :
77 : enum um_clientid {UM_CLIENTID_NAME, UM_CLIENTID_IP, UM_CLIENTID_HOSTNAME};
78 :
79 : struct um_config_data {
80 : enum um_clientid clientid;
81 : };
82 :
83 : static const struct enum_list um_clientid[] = {
84 : {UM_CLIENTID_NAME, "user"},
85 : {UM_CLIENTID_IP, "ip"},
86 : {UM_CLIENTID_HOSTNAME, "hostname"},
87 : {-1, NULL}
88 : };
89 :
90 : /* supplements the directory list stream */
91 : typedef struct um_dirinfo_struct {
92 : DIR* dirstream;
93 : char *dirpath;
94 : char *clientPath;
95 : bool isInMediaFiles;
96 : char *clientSubDirname;
97 : } um_dirinfo_struct;
98 :
99 : /**
100 : * Returns true and first group of digits in path, false and 0 otherwise
101 : **/
102 0 : static bool get_digit_group(const char *path, uintmax_t *digit)
103 : {
104 0 : const char *p = path;
105 : codepoint_t cp;
106 : size_t size;
107 0 : int error = 0;
108 :
109 0 : DEBUG(10, ("get_digit_group entering with path '%s'\n",
110 : path));
111 :
112 : /*
113 : * Delibiretly initialize to 0 because callers use this result
114 : * even though the string doesn't contain any number and we
115 : * returned false
116 : */
117 0 : *digit = 0;
118 :
119 0 : while (*p) {
120 0 : cp = next_codepoint(p, &size);
121 0 : if (cp == -1) {
122 0 : return false;
123 : }
124 0 : if ((size == 1) && (isdigit(cp))) {
125 0 : *digit = (uintmax_t)smb_strtoul(p,
126 : NULL,
127 : 10,
128 : &error,
129 : SMB_STR_STANDARD);
130 0 : if (error != 0) {
131 0 : return false;
132 : }
133 0 : DEBUG(10, ("num_suffix = '%ju'\n",
134 : *digit));
135 0 : return true;
136 : }
137 0 : p += size;
138 : }
139 :
140 0 : return false;
141 : }
142 :
143 : /* Add "_<remote_name>.<number>" suffix to path or filename.
144 : *
145 : * Success: return 0
146 : * Failure: set errno, path NULL, return -1
147 : */
148 :
149 0 : static int alloc_append_client_suffix(vfs_handle_struct *handle,
150 : char **path)
151 : {
152 0 : int status = 0;
153 : uintmax_t number;
154 : const char *clientid;
155 : struct um_config_data *config;
156 :
157 0 : DEBUG(10, ("Entering with path '%s'\n", *path));
158 :
159 0 : SMB_VFS_HANDLE_GET_DATA(handle, config,
160 : struct um_config_data,
161 : return -1);
162 :
163 0 : (void)get_digit_group(*path, &number);
164 :
165 0 : switch (config->clientid) {
166 :
167 0 : case UM_CLIENTID_IP:
168 0 : clientid = tsocket_address_inet_addr_string(
169 0 : handle->conn->sconn->remote_address, talloc_tos());
170 0 : if (clientid == NULL) {
171 0 : errno = ENOMEM;
172 0 : status = -1;
173 0 : goto err;
174 : }
175 0 : break;
176 :
177 0 : case UM_CLIENTID_HOSTNAME:
178 0 : clientid = get_remote_machine_name();
179 0 : break;
180 :
181 0 : case UM_CLIENTID_NAME:
182 : default:
183 0 : clientid = get_current_username();
184 0 : break;
185 : }
186 :
187 0 : *path = talloc_asprintf_append(*path, "_%s.%ju",
188 : clientid, number);
189 0 : if (*path == NULL) {
190 0 : DEBUG(1, ("alloc_append_client_suffix "
191 : "out of memory\n"));
192 0 : errno = ENOMEM;
193 0 : status = -1;
194 0 : goto err;
195 : }
196 0 : DEBUG(10, ("Leaving with *path '%s'\n", *path));
197 0 : err:
198 0 : return status;
199 : }
200 :
201 : /* Returns true if the file or directory begins with the appledouble
202 : * prefix.
203 : */
204 0 : static bool is_apple_double(const char* fname)
205 : {
206 0 : bool ret = false;
207 :
208 0 : DEBUG(10, ("Entering with fname '%s'\n", fname));
209 :
210 0 : if (strnequal(APPLE_DOUBLE_PREFIX, fname, APPLE_DOUBLE_PREFIX_LEN)) {
211 0 : ret = true;
212 : }
213 0 : DEBUG(10, ("Leaving with ret '%s'\n",
214 : ret == true ? "true" : "false"));
215 0 : return ret;
216 : }
217 :
218 0 : static bool starts_with_media_dir(const char* media_dirname,
219 : size_t media_dirname_len,
220 : const char *path)
221 : {
222 0 : bool ret = false;
223 0 : const char *path_start = path;
224 :
225 0 : DEBUG(10, ("Entering with media_dirname '%s' "
226 : "path '%s'\n", media_dirname, path));
227 :
228 : /* Sometimes Samba gives us "./OMFI MediaFiles". */
229 0 : if (strnequal(path, "./", 2)) {
230 0 : path_start += 2;
231 : }
232 :
233 0 : if (strnequal(media_dirname, path_start, media_dirname_len)
234 0 : &&
235 0 : ((path_start[media_dirname_len] == '\0') ||
236 0 : (path_start[media_dirname_len] == '/'))) {
237 0 : ret = true;
238 : }
239 :
240 0 : DEBUG(10, ("Leaving with ret '%s'\n",
241 : ret == true ? "true" : "false"));
242 0 : return ret;
243 : }
244 :
245 : /*
246 : * Returns true if the file or directory referenced by the path is ONE
247 : * LEVEL below the AVID_MXF_DIRNAME or OMFI_MEDIAFILES_DIRNAME
248 : * directory
249 : */
250 0 : static bool is_in_media_dir(const char *path)
251 : {
252 0 : int transition_count = 0;
253 0 : const char *path_start = path;
254 : const char *p;
255 : const char *media_dirname;
256 : size_t media_dirname_len;
257 :
258 0 : DEBUG(10, ("Entering with path'%s' ", path));
259 :
260 : /* Sometimes Samba gives us "./OMFI MediaFiles". */
261 0 : if (strnequal(path, "./", 2)) {
262 0 : path_start += 2;
263 : }
264 :
265 0 : if (strnequal(path_start, AVID_MXF_DIRNAME, AVID_MXF_DIRNAME_LEN)) {
266 0 : media_dirname = AVID_MXF_DIRNAME;
267 0 : media_dirname_len = AVID_MXF_DIRNAME_LEN;
268 0 : } else if (strnequal(path_start,
269 : OMFI_MEDIAFILES_DIRNAME,
270 : OMFI_MEDIAFILES_DIRNAME_LEN)) {
271 0 : media_dirname = OMFI_MEDIAFILES_DIRNAME;
272 0 : media_dirname_len = OMFI_MEDIAFILES_DIRNAME_LEN;
273 : } else {
274 0 : return false;
275 : }
276 :
277 0 : if (path_start[media_dirname_len] == '\0') {
278 0 : goto out;
279 : }
280 :
281 0 : p = path_start + media_dirname_len + 1;
282 :
283 : while (true) {
284 0 : if (*p == '\0' || *p == '/') {
285 0 : if (strnequal(p - 3, "/..", 3)) {
286 0 : transition_count--;
287 0 : } else if ((p[-1] != '/') || !strnequal(p - 2, "/.", 2)) {
288 0 : transition_count++;
289 : }
290 : }
291 0 : if (*p == '\0') {
292 0 : break;
293 : }
294 0 : p++;
295 : }
296 :
297 0 : out:
298 0 : DEBUG(10, ("Going out with transition_count '%i'\n",
299 : transition_count));
300 0 : if (((transition_count == 1) && (media_dirname == AVID_MXF_DIRNAME))
301 0 : ||
302 0 : ((transition_count == 0) && (media_dirname == OMFI_MEDIAFILES_DIRNAME))) {
303 0 : return true;
304 : }
305 0 : else return false;
306 : }
307 :
308 : /*
309 : * Returns true if the file or directory referenced by the path is
310 : * below the AVID_MEDIAFILES_DIRNAME or OMFI_MEDIAFILES_DIRNAME
311 : * directory The AVID_MEDIAFILES_DIRNAME and OMFI_MEDIAFILES_DIRNAME
312 : * are assumed to be in the root directory, which is generally a safe
313 : * assumption in the fixed-path world of Avid.
314 : */
315 0 : static bool is_in_media_files(const char *path)
316 : {
317 0 : bool ret = false;
318 :
319 0 : DEBUG(10, ("Entering with path '%s'\n", path));
320 :
321 0 : if (starts_with_media_dir(AVID_MXF_DIRNAME,
322 0 : AVID_MXF_DIRNAME_LEN, path) ||
323 0 : starts_with_media_dir(OMFI_MEDIAFILES_DIRNAME,
324 : OMFI_MEDIAFILES_DIRNAME_LEN, path)) {
325 0 : ret = true;
326 : }
327 0 : DEBUG(10, ("Leaving with ret '%s'\n",
328 : ret == true ? "true" : "false"));
329 0 : return ret;
330 : }
331 :
332 :
333 : /* Add client suffix to "pure-number" path.
334 : *
335 : * Caller must free newPath.
336 : *
337 : * Success: return 0
338 : * Failure: set errno, newPath NULL, return -1
339 : */
340 0 : static int alloc_get_client_path(vfs_handle_struct *handle,
341 : TALLOC_CTX *ctx,
342 : const char *path_in,
343 : char **path_out)
344 : {
345 0 : int status = 0;
346 : char *p;
347 : char *digits;
348 : size_t digits_len;
349 : uintmax_t number;
350 :
351 0 : *path_out = talloc_strdup(ctx, path_in);
352 0 : if (*path_out == NULL) {
353 0 : DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
354 0 : return -1;
355 : }
356 :
357 0 : (void)get_digit_group(*path_out, &number);
358 :
359 0 : digits = talloc_asprintf(NULL, "%ju", number);
360 0 : if (digits == NULL) {
361 0 : DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
362 0 : return -1;
363 : }
364 0 : digits_len = strlen(digits);
365 :
366 0 : p = strstr_m(path_in, digits);
367 0 : if ((p)
368 0 : &&
369 0 : ((p[digits_len] == '\0') || (p[digits_len] == '/'))
370 0 : &&
371 0 : (((p - path_in > 0) && (p[-1] == '/'))
372 0 : ||
373 0 : (((p - path_in) > APPLE_DOUBLE_PREFIX_LEN)
374 0 : &&
375 0 : is_apple_double(p - APPLE_DOUBLE_PREFIX_LEN)
376 0 : &&
377 0 : (p[-(APPLE_DOUBLE_PREFIX_LEN + 1)] == '/'))))
378 : {
379 0 : (*path_out)[p - path_in + digits_len] = '\0';
380 :
381 0 : status = alloc_append_client_suffix(handle, path_out);
382 0 : if (status != 0) {
383 0 : goto out;
384 : }
385 :
386 0 : *path_out = talloc_strdup_append(*path_out, p + digits_len);
387 0 : if (*path_out == NULL) {
388 0 : DEBUG(1, ("alloc_get_client_path ENOMEM\n"));
389 0 : status = -1;
390 0 : goto out;
391 : }
392 : }
393 0 : out:
394 : /* path_out must be freed in caller. */
395 0 : DEBUG(10, ("Result:'%s'\n", *path_out));
396 0 : return status;
397 : }
398 :
399 : /*
400 : * Success: return 0
401 : * Failure: set errno, return -1
402 : */
403 0 : static int alloc_get_client_smb_fname(struct vfs_handle_struct *handle,
404 : TALLOC_CTX *ctx,
405 : const struct smb_filename *smb_fname,
406 : struct smb_filename **client_fname)
407 : {
408 : int status ;
409 :
410 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
411 : smb_fname->base_name));
412 :
413 0 : *client_fname = cp_smb_filename(ctx, smb_fname);
414 0 : if (*client_fname == NULL) {
415 0 : DEBUG(1, ("cp_smb_filename returned NULL\n"));
416 0 : return -1;
417 : }
418 0 : status = alloc_get_client_path(handle, ctx,
419 0 : smb_fname->base_name,
420 0 : &(*client_fname)->base_name);
421 0 : if (status != 0) {
422 0 : return -1;
423 : }
424 :
425 0 : DEBUG(10, ("Leaving with (*client_fname)->base_name "
426 : "'%s'\n", (*client_fname)->base_name));
427 :
428 0 : return 0;
429 : }
430 :
431 :
432 : /*
433 : * Success: return 0
434 : * Failure: set errno, return -1
435 : */
436 0 : static int alloc_set_client_dirinfo_path(struct vfs_handle_struct *handle,
437 : TALLOC_CTX *ctx,
438 : char **path,
439 : const char *suffix_number)
440 : {
441 : int status;
442 :
443 0 : DEBUG(10, ("Entering with suffix_number '%s'\n",
444 : suffix_number));
445 :
446 0 : *path = talloc_strdup(ctx, suffix_number);
447 0 : if (*path == NULL) {
448 0 : DEBUG(1, ("alloc_set_client_dirinfo_path ENOMEM\n"));
449 0 : return -1;
450 : }
451 0 : status = alloc_append_client_suffix(handle, path);
452 0 : if (status != 0) {
453 0 : return -1;
454 : }
455 :
456 0 : DEBUG(10, ("Leaving with *path '%s'\n", *path));
457 :
458 0 : return 0;
459 : }
460 :
461 0 : static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
462 : const char *fname,
463 : struct um_dirinfo_struct **di_result)
464 : {
465 0 : int status = 0;
466 : char *digits;
467 : uintmax_t number;
468 : struct um_dirinfo_struct *dip;
469 :
470 0 : DEBUG(10, ("Entering with fname '%s'\n", fname));
471 :
472 0 : *di_result = talloc(NULL, struct um_dirinfo_struct);
473 0 : if (*di_result == NULL) {
474 0 : goto err;
475 : }
476 0 : dip = *di_result;
477 :
478 0 : dip->dirpath = talloc_strdup(dip, fname);
479 0 : if (dip->dirpath == NULL) {
480 0 : goto err;
481 : }
482 :
483 0 : if (!is_in_media_files(fname)) {
484 0 : dip->isInMediaFiles = false;
485 0 : dip->clientPath = NULL;
486 0 : dip->clientSubDirname = NULL;
487 0 : goto out;
488 : }
489 :
490 0 : dip->isInMediaFiles = true;
491 :
492 0 : (void)get_digit_group(fname, &number);
493 0 : digits = talloc_asprintf(talloc_tos(), "%ju", number);
494 0 : if (digits == NULL) {
495 0 : goto err;
496 : }
497 :
498 0 : status = alloc_set_client_dirinfo_path(handle, dip,
499 : &dip->clientSubDirname,
500 : digits);
501 0 : if (status != 0) {
502 0 : goto err;
503 : }
504 :
505 0 : status = alloc_get_client_path(handle, dip, fname,
506 : &dip->clientPath);
507 0 : if (status != 0 || dip->clientPath == NULL) {
508 : goto err;
509 : }
510 :
511 0 : out:
512 0 : DEBUG(10, ("Leaving with (*dirInfo)->dirpath '%s', "
513 : "(*dirInfo)->clientPath '%s'\n",
514 : dip->dirpath, dip->clientPath));
515 0 : return status;
516 :
517 0 : err:
518 0 : DEBUG(1, ("Failing with fname '%s'\n", fname));
519 0 : TALLOC_FREE(*di_result);
520 0 : status = -1;
521 0 : errno = ENOMEM;
522 0 : return status;
523 : }
524 :
525 : /**********************************************************************
526 : * VFS functions
527 : **********************************************************************/
528 :
529 : /*
530 : * Success: return 0
531 : * Failure: set errno, return -1
532 : */
533 0 : static int um_statvfs(struct vfs_handle_struct *handle,
534 : const struct smb_filename *smb_fname,
535 : struct vfs_statvfs_struct *statbuf)
536 : {
537 : int status;
538 0 : struct smb_filename *client_fname = NULL;
539 :
540 0 : DEBUG(10, ("Entering with path '%s'\n", smb_fname->base_name));
541 :
542 0 : if (!is_in_media_files(smb_fname->base_name)) {
543 0 : return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
544 : }
545 :
546 0 : status = alloc_get_client_smb_fname(handle,
547 : talloc_tos(),
548 : smb_fname,
549 : &client_fname);
550 0 : if (status != 0) {
551 0 : goto err;
552 : }
553 :
554 0 : status = SMB_VFS_NEXT_STATVFS(handle, client_fname, statbuf);
555 0 : err:
556 0 : TALLOC_FREE(client_fname);
557 0 : DEBUG(10, ("Leaving with path '%s'\n", smb_fname->base_name));
558 0 : return status;
559 : }
560 :
561 0 : static DIR *um_fdopendir(vfs_handle_struct *handle,
562 : files_struct *fsp,
563 : const char *mask,
564 : uint32_t attr)
565 : {
566 0 : struct um_dirinfo_struct *dirInfo = NULL;
567 : DIR *dirstream;
568 :
569 0 : DEBUG(10, ("Entering with fsp->fsp_name->base_name '%s'\n",
570 : fsp->fsp_name->base_name));
571 :
572 0 : dirstream = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
573 0 : if (!dirstream) {
574 0 : goto err;
575 : }
576 :
577 0 : if (alloc_set_client_dirinfo(handle,
578 0 : fsp->fsp_name->base_name,
579 : &dirInfo)) {
580 0 : goto err;
581 : }
582 :
583 0 : dirInfo->dirstream = dirstream;
584 :
585 0 : if (!dirInfo->isInMediaFiles) {
586 : /*
587 : * FIXME: this is the original code, something must be
588 : * missing here, but what? -slow
589 : */
590 0 : goto out;
591 : }
592 :
593 0 : out:
594 0 : DEBUG(10, ("Leaving with dirInfo->dirpath '%s', "
595 : "dirInfo->clientPath '%s', "
596 : "fsp->fsp_name->st.st_ex_mtime %s",
597 : dirInfo->dirpath,
598 : dirInfo->clientPath,
599 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
600 0 : return (DIR *) dirInfo;
601 :
602 0 : err:
603 0 : DEBUG(1, ("Failing with fsp->fsp_name->base_name '%s'\n",
604 : fsp->fsp_name->base_name));
605 0 : TALLOC_FREE(dirInfo);
606 0 : return NULL;
607 : }
608 :
609 : /*
610 : * skip own suffixed directory
611 : * replace own suffixed directory with non suffixed.
612 : *
613 : * Success: return dirent
614 : * End of data: return NULL
615 : * Failure: set errno, return NULL
616 : */
617 0 : static struct dirent *um_readdir(vfs_handle_struct *handle,
618 : struct files_struct *dirfsp,
619 : DIR *dirp,
620 : SMB_STRUCT_STAT *sbuf)
621 : {
622 0 : um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
623 0 : struct dirent *d = NULL;
624 : int skip;
625 :
626 0 : DEBUG(10, ("dirInfo->dirpath '%s', "
627 : "dirInfo->clientPath '%s', "
628 : "dirInfo->isInMediaFiles '%s', "
629 : "dirInfo->clientSubDirname '%s'\n",
630 : dirInfo->dirpath,
631 : dirInfo->clientPath,
632 : dirInfo->isInMediaFiles ? "true" : "false",
633 : dirInfo->clientSubDirname));
634 :
635 0 : if (!dirInfo->isInMediaFiles) {
636 0 : return SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream, sbuf);
637 : }
638 :
639 : do {
640 : const char* dname;
641 : bool isAppleDouble;
642 : char *digits;
643 : size_t digits_len;
644 : uintmax_t number;
645 :
646 0 : skip = false;
647 0 : d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream, sbuf);
648 :
649 0 : if (d == NULL) {
650 0 : break;
651 : }
652 :
653 : /* ignore apple double prefix for logic below */
654 0 : if (is_apple_double(d->d_name)) {
655 0 : dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
656 0 : isAppleDouble = true;
657 : } else {
658 0 : dname = d->d_name;
659 0 : isAppleDouble = false;
660 : }
661 :
662 0 : DEBUG(10, ("dname = '%s'\n", dname));
663 :
664 0 : (void)get_digit_group(dname, &number);
665 0 : digits = talloc_asprintf(talloc_tos(), "%ju", number);
666 0 : if (digits == NULL) {
667 0 : DEBUG(1, ("out of memory"));
668 0 : goto err;
669 : }
670 0 : digits_len = strlen(digits);
671 :
672 0 : if (alloc_set_client_dirinfo_path(handle,
673 : dirInfo,
674 : &((dirInfo)->clientSubDirname),
675 : digits)) {
676 0 : goto err;
677 : }
678 :
679 : /*
680 : * If set to "true", vfs shows digits-only
681 : * non-suffixed subdirectories. Normally, such
682 : * subdirectories can exists only in non-media
683 : * directories, so we set it to "false". Otherwise,
684 : * if we have such subdirectories (probably created
685 : * over not "unityed" connection), it can be little
686 : * bit confusing.
687 : */
688 0 : if (strequal(dname, digits)) {
689 0 : skip = false;
690 0 : } else if (strequal(dname, dirInfo->clientSubDirname)) {
691 : /*
692 : * Remove suffix of this client's suffixed
693 : * subdirectories
694 : */
695 0 : if (isAppleDouble) {
696 0 : d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
697 : } else {
698 0 : d->d_name[digits_len] = '\0';
699 : }
700 0 : } else if (strnequal(digits, dname, digits_len)) {
701 : /*
702 : * Set to false to see another clients subdirectories
703 : */
704 0 : skip = false;
705 : }
706 0 : } while (skip);
707 :
708 0 : DEBUG(10, ("Leaving um_readdir\n"));
709 0 : return d;
710 0 : err:
711 0 : TALLOC_FREE(dirInfo);
712 0 : return NULL;
713 : }
714 :
715 0 : static void um_seekdir(vfs_handle_struct *handle,
716 : DIR *dirp,
717 : long offset)
718 : {
719 0 : DEBUG(10, ("Entering and leaving um_seekdir\n"));
720 0 : SMB_VFS_NEXT_SEEKDIR(handle,
721 : ((um_dirinfo_struct*)dirp)->dirstream, offset);
722 0 : }
723 :
724 0 : static long um_telldir(vfs_handle_struct *handle,
725 : DIR *dirp)
726 : {
727 0 : DEBUG(10, ("Entering and leaving um_telldir\n"));
728 0 : return SMB_VFS_NEXT_TELLDIR(handle,
729 : ((um_dirinfo_struct*)dirp)->dirstream);
730 : }
731 :
732 0 : static void um_rewinddir(vfs_handle_struct *handle,
733 : DIR *dirp)
734 : {
735 0 : DEBUG(10, ("Entering and leaving um_rewinddir\n"));
736 0 : SMB_VFS_NEXT_REWINDDIR(handle,
737 : ((um_dirinfo_struct*)dirp)->dirstream);
738 0 : }
739 :
740 0 : static int um_mkdirat(vfs_handle_struct *handle,
741 : struct files_struct *dirfsp,
742 : const struct smb_filename *smb_fname,
743 : mode_t mode)
744 : {
745 : int status;
746 0 : const char *path = NULL;
747 0 : struct smb_filename *client_fname = NULL;
748 0 : struct smb_filename *full_fname = NULL;
749 :
750 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
751 : dirfsp,
752 : smb_fname);
753 0 : if (full_fname == NULL) {
754 0 : return -1;
755 : }
756 :
757 0 : path = full_fname->base_name;
758 0 : DEBUG(10, ("Entering with path '%s'\n", path));
759 :
760 0 : if (!is_in_media_files(path) || !is_in_media_dir(path)) {
761 0 : TALLOC_FREE(full_fname);
762 0 : return SMB_VFS_NEXT_MKDIRAT(handle,
763 : dirfsp,
764 : smb_fname,
765 : mode);
766 : }
767 :
768 0 : status = alloc_get_client_smb_fname(handle,
769 : talloc_tos(),
770 : full_fname,
771 : &client_fname);
772 0 : if (status != 0) {
773 0 : goto err;
774 : }
775 :
776 0 : status = SMB_VFS_NEXT_MKDIRAT(handle,
777 : handle->conn->cwd_fsp,
778 : client_fname,
779 : mode);
780 0 : err:
781 0 : DEBUG(10, ("Leaving with path '%s'\n", path));
782 0 : TALLOC_FREE(client_fname);
783 0 : TALLOC_FREE(full_fname);
784 0 : return status;
785 : }
786 :
787 0 : static int um_closedir(vfs_handle_struct *handle,
788 : DIR *dirp)
789 : {
790 0 : DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
791 :
792 0 : TALLOC_FREE(dirp);
793 :
794 0 : return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
795 : }
796 :
797 0 : static int um_openat(struct vfs_handle_struct *handle,
798 : const struct files_struct *dirfsp,
799 : const struct smb_filename *smb_fname,
800 : struct files_struct *fsp,
801 : const struct vfs_open_how *how)
802 : {
803 0 : struct smb_filename *client_fname = NULL;
804 : int ret;
805 :
806 0 : DBG_DEBUG("Entering with smb_fname->base_name '%s'\n",
807 : smb_fname->base_name);
808 :
809 0 : if (!is_in_media_files(smb_fname->base_name)) {
810 0 : return SMB_VFS_NEXT_OPENAT(handle,
811 : dirfsp,
812 : smb_fname,
813 : fsp,
814 : how);
815 : }
816 :
817 0 : if (alloc_get_client_smb_fname(handle, talloc_tos(),
818 : smb_fname,
819 : &client_fname)) {
820 0 : ret = -1;
821 0 : goto err;
822 : }
823 :
824 : /*
825 : * FIXME:
826 : * What about fsp->fsp_name? We also have to get correct stat
827 : * info into fsp and smb_fname for DB files, don't we?
828 : */
829 :
830 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
831 : "smb_fname->st.st_ex_mtime %s"
832 : "fsp->fsp_name->st.st_ex_mtime %s",
833 : smb_fname->base_name,
834 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
835 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
836 :
837 0 : ret = SMB_VFS_NEXT_OPENAT(handle,
838 : dirfsp,
839 : client_fname,
840 : fsp,
841 : how);
842 0 : err:
843 0 : TALLOC_FREE(client_fname);
844 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
845 : smb_fname->base_name));
846 0 : return ret;
847 : }
848 :
849 0 : static NTSTATUS um_create_file(vfs_handle_struct *handle,
850 : struct smb_request *req,
851 : struct files_struct *dirfsp,
852 : struct smb_filename *smb_fname,
853 : uint32_t access_mask,
854 : uint32_t share_access,
855 : uint32_t create_disposition,
856 : uint32_t create_options,
857 : uint32_t file_attributes,
858 : uint32_t oplock_request,
859 : const struct smb2_lease *lease,
860 : uint64_t allocation_size,
861 : uint32_t private_flags,
862 : struct security_descriptor *sd,
863 : struct ea_list *ea_list,
864 : files_struct **result_fsp,
865 : int *pinfo,
866 : const struct smb2_create_blobs *in_context_blobs,
867 : struct smb2_create_blobs *out_context_blobs)
868 : {
869 : NTSTATUS status;
870 0 : struct smb_filename *client_fname = NULL;
871 :
872 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
873 : smb_fname->base_name));
874 :
875 0 : if (!is_in_media_files(smb_fname->base_name)) {
876 0 : return SMB_VFS_NEXT_CREATE_FILE(
877 : handle,
878 : req,
879 : dirfsp,
880 : smb_fname,
881 : access_mask,
882 : share_access,
883 : create_disposition,
884 : create_options,
885 : file_attributes,
886 : oplock_request,
887 : lease,
888 : allocation_size,
889 : private_flags,
890 : sd,
891 : ea_list,
892 : result_fsp,
893 : pinfo,
894 : in_context_blobs,
895 : out_context_blobs);
896 : }
897 :
898 0 : if (alloc_get_client_smb_fname(handle, talloc_tos(),
899 : smb_fname,
900 : &client_fname)) {
901 0 : status = map_nt_error_from_unix(errno);
902 0 : goto err;
903 : }
904 :
905 : /*
906 : * FIXME:
907 : * This only creates files, so we don't have to worry about
908 : * our fake directory stat'ing here. But we still need to
909 : * route stat calls for DB files properly, right?
910 : */
911 0 : status = SMB_VFS_NEXT_CREATE_FILE(
912 : handle,
913 : req,
914 : dirfsp,
915 : client_fname,
916 : access_mask,
917 : share_access,
918 : create_disposition,
919 : create_options,
920 : file_attributes,
921 : oplock_request,
922 : lease,
923 : allocation_size,
924 : private_flags,
925 : sd,
926 : ea_list,
927 : result_fsp,
928 : pinfo,
929 : in_context_blobs,
930 : out_context_blobs);
931 0 : err:
932 0 : TALLOC_FREE(client_fname);
933 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
934 : "smb_fname->st.st_ex_mtime %s"
935 : " fsp->fsp_name->st.st_ex_mtime %s",
936 : smb_fname->base_name,
937 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
938 : (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
939 : ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
940 : "No fsp time\n"));
941 0 : return status;
942 : }
943 :
944 0 : static int um_renameat(vfs_handle_struct *handle,
945 : files_struct *srcfsp,
946 : const struct smb_filename *smb_fname_src,
947 : files_struct *dstfsp,
948 : const struct smb_filename *smb_fname_dst)
949 : {
950 : int status;
951 0 : struct smb_filename *src_full_fname = NULL;
952 0 : struct smb_filename *dst_full_fname = NULL;
953 0 : struct smb_filename *src_client_fname = NULL;
954 0 : struct smb_filename *dst_client_fname = NULL;
955 :
956 0 : src_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
957 : srcfsp,
958 : smb_fname_src);
959 0 : if (src_full_fname == NULL) {
960 0 : errno = ENOMEM;
961 0 : return -1;
962 : }
963 0 : dst_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
964 : dstfsp,
965 : smb_fname_dst);
966 0 : if (dst_full_fname == NULL) {
967 0 : TALLOC_FREE(src_full_fname);
968 0 : errno = ENOMEM;
969 0 : return -1;
970 : }
971 :
972 0 : DBG_DEBUG( "Entering with "
973 : "smb_fname_src->base_name '%s', "
974 : "smb_fname_dst->base_name '%s'\n",
975 : smb_fname_src->base_name,
976 : smb_fname_dst->base_name);
977 :
978 0 : if (!is_in_media_files(src_full_fname->base_name)
979 0 : &&
980 0 : !is_in_media_files(dst_full_fname->base_name)) {
981 0 : TALLOC_FREE(src_full_fname);
982 0 : TALLOC_FREE(dst_full_fname);
983 0 : return SMB_VFS_NEXT_RENAMEAT(handle,
984 : srcfsp,
985 : smb_fname_src,
986 : dstfsp,
987 : smb_fname_dst);
988 : }
989 :
990 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
991 : src_full_fname,
992 : &src_client_fname);
993 0 : if (status != 0) {
994 0 : goto err;
995 : }
996 :
997 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
998 : dst_full_fname,
999 : &dst_client_fname);
1000 :
1001 0 : if (status != 0) {
1002 0 : goto err;
1003 : }
1004 :
1005 0 : status = SMB_VFS_NEXT_RENAMEAT(handle,
1006 : handle->conn->cwd_fsp,
1007 : src_client_fname,
1008 : handle->conn->cwd_fsp,
1009 : dst_client_fname);
1010 :
1011 0 : err:
1012 0 : TALLOC_FREE(dst_client_fname);
1013 0 : TALLOC_FREE(src_client_fname);
1014 0 : TALLOC_FREE(src_full_fname);
1015 0 : TALLOC_FREE(dst_full_fname);
1016 0 : DBG_DEBUG( "Leaving with smb_fname_src->base_name '%s',"
1017 : " smb_fname_dst->base_name '%s'\n",
1018 : smb_fname_src->base_name,
1019 : smb_fname_dst->base_name);
1020 0 : return status;
1021 : }
1022 :
1023 :
1024 : /*
1025 : * Success: return 0
1026 : * Failure: set errno, return -1
1027 : */
1028 0 : static int um_stat(vfs_handle_struct *handle,
1029 : struct smb_filename *smb_fname)
1030 : {
1031 0 : int status = 0;
1032 0 : struct smb_filename *client_fname = NULL;
1033 :
1034 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1035 : smb_fname->base_name));
1036 :
1037 0 : if (!is_in_media_files(smb_fname->base_name)) {
1038 0 : return SMB_VFS_NEXT_STAT(handle, smb_fname);
1039 : }
1040 :
1041 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1042 : smb_fname,
1043 : &client_fname);
1044 0 : if (status != 0) {
1045 0 : goto err;
1046 : }
1047 0 : DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1048 : client_fname->base_name));
1049 :
1050 0 : status = SMB_VFS_NEXT_STAT(handle, client_fname);
1051 0 : if (status != 0) {
1052 0 : goto err;
1053 : }
1054 :
1055 : /*
1056 : * Unlike functions with const smb_filename, we have to modify
1057 : * smb_fname itself to pass our info back up.
1058 : */
1059 0 : DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1060 : smb_fname->base_name, client_fname->base_name));
1061 0 : smb_fname->st = client_fname->st;
1062 :
1063 0 : err:
1064 0 : TALLOC_FREE(client_fname);
1065 0 : DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1066 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1067 0 : return status;
1068 : }
1069 :
1070 0 : static int um_lstat(vfs_handle_struct *handle,
1071 : struct smb_filename *smb_fname)
1072 : {
1073 0 : int status = 0;
1074 0 : struct smb_filename *client_fname = NULL;
1075 :
1076 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1077 : smb_fname->base_name));
1078 :
1079 0 : if (!is_in_media_files(smb_fname->base_name)) {
1080 0 : return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1081 : }
1082 :
1083 0 : client_fname = NULL;
1084 :
1085 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1086 : smb_fname,
1087 : &client_fname);
1088 0 : if (status != 0) {
1089 0 : goto err;
1090 : }
1091 0 : status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1092 0 : if (status != 0) {
1093 0 : goto err;
1094 : }
1095 :
1096 0 : smb_fname->st = client_fname->st;
1097 :
1098 0 : err:
1099 0 : TALLOC_FREE(client_fname);
1100 0 : DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1101 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1102 0 : return status;
1103 : }
1104 :
1105 0 : static int um_fstat(vfs_handle_struct *handle,
1106 : files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1107 : {
1108 0 : int status = 0;
1109 :
1110 0 : DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1111 : "'%s'\n", fsp_str_dbg(fsp)));
1112 :
1113 0 : status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1114 0 : if (status != 0) {
1115 0 : goto out;
1116 : }
1117 :
1118 0 : if ((fsp->fsp_name == NULL) ||
1119 0 : !is_in_media_files(fsp->fsp_name->base_name)) {
1120 : goto out;
1121 : }
1122 :
1123 0 : status = um_stat(handle, fsp->fsp_name);
1124 0 : if (status != 0) {
1125 0 : goto out;
1126 : }
1127 :
1128 0 : *sbuf = fsp->fsp_name->st;
1129 :
1130 0 : out:
1131 0 : DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s\n",
1132 : fsp->fsp_name != NULL ?
1133 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0"));
1134 0 : return status;
1135 : }
1136 :
1137 0 : static int um_unlinkat(vfs_handle_struct *handle,
1138 : struct files_struct *dirfsp,
1139 : const struct smb_filename *smb_fname,
1140 : int flags)
1141 : {
1142 : int ret;
1143 0 : struct smb_filename *full_fname = NULL;
1144 0 : struct smb_filename *client_fname = NULL;
1145 :
1146 0 : DEBUG(10, ("Entering um_unlinkat\n"));
1147 :
1148 0 : if (!is_in_media_files(smb_fname->base_name)) {
1149 0 : return SMB_VFS_NEXT_UNLINKAT(handle,
1150 : dirfsp,
1151 : smb_fname,
1152 : flags);
1153 : }
1154 :
1155 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1156 : dirfsp,
1157 : smb_fname);
1158 0 : if (full_fname == NULL) {
1159 0 : return -1;
1160 : }
1161 :
1162 0 : ret = alloc_get_client_smb_fname(handle, talloc_tos(),
1163 : full_fname,
1164 : &client_fname);
1165 0 : if (ret != 0) {
1166 0 : goto err;
1167 : }
1168 :
1169 0 : ret = SMB_VFS_NEXT_UNLINKAT(handle,
1170 : dirfsp->conn->cwd_fsp,
1171 : client_fname,
1172 : flags);
1173 :
1174 0 : err:
1175 0 : TALLOC_FREE(full_fname);
1176 0 : TALLOC_FREE(client_fname);
1177 0 : return ret;
1178 : }
1179 :
1180 0 : static int um_lchown(vfs_handle_struct *handle,
1181 : const struct smb_filename *smb_fname,
1182 : uid_t uid,
1183 : gid_t gid)
1184 : {
1185 : int status;
1186 0 : struct smb_filename *client_fname = NULL;
1187 :
1188 0 : DEBUG(10, ("Entering um_lchown\n"));
1189 0 : if (!is_in_media_files(smb_fname->base_name)) {
1190 0 : return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1191 : }
1192 :
1193 0 : status = alloc_get_client_smb_fname(handle,
1194 : talloc_tos(),
1195 : smb_fname,
1196 : &client_fname);
1197 0 : if (status != 0) {
1198 0 : goto err;
1199 : }
1200 :
1201 0 : status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1202 :
1203 0 : err:
1204 0 : TALLOC_FREE(client_fname);
1205 0 : return status;
1206 : }
1207 :
1208 0 : static int um_chdir(vfs_handle_struct *handle,
1209 : const struct smb_filename *smb_fname)
1210 : {
1211 : int status;
1212 0 : struct smb_filename *client_fname = NULL;
1213 :
1214 0 : DEBUG(10, ("Entering um_chdir\n"));
1215 :
1216 0 : if (!is_in_media_files(smb_fname->base_name)) {
1217 0 : return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1218 : }
1219 :
1220 0 : status = alloc_get_client_smb_fname(handle,
1221 : talloc_tos(),
1222 : smb_fname,
1223 : &client_fname);
1224 0 : if (status != 0) {
1225 0 : goto err;
1226 : }
1227 :
1228 0 : status = SMB_VFS_NEXT_CHDIR(handle, client_fname);
1229 :
1230 0 : err:
1231 0 : TALLOC_FREE(client_fname);
1232 0 : return status;
1233 : }
1234 :
1235 0 : static int um_symlinkat(vfs_handle_struct *handle,
1236 : const struct smb_filename *link_contents,
1237 : struct files_struct *dirfsp,
1238 : const struct smb_filename *new_smb_fname)
1239 : {
1240 : int status;
1241 0 : struct smb_filename *new_link_target = NULL;
1242 0 : struct smb_filename *new_client_fname = NULL;
1243 0 : struct smb_filename *full_fname = NULL;
1244 :
1245 0 : DEBUG(10, ("Entering um_symlinkat\n"));
1246 :
1247 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1248 : dirfsp,
1249 : new_smb_fname);
1250 0 : if (full_fname == NULL) {
1251 0 : return -1;
1252 : }
1253 :
1254 0 : if (!is_in_media_files(link_contents->base_name) &&
1255 0 : !is_in_media_files(full_fname->base_name)) {
1256 0 : TALLOC_FREE(full_fname);
1257 0 : return SMB_VFS_NEXT_SYMLINKAT(handle,
1258 : link_contents,
1259 : dirfsp,
1260 : new_smb_fname);
1261 : }
1262 :
1263 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1264 : link_contents, &new_link_target);
1265 0 : if (status != 0) {
1266 0 : goto err;
1267 : }
1268 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1269 : full_fname, &new_client_fname);
1270 0 : if (status != 0) {
1271 0 : goto err;
1272 : }
1273 :
1274 0 : status = SMB_VFS_NEXT_SYMLINKAT(handle,
1275 : new_link_target,
1276 : handle->conn->cwd_fsp,
1277 : new_client_fname);
1278 :
1279 0 : err:
1280 0 : TALLOC_FREE(new_link_target);
1281 0 : TALLOC_FREE(new_client_fname);
1282 0 : TALLOC_FREE(full_fname);
1283 0 : return status;
1284 : }
1285 :
1286 0 : static int um_readlinkat(vfs_handle_struct *handle,
1287 : const struct files_struct *dirfsp,
1288 : const struct smb_filename *smb_fname,
1289 : char *buf,
1290 : size_t bufsiz)
1291 : {
1292 : int status;
1293 0 : struct smb_filename *client_fname = NULL;
1294 0 : struct smb_filename *full_fname = NULL;
1295 :
1296 0 : DEBUG(10, ("Entering um_readlinkat\n"));
1297 :
1298 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1299 : dirfsp,
1300 : smb_fname);
1301 0 : if (full_fname == NULL) {
1302 0 : return -1;
1303 : }
1304 :
1305 0 : if (!is_in_media_files(full_fname->base_name)) {
1306 0 : TALLOC_FREE(full_fname);
1307 0 : return SMB_VFS_NEXT_READLINKAT(handle,
1308 : dirfsp,
1309 : smb_fname,
1310 : buf,
1311 : bufsiz);
1312 : }
1313 :
1314 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1315 : full_fname, &client_fname);
1316 0 : if (status != 0) {
1317 0 : goto err;
1318 : }
1319 :
1320 0 : status = SMB_VFS_NEXT_READLINKAT(handle,
1321 : handle->conn->cwd_fsp,
1322 : client_fname,
1323 : buf,
1324 : bufsiz);
1325 :
1326 0 : err:
1327 0 : TALLOC_FREE(full_fname);
1328 0 : TALLOC_FREE(client_fname);
1329 0 : return status;
1330 : }
1331 :
1332 0 : static int um_linkat(vfs_handle_struct *handle,
1333 : files_struct *srcfsp,
1334 : const struct smb_filename *old_smb_fname,
1335 : files_struct *dstfsp,
1336 : const struct smb_filename *new_smb_fname,
1337 : int flags)
1338 : {
1339 : int status;
1340 0 : struct smb_filename *old_full_fname = NULL;
1341 0 : struct smb_filename *new_full_fname = NULL;
1342 0 : struct smb_filename *old_client_fname = NULL;
1343 0 : struct smb_filename *new_client_fname = NULL;
1344 :
1345 0 : old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1346 : srcfsp,
1347 : old_smb_fname);
1348 0 : if (old_full_fname == NULL) {
1349 0 : return -1;
1350 : }
1351 0 : new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1352 : dstfsp,
1353 : new_smb_fname);
1354 0 : if (new_full_fname == NULL) {
1355 0 : TALLOC_FREE(old_full_fname);
1356 0 : return -1;
1357 : }
1358 :
1359 0 : DEBUG(10, ("Entering um_linkat\n"));
1360 0 : if (!is_in_media_files(old_full_fname->base_name) &&
1361 0 : !is_in_media_files(new_full_fname->base_name)) {
1362 0 : TALLOC_FREE(old_full_fname);
1363 0 : TALLOC_FREE(new_full_fname);
1364 0 : return SMB_VFS_NEXT_LINKAT(handle,
1365 : srcfsp,
1366 : old_smb_fname,
1367 : dstfsp,
1368 : new_smb_fname,
1369 : flags);
1370 : }
1371 :
1372 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1373 : old_full_fname, &old_client_fname);
1374 0 : if (status != 0) {
1375 0 : goto err;
1376 : }
1377 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1378 : new_full_fname, &new_client_fname);
1379 0 : if (status != 0) {
1380 0 : goto err;
1381 : }
1382 :
1383 0 : status = SMB_VFS_NEXT_LINKAT(handle,
1384 : handle->conn->cwd_fsp,
1385 : old_client_fname,
1386 : handle->conn->cwd_fsp,
1387 : new_client_fname,
1388 : flags);
1389 :
1390 0 : err:
1391 0 : TALLOC_FREE(old_full_fname);
1392 0 : TALLOC_FREE(new_full_fname);
1393 0 : TALLOC_FREE(old_client_fname);
1394 0 : TALLOC_FREE(new_client_fname);
1395 0 : return status;
1396 : }
1397 :
1398 0 : static int um_mknodat(vfs_handle_struct *handle,
1399 : files_struct *dirfsp,
1400 : const struct smb_filename *smb_fname,
1401 : mode_t mode,
1402 : SMB_DEV_T dev)
1403 : {
1404 : int status;
1405 0 : struct smb_filename *client_fname = NULL;
1406 0 : struct smb_filename *full_fname = NULL;
1407 :
1408 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1409 : dirfsp,
1410 : smb_fname);
1411 0 : if (full_fname == NULL) {
1412 0 : return -1;
1413 : }
1414 :
1415 0 : DEBUG(10, ("Entering um_mknodat\n"));
1416 0 : if (!is_in_media_files(full_fname->base_name)) {
1417 0 : TALLOC_FREE(full_fname);
1418 0 : return SMB_VFS_NEXT_MKNODAT(handle,
1419 : dirfsp,
1420 : smb_fname,
1421 : mode,
1422 : dev);
1423 : }
1424 :
1425 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1426 : full_fname, &client_fname);
1427 0 : if (status != 0) {
1428 0 : goto err;
1429 : }
1430 :
1431 0 : status = SMB_VFS_NEXT_MKNODAT(handle,
1432 : handle->conn->cwd_fsp,
1433 : client_fname,
1434 : mode,
1435 : dev);
1436 :
1437 0 : err:
1438 0 : TALLOC_FREE(client_fname);
1439 0 : TALLOC_FREE(full_fname);
1440 0 : return status;
1441 : }
1442 :
1443 0 : static struct smb_filename *um_realpath(vfs_handle_struct *handle,
1444 : TALLOC_CTX *ctx,
1445 : const struct smb_filename *smb_fname)
1446 : {
1447 0 : struct smb_filename *client_fname = NULL;
1448 0 : struct smb_filename *result_fname = NULL;
1449 : int status;
1450 :
1451 0 : DEBUG(10, ("Entering um_realpath\n"));
1452 :
1453 0 : if (!is_in_media_files(smb_fname->base_name)) {
1454 0 : return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1455 : }
1456 :
1457 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1458 : smb_fname, &client_fname);
1459 0 : if (status != 0) {
1460 0 : goto err;
1461 : }
1462 :
1463 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, client_fname);
1464 :
1465 0 : err:
1466 0 : TALLOC_FREE(client_fname);
1467 0 : return result_fname;
1468 : }
1469 :
1470 0 : static int um_connect(vfs_handle_struct *handle,
1471 : const char *service,
1472 : const char *user)
1473 : {
1474 : int rc;
1475 : struct um_config_data *config;
1476 : int enumval;
1477 :
1478 0 : rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1479 0 : if (rc != 0) {
1480 0 : return rc;
1481 : }
1482 :
1483 0 : config = talloc_zero(handle->conn, struct um_config_data);
1484 0 : if (!config) {
1485 0 : DEBUG(1, ("talloc_zero() failed\n"));
1486 0 : errno = ENOMEM;
1487 0 : return -1;
1488 : }
1489 :
1490 0 : enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1491 : "clientid", um_clientid, UM_CLIENTID_NAME);
1492 0 : if (enumval == -1) {
1493 0 : DEBUG(1, ("value for %s: type unknown\n",
1494 : UM_PARAM_TYPE_NAME));
1495 0 : return -1;
1496 : }
1497 0 : config->clientid = (enum um_clientid)enumval;
1498 :
1499 0 : SMB_VFS_HANDLE_SET_DATA(handle, config,
1500 : NULL, struct um_config_data,
1501 : return -1);
1502 :
1503 0 : return 0;
1504 : }
1505 :
1506 : /* VFS operations structure */
1507 :
1508 : static struct vfs_fn_pointers vfs_um_fns = {
1509 : .connect_fn = um_connect,
1510 :
1511 : /* Disk operations */
1512 :
1513 : .statvfs_fn = um_statvfs,
1514 :
1515 : /* Directory operations */
1516 :
1517 : .fdopendir_fn = um_fdopendir,
1518 : .readdir_fn = um_readdir,
1519 : .seekdir_fn = um_seekdir,
1520 : .telldir_fn = um_telldir,
1521 : .rewind_dir_fn = um_rewinddir,
1522 : .mkdirat_fn = um_mkdirat,
1523 : .closedir_fn = um_closedir,
1524 :
1525 : /* File operations */
1526 :
1527 : .openat_fn = um_openat,
1528 : .create_file_fn = um_create_file,
1529 : .renameat_fn = um_renameat,
1530 : .stat_fn = um_stat,
1531 : .lstat_fn = um_lstat,
1532 : .fstat_fn = um_fstat,
1533 : .unlinkat_fn = um_unlinkat,
1534 : .lchown_fn = um_lchown,
1535 : .chdir_fn = um_chdir,
1536 : .symlinkat_fn = um_symlinkat,
1537 : .readlinkat_fn = um_readlinkat,
1538 : .linkat_fn = um_linkat,
1539 : .mknodat_fn = um_mknodat,
1540 : .realpath_fn = um_realpath,
1541 :
1542 : /* EA operations. */
1543 : .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1544 : .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1545 : };
1546 :
1547 : static_decl_vfs;
1548 26 : NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1549 : {
1550 26 : NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1551 : "unityed_media", &vfs_um_fns);
1552 26 : if (!NT_STATUS_IS_OK(ret)) {
1553 0 : return ret;
1554 : }
1555 :
1556 26 : vfs_um_debug_level = debug_add_class("unityed_media");
1557 :
1558 26 : if (vfs_um_debug_level == -1) {
1559 0 : vfs_um_debug_level = DBGC_VFS;
1560 0 : DEBUG(1, ("unityed_media_init: Couldn't register custom "
1561 : "debugging class.\n"));
1562 : }
1563 :
1564 26 : return ret;
1565 : }
|