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'\n", 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 0 : 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 : static struct dirent *
618 0 : um_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp)
619 : {
620 0 : um_dirinfo_struct* dirInfo = (um_dirinfo_struct*)dirp;
621 0 : struct dirent *d = NULL;
622 : int skip;
623 :
624 0 : DEBUG(10, ("dirInfo->dirpath '%s', "
625 : "dirInfo->clientPath '%s', "
626 : "dirInfo->isInMediaFiles '%s', "
627 : "dirInfo->clientSubDirname '%s'\n",
628 : dirInfo->dirpath,
629 : dirInfo->clientPath,
630 : dirInfo->isInMediaFiles ? "true" : "false",
631 : dirInfo->clientSubDirname));
632 :
633 0 : if (!dirInfo->isInMediaFiles) {
634 0 : return SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream);
635 : }
636 :
637 : do {
638 : const char* dname;
639 : bool isAppleDouble;
640 : char *digits;
641 : size_t digits_len;
642 : uintmax_t number;
643 :
644 0 : skip = false;
645 0 : d = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirInfo->dirstream);
646 :
647 0 : if (d == NULL) {
648 0 : break;
649 : }
650 :
651 : /* ignore apple double prefix for logic below */
652 0 : if (is_apple_double(d->d_name)) {
653 0 : dname = &d->d_name[APPLE_DOUBLE_PREFIX_LEN];
654 0 : isAppleDouble = true;
655 : } else {
656 0 : dname = d->d_name;
657 0 : isAppleDouble = false;
658 : }
659 :
660 0 : DEBUG(10, ("dname = '%s'\n", dname));
661 :
662 0 : (void)get_digit_group(dname, &number);
663 0 : digits = talloc_asprintf(talloc_tos(), "%ju", number);
664 0 : if (digits == NULL) {
665 0 : DEBUG(1, ("out of memory\n"));
666 0 : goto err;
667 : }
668 0 : digits_len = strlen(digits);
669 :
670 0 : if (alloc_set_client_dirinfo_path(handle,
671 : dirInfo,
672 : &((dirInfo)->clientSubDirname),
673 : digits)) {
674 0 : goto err;
675 : }
676 :
677 : /*
678 : * If set to "true", vfs shows digits-only
679 : * non-suffixed subdirectories. Normally, such
680 : * subdirectories can exists only in non-media
681 : * directories, so we set it to "false". Otherwise,
682 : * if we have such subdirectories (probably created
683 : * over not "unityed" connection), it can be little
684 : * bit confusing.
685 : */
686 0 : if (strequal(dname, digits)) {
687 0 : skip = false;
688 0 : } else if (strequal(dname, dirInfo->clientSubDirname)) {
689 : /*
690 : * Remove suffix of this client's suffixed
691 : * subdirectories
692 : */
693 0 : if (isAppleDouble) {
694 0 : d->d_name[digits_len + APPLE_DOUBLE_PREFIX_LEN] = '\0';
695 : } else {
696 0 : d->d_name[digits_len] = '\0';
697 : }
698 0 : } else if (strnequal(digits, dname, digits_len)) {
699 : /*
700 : * Set to false to see another clients subdirectories
701 : */
702 0 : skip = false;
703 : }
704 0 : } while (skip);
705 :
706 0 : DEBUG(10, ("Leaving um_readdir\n"));
707 0 : return d;
708 0 : err:
709 0 : TALLOC_FREE(dirInfo);
710 0 : return NULL;
711 : }
712 :
713 0 : static void um_rewinddir(vfs_handle_struct *handle,
714 : DIR *dirp)
715 : {
716 0 : DEBUG(10, ("Entering and leaving um_rewinddir\n"));
717 0 : SMB_VFS_NEXT_REWINDDIR(handle,
718 : ((um_dirinfo_struct*)dirp)->dirstream);
719 0 : }
720 :
721 0 : static int um_mkdirat(vfs_handle_struct *handle,
722 : struct files_struct *dirfsp,
723 : const struct smb_filename *smb_fname,
724 : mode_t mode)
725 : {
726 : int status;
727 0 : const char *path = NULL;
728 0 : struct smb_filename *client_fname = NULL;
729 0 : struct smb_filename *full_fname = NULL;
730 :
731 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
732 : dirfsp,
733 : smb_fname);
734 0 : if (full_fname == NULL) {
735 0 : return -1;
736 : }
737 :
738 0 : path = full_fname->base_name;
739 0 : DEBUG(10, ("Entering with path '%s'\n", path));
740 :
741 0 : if (!is_in_media_files(path) || !is_in_media_dir(path)) {
742 0 : TALLOC_FREE(full_fname);
743 0 : return SMB_VFS_NEXT_MKDIRAT(handle,
744 : dirfsp,
745 : smb_fname,
746 : mode);
747 : }
748 :
749 0 : status = alloc_get_client_smb_fname(handle,
750 : talloc_tos(),
751 : full_fname,
752 : &client_fname);
753 0 : if (status != 0) {
754 0 : goto err;
755 : }
756 :
757 0 : status = SMB_VFS_NEXT_MKDIRAT(handle,
758 : handle->conn->cwd_fsp,
759 : client_fname,
760 : mode);
761 0 : err:
762 0 : DEBUG(10, ("Leaving with path '%s'\n", path));
763 0 : TALLOC_FREE(client_fname);
764 0 : TALLOC_FREE(full_fname);
765 0 : return status;
766 : }
767 :
768 0 : static int um_closedir(vfs_handle_struct *handle,
769 : DIR *dirp)
770 : {
771 0 : DIR *realdirp = ((um_dirinfo_struct*)dirp)->dirstream;
772 :
773 0 : TALLOC_FREE(dirp);
774 :
775 0 : return SMB_VFS_NEXT_CLOSEDIR(handle, realdirp);
776 : }
777 :
778 0 : static int um_openat(struct vfs_handle_struct *handle,
779 : const struct files_struct *dirfsp,
780 : const struct smb_filename *smb_fname,
781 : struct files_struct *fsp,
782 : const struct vfs_open_how *how)
783 : {
784 0 : struct smb_filename *client_fname = NULL;
785 : int ret;
786 :
787 0 : DBG_DEBUG("Entering with smb_fname->base_name '%s'\n",
788 : smb_fname->base_name);
789 :
790 0 : if (!is_in_media_files(smb_fname->base_name)) {
791 0 : return SMB_VFS_NEXT_OPENAT(handle,
792 : dirfsp,
793 : smb_fname,
794 : fsp,
795 : how);
796 : }
797 :
798 0 : if (alloc_get_client_smb_fname(handle, talloc_tos(),
799 : smb_fname,
800 : &client_fname)) {
801 0 : ret = -1;
802 0 : goto err;
803 : }
804 :
805 : /*
806 : * FIXME:
807 : * What about fsp->fsp_name? We also have to get correct stat
808 : * info into fsp and smb_fname for DB files, don't we?
809 : */
810 :
811 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s' "
812 : "smb_fname->st.st_ex_mtime %s"
813 : "fsp->fsp_name->st.st_ex_mtime %s",
814 : smb_fname->base_name,
815 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
816 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec))));
817 :
818 0 : ret = SMB_VFS_NEXT_OPENAT(handle,
819 : dirfsp,
820 : client_fname,
821 : fsp,
822 : how);
823 0 : err:
824 0 : TALLOC_FREE(client_fname);
825 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s'\n",
826 : smb_fname->base_name));
827 0 : return ret;
828 : }
829 :
830 0 : static NTSTATUS um_create_file(vfs_handle_struct *handle,
831 : struct smb_request *req,
832 : struct files_struct *dirfsp,
833 : struct smb_filename *smb_fname,
834 : uint32_t access_mask,
835 : uint32_t share_access,
836 : uint32_t create_disposition,
837 : uint32_t create_options,
838 : uint32_t file_attributes,
839 : uint32_t oplock_request,
840 : const struct smb2_lease *lease,
841 : uint64_t allocation_size,
842 : uint32_t private_flags,
843 : struct security_descriptor *sd,
844 : struct ea_list *ea_list,
845 : files_struct **result_fsp,
846 : int *pinfo,
847 : const struct smb2_create_blobs *in_context_blobs,
848 : struct smb2_create_blobs *out_context_blobs)
849 : {
850 : NTSTATUS status;
851 0 : struct smb_filename *client_fname = NULL;
852 :
853 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
854 : smb_fname->base_name));
855 :
856 0 : if (!is_in_media_files(smb_fname->base_name)) {
857 0 : return SMB_VFS_NEXT_CREATE_FILE(
858 : handle,
859 : req,
860 : dirfsp,
861 : smb_fname,
862 : access_mask,
863 : share_access,
864 : create_disposition,
865 : create_options,
866 : file_attributes,
867 : oplock_request,
868 : lease,
869 : allocation_size,
870 : private_flags,
871 : sd,
872 : ea_list,
873 : result_fsp,
874 : pinfo,
875 : in_context_blobs,
876 : out_context_blobs);
877 : }
878 :
879 0 : if (alloc_get_client_smb_fname(handle, talloc_tos(),
880 : smb_fname,
881 : &client_fname)) {
882 0 : status = map_nt_error_from_unix(errno);
883 0 : goto err;
884 : }
885 :
886 : /*
887 : * FIXME:
888 : * This only creates files, so we don't have to worry about
889 : * our fake directory stat'ing here. But we still need to
890 : * route stat calls for DB files properly, right?
891 : */
892 0 : status = SMB_VFS_NEXT_CREATE_FILE(
893 : handle,
894 : req,
895 : dirfsp,
896 : client_fname,
897 : access_mask,
898 : share_access,
899 : create_disposition,
900 : create_options,
901 : file_attributes,
902 : oplock_request,
903 : lease,
904 : allocation_size,
905 : private_flags,
906 : sd,
907 : ea_list,
908 : result_fsp,
909 : pinfo,
910 : in_context_blobs,
911 : out_context_blobs);
912 0 : err:
913 0 : TALLOC_FREE(client_fname);
914 0 : DEBUG(10, ("Leaving with smb_fname->base_name '%s'"
915 : "smb_fname->st.st_ex_mtime %s"
916 : " fsp->fsp_name->st.st_ex_mtime %s",
917 : smb_fname->base_name,
918 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec)),
919 : (*result_fsp) && VALID_STAT((*result_fsp)->fsp_name->st) ?
920 : ctime(&((*result_fsp)->fsp_name->st.st_ex_mtime.tv_sec)) :
921 : "No fsp time\n"));
922 0 : return status;
923 : }
924 :
925 0 : static int um_renameat(vfs_handle_struct *handle,
926 : files_struct *srcfsp,
927 : const struct smb_filename *smb_fname_src,
928 : files_struct *dstfsp,
929 : const struct smb_filename *smb_fname_dst)
930 : {
931 : int status;
932 0 : struct smb_filename *src_full_fname = NULL;
933 0 : struct smb_filename *dst_full_fname = NULL;
934 0 : struct smb_filename *src_client_fname = NULL;
935 0 : struct smb_filename *dst_client_fname = NULL;
936 :
937 0 : src_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
938 : srcfsp,
939 : smb_fname_src);
940 0 : if (src_full_fname == NULL) {
941 0 : errno = ENOMEM;
942 0 : return -1;
943 : }
944 0 : dst_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
945 : dstfsp,
946 : smb_fname_dst);
947 0 : if (dst_full_fname == NULL) {
948 0 : TALLOC_FREE(src_full_fname);
949 0 : errno = ENOMEM;
950 0 : return -1;
951 : }
952 :
953 0 : DBG_DEBUG( "Entering with "
954 : "smb_fname_src->base_name '%s', "
955 : "smb_fname_dst->base_name '%s'\n",
956 : smb_fname_src->base_name,
957 : smb_fname_dst->base_name);
958 :
959 0 : if (!is_in_media_files(src_full_fname->base_name)
960 0 : &&
961 0 : !is_in_media_files(dst_full_fname->base_name)) {
962 0 : TALLOC_FREE(src_full_fname);
963 0 : TALLOC_FREE(dst_full_fname);
964 0 : return SMB_VFS_NEXT_RENAMEAT(handle,
965 : srcfsp,
966 : smb_fname_src,
967 : dstfsp,
968 : smb_fname_dst);
969 : }
970 :
971 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
972 : src_full_fname,
973 : &src_client_fname);
974 0 : if (status != 0) {
975 0 : goto err;
976 : }
977 :
978 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
979 : dst_full_fname,
980 : &dst_client_fname);
981 :
982 0 : if (status != 0) {
983 0 : goto err;
984 : }
985 :
986 0 : status = SMB_VFS_NEXT_RENAMEAT(handle,
987 : handle->conn->cwd_fsp,
988 : src_client_fname,
989 : handle->conn->cwd_fsp,
990 : dst_client_fname);
991 :
992 0 : err:
993 0 : TALLOC_FREE(dst_client_fname);
994 0 : TALLOC_FREE(src_client_fname);
995 0 : TALLOC_FREE(src_full_fname);
996 0 : TALLOC_FREE(dst_full_fname);
997 0 : DBG_DEBUG( "Leaving with smb_fname_src->base_name '%s',"
998 : " smb_fname_dst->base_name '%s'\n",
999 : smb_fname_src->base_name,
1000 : smb_fname_dst->base_name);
1001 0 : return status;
1002 : }
1003 :
1004 :
1005 : /*
1006 : * Success: return 0
1007 : * Failure: set errno, return -1
1008 : */
1009 0 : static int um_stat(vfs_handle_struct *handle,
1010 : struct smb_filename *smb_fname)
1011 : {
1012 0 : int status = 0;
1013 0 : struct smb_filename *client_fname = NULL;
1014 :
1015 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1016 : smb_fname->base_name));
1017 :
1018 0 : if (!is_in_media_files(smb_fname->base_name)) {
1019 0 : return SMB_VFS_NEXT_STAT(handle, smb_fname);
1020 : }
1021 :
1022 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1023 : smb_fname,
1024 : &client_fname);
1025 0 : if (status != 0) {
1026 0 : goto err;
1027 : }
1028 0 : DEBUG(10, ("Stat'ing client_fname->base_name '%s'\n",
1029 : client_fname->base_name));
1030 :
1031 0 : status = SMB_VFS_NEXT_STAT(handle, client_fname);
1032 0 : if (status != 0) {
1033 0 : goto err;
1034 : }
1035 :
1036 : /*
1037 : * Unlike functions with const smb_filename, we have to modify
1038 : * smb_fname itself to pass our info back up.
1039 : */
1040 0 : DEBUG(10, ("Setting smb_fname '%s' stat from client_fname '%s'\n",
1041 : smb_fname->base_name, client_fname->base_name));
1042 0 : smb_fname->st = client_fname->st;
1043 :
1044 0 : err:
1045 0 : TALLOC_FREE(client_fname);
1046 0 : DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1047 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1048 0 : return status;
1049 : }
1050 :
1051 0 : static int um_lstat(vfs_handle_struct *handle,
1052 : struct smb_filename *smb_fname)
1053 : {
1054 0 : int status = 0;
1055 0 : struct smb_filename *client_fname = NULL;
1056 :
1057 0 : DEBUG(10, ("Entering with smb_fname->base_name '%s'\n",
1058 : smb_fname->base_name));
1059 :
1060 0 : if (!is_in_media_files(smb_fname->base_name)) {
1061 0 : return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1062 : }
1063 :
1064 0 : client_fname = NULL;
1065 :
1066 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1067 : smb_fname,
1068 : &client_fname);
1069 0 : if (status != 0) {
1070 0 : goto err;
1071 : }
1072 0 : status = SMB_VFS_NEXT_LSTAT(handle, client_fname);
1073 0 : if (status != 0) {
1074 0 : goto err;
1075 : }
1076 :
1077 0 : smb_fname->st = client_fname->st;
1078 :
1079 0 : err:
1080 0 : TALLOC_FREE(client_fname);
1081 0 : DEBUG(10, ("Leaving with smb_fname->st.st_ex_mtime %s",
1082 : ctime(&(smb_fname->st.st_ex_mtime.tv_sec))));
1083 0 : return status;
1084 : }
1085 :
1086 0 : static int um_fstat(vfs_handle_struct *handle,
1087 : files_struct *fsp, SMB_STRUCT_STAT *sbuf)
1088 : {
1089 0 : int status = 0;
1090 :
1091 0 : DEBUG(10, ("Entering with fsp->fsp_name->base_name "
1092 : "'%s'\n", fsp_str_dbg(fsp)));
1093 :
1094 0 : status = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1095 0 : if (status != 0) {
1096 0 : goto out;
1097 : }
1098 :
1099 0 : if ((fsp->fsp_name == NULL) ||
1100 0 : !is_in_media_files(fsp->fsp_name->base_name)) {
1101 0 : goto out;
1102 : }
1103 :
1104 0 : status = um_stat(handle, fsp->fsp_name);
1105 0 : if (status != 0) {
1106 0 : goto out;
1107 : }
1108 :
1109 0 : *sbuf = fsp->fsp_name->st;
1110 :
1111 0 : out:
1112 0 : DEBUG(10, ("Leaving with fsp->fsp_name->st.st_ex_mtime %s",
1113 : fsp->fsp_name != NULL ?
1114 : ctime(&(fsp->fsp_name->st.st_ex_mtime.tv_sec)) : "0\n"));
1115 0 : return status;
1116 : }
1117 :
1118 0 : static int um_unlinkat(vfs_handle_struct *handle,
1119 : struct files_struct *dirfsp,
1120 : const struct smb_filename *smb_fname,
1121 : int flags)
1122 : {
1123 : int ret;
1124 0 : struct smb_filename *full_fname = NULL;
1125 0 : struct smb_filename *client_fname = NULL;
1126 :
1127 0 : DEBUG(10, ("Entering um_unlinkat\n"));
1128 :
1129 0 : if (!is_in_media_files(smb_fname->base_name)) {
1130 0 : return SMB_VFS_NEXT_UNLINKAT(handle,
1131 : dirfsp,
1132 : smb_fname,
1133 : flags);
1134 : }
1135 :
1136 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1137 : dirfsp,
1138 : smb_fname);
1139 0 : if (full_fname == NULL) {
1140 0 : return -1;
1141 : }
1142 :
1143 0 : ret = alloc_get_client_smb_fname(handle, talloc_tos(),
1144 : full_fname,
1145 : &client_fname);
1146 0 : if (ret != 0) {
1147 0 : goto err;
1148 : }
1149 :
1150 0 : ret = SMB_VFS_NEXT_UNLINKAT(handle,
1151 : dirfsp->conn->cwd_fsp,
1152 : client_fname,
1153 : flags);
1154 :
1155 0 : err:
1156 0 : TALLOC_FREE(full_fname);
1157 0 : TALLOC_FREE(client_fname);
1158 0 : return ret;
1159 : }
1160 :
1161 0 : static int um_lchown(vfs_handle_struct *handle,
1162 : const struct smb_filename *smb_fname,
1163 : uid_t uid,
1164 : gid_t gid)
1165 : {
1166 : int status;
1167 0 : struct smb_filename *client_fname = NULL;
1168 :
1169 0 : DEBUG(10, ("Entering um_lchown\n"));
1170 0 : if (!is_in_media_files(smb_fname->base_name)) {
1171 0 : return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
1172 : }
1173 :
1174 0 : status = alloc_get_client_smb_fname(handle,
1175 : talloc_tos(),
1176 : smb_fname,
1177 : &client_fname);
1178 0 : if (status != 0) {
1179 0 : goto err;
1180 : }
1181 :
1182 0 : status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid);
1183 :
1184 0 : err:
1185 0 : TALLOC_FREE(client_fname);
1186 0 : return status;
1187 : }
1188 :
1189 0 : static int um_chdir(vfs_handle_struct *handle,
1190 : const struct smb_filename *smb_fname)
1191 : {
1192 : int status;
1193 0 : struct smb_filename *client_fname = NULL;
1194 :
1195 0 : DEBUG(10, ("Entering um_chdir\n"));
1196 :
1197 0 : if (!is_in_media_files(smb_fname->base_name)) {
1198 0 : return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
1199 : }
1200 :
1201 0 : status = alloc_get_client_smb_fname(handle,
1202 : talloc_tos(),
1203 : smb_fname,
1204 : &client_fname);
1205 0 : if (status != 0) {
1206 0 : goto err;
1207 : }
1208 :
1209 0 : status = SMB_VFS_NEXT_CHDIR(handle, client_fname);
1210 :
1211 0 : err:
1212 0 : TALLOC_FREE(client_fname);
1213 0 : return status;
1214 : }
1215 :
1216 0 : static int um_symlinkat(vfs_handle_struct *handle,
1217 : const struct smb_filename *link_contents,
1218 : struct files_struct *dirfsp,
1219 : const struct smb_filename *new_smb_fname)
1220 : {
1221 : int status;
1222 0 : struct smb_filename *new_link_target = NULL;
1223 0 : struct smb_filename *new_client_fname = NULL;
1224 0 : struct smb_filename *full_fname = NULL;
1225 :
1226 0 : DEBUG(10, ("Entering um_symlinkat\n"));
1227 :
1228 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1229 : dirfsp,
1230 : new_smb_fname);
1231 0 : if (full_fname == NULL) {
1232 0 : return -1;
1233 : }
1234 :
1235 0 : if (!is_in_media_files(link_contents->base_name) &&
1236 0 : !is_in_media_files(full_fname->base_name)) {
1237 0 : TALLOC_FREE(full_fname);
1238 0 : return SMB_VFS_NEXT_SYMLINKAT(handle,
1239 : link_contents,
1240 : dirfsp,
1241 : new_smb_fname);
1242 : }
1243 :
1244 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1245 : link_contents, &new_link_target);
1246 0 : if (status != 0) {
1247 0 : goto err;
1248 : }
1249 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1250 : full_fname, &new_client_fname);
1251 0 : if (status != 0) {
1252 0 : goto err;
1253 : }
1254 :
1255 0 : status = SMB_VFS_NEXT_SYMLINKAT(handle,
1256 : new_link_target,
1257 : handle->conn->cwd_fsp,
1258 : new_client_fname);
1259 :
1260 0 : err:
1261 0 : TALLOC_FREE(new_link_target);
1262 0 : TALLOC_FREE(new_client_fname);
1263 0 : TALLOC_FREE(full_fname);
1264 0 : return status;
1265 : }
1266 :
1267 0 : static int um_readlinkat(vfs_handle_struct *handle,
1268 : const struct files_struct *dirfsp,
1269 : const struct smb_filename *smb_fname,
1270 : char *buf,
1271 : size_t bufsiz)
1272 : {
1273 : int status;
1274 0 : struct smb_filename *client_fname = NULL;
1275 0 : struct smb_filename *full_fname = NULL;
1276 :
1277 0 : DEBUG(10, ("Entering um_readlinkat\n"));
1278 :
1279 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1280 : dirfsp,
1281 : smb_fname);
1282 0 : if (full_fname == NULL) {
1283 0 : return -1;
1284 : }
1285 :
1286 0 : if (!is_in_media_files(full_fname->base_name)) {
1287 0 : TALLOC_FREE(full_fname);
1288 0 : return SMB_VFS_NEXT_READLINKAT(handle,
1289 : dirfsp,
1290 : smb_fname,
1291 : buf,
1292 : bufsiz);
1293 : }
1294 :
1295 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1296 : full_fname, &client_fname);
1297 0 : if (status != 0) {
1298 0 : goto err;
1299 : }
1300 :
1301 0 : status = SMB_VFS_NEXT_READLINKAT(handle,
1302 : handle->conn->cwd_fsp,
1303 : client_fname,
1304 : buf,
1305 : bufsiz);
1306 :
1307 0 : err:
1308 0 : TALLOC_FREE(full_fname);
1309 0 : TALLOC_FREE(client_fname);
1310 0 : return status;
1311 : }
1312 :
1313 0 : static int um_linkat(vfs_handle_struct *handle,
1314 : files_struct *srcfsp,
1315 : const struct smb_filename *old_smb_fname,
1316 : files_struct *dstfsp,
1317 : const struct smb_filename *new_smb_fname,
1318 : int flags)
1319 : {
1320 : int status;
1321 0 : struct smb_filename *old_full_fname = NULL;
1322 0 : struct smb_filename *new_full_fname = NULL;
1323 0 : struct smb_filename *old_client_fname = NULL;
1324 0 : struct smb_filename *new_client_fname = NULL;
1325 :
1326 0 : old_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1327 : srcfsp,
1328 : old_smb_fname);
1329 0 : if (old_full_fname == NULL) {
1330 0 : return -1;
1331 : }
1332 0 : new_full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1333 : dstfsp,
1334 : new_smb_fname);
1335 0 : if (new_full_fname == NULL) {
1336 0 : TALLOC_FREE(old_full_fname);
1337 0 : return -1;
1338 : }
1339 :
1340 0 : DEBUG(10, ("Entering um_linkat\n"));
1341 0 : if (!is_in_media_files(old_full_fname->base_name) &&
1342 0 : !is_in_media_files(new_full_fname->base_name)) {
1343 0 : TALLOC_FREE(old_full_fname);
1344 0 : TALLOC_FREE(new_full_fname);
1345 0 : return SMB_VFS_NEXT_LINKAT(handle,
1346 : srcfsp,
1347 : old_smb_fname,
1348 : dstfsp,
1349 : new_smb_fname,
1350 : flags);
1351 : }
1352 :
1353 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1354 : old_full_fname, &old_client_fname);
1355 0 : if (status != 0) {
1356 0 : goto err;
1357 : }
1358 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1359 : new_full_fname, &new_client_fname);
1360 0 : if (status != 0) {
1361 0 : goto err;
1362 : }
1363 :
1364 0 : status = SMB_VFS_NEXT_LINKAT(handle,
1365 : handle->conn->cwd_fsp,
1366 : old_client_fname,
1367 : handle->conn->cwd_fsp,
1368 : new_client_fname,
1369 : flags);
1370 :
1371 0 : err:
1372 0 : TALLOC_FREE(old_full_fname);
1373 0 : TALLOC_FREE(new_full_fname);
1374 0 : TALLOC_FREE(old_client_fname);
1375 0 : TALLOC_FREE(new_client_fname);
1376 0 : return status;
1377 : }
1378 :
1379 0 : static int um_mknodat(vfs_handle_struct *handle,
1380 : files_struct *dirfsp,
1381 : const struct smb_filename *smb_fname,
1382 : mode_t mode,
1383 : SMB_DEV_T dev)
1384 : {
1385 : int status;
1386 0 : struct smb_filename *client_fname = NULL;
1387 0 : struct smb_filename *full_fname = NULL;
1388 :
1389 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1390 : dirfsp,
1391 : smb_fname);
1392 0 : if (full_fname == NULL) {
1393 0 : return -1;
1394 : }
1395 :
1396 0 : DEBUG(10, ("Entering um_mknodat\n"));
1397 0 : if (!is_in_media_files(full_fname->base_name)) {
1398 0 : TALLOC_FREE(full_fname);
1399 0 : return SMB_VFS_NEXT_MKNODAT(handle,
1400 : dirfsp,
1401 : smb_fname,
1402 : mode,
1403 : dev);
1404 : }
1405 :
1406 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1407 : full_fname, &client_fname);
1408 0 : if (status != 0) {
1409 0 : goto err;
1410 : }
1411 :
1412 0 : status = SMB_VFS_NEXT_MKNODAT(handle,
1413 : handle->conn->cwd_fsp,
1414 : client_fname,
1415 : mode,
1416 : dev);
1417 :
1418 0 : err:
1419 0 : TALLOC_FREE(client_fname);
1420 0 : TALLOC_FREE(full_fname);
1421 0 : return status;
1422 : }
1423 :
1424 0 : static struct smb_filename *um_realpath(vfs_handle_struct *handle,
1425 : TALLOC_CTX *ctx,
1426 : const struct smb_filename *smb_fname)
1427 : {
1428 0 : struct smb_filename *client_fname = NULL;
1429 0 : struct smb_filename *result_fname = NULL;
1430 : int status;
1431 :
1432 0 : DEBUG(10, ("Entering um_realpath\n"));
1433 :
1434 0 : if (!is_in_media_files(smb_fname->base_name)) {
1435 0 : return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1436 : }
1437 :
1438 0 : status = alloc_get_client_smb_fname(handle, talloc_tos(),
1439 : smb_fname, &client_fname);
1440 0 : if (status != 0) {
1441 0 : goto err;
1442 : }
1443 :
1444 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, client_fname);
1445 :
1446 0 : err:
1447 0 : TALLOC_FREE(client_fname);
1448 0 : return result_fname;
1449 : }
1450 :
1451 0 : static int um_connect(vfs_handle_struct *handle,
1452 : const char *service,
1453 : const char *user)
1454 : {
1455 : int rc;
1456 : struct um_config_data *config;
1457 : int enumval;
1458 :
1459 0 : rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
1460 0 : if (rc != 0) {
1461 0 : return rc;
1462 : }
1463 :
1464 0 : config = talloc_zero(handle->conn, struct um_config_data);
1465 0 : if (!config) {
1466 0 : DEBUG(1, ("talloc_zero() failed\n"));
1467 0 : errno = ENOMEM;
1468 0 : return -1;
1469 : }
1470 :
1471 0 : enumval = lp_parm_enum(SNUM(handle->conn), UM_PARAM_TYPE_NAME,
1472 : "clientid", um_clientid, UM_CLIENTID_NAME);
1473 0 : if (enumval == -1) {
1474 0 : DEBUG(1, ("value for %s: type unknown\n",
1475 : UM_PARAM_TYPE_NAME));
1476 0 : return -1;
1477 : }
1478 0 : config->clientid = (enum um_clientid)enumval;
1479 :
1480 0 : SMB_VFS_HANDLE_SET_DATA(handle, config,
1481 : NULL, struct um_config_data,
1482 : return -1);
1483 :
1484 0 : return 0;
1485 : }
1486 :
1487 : /* VFS operations structure */
1488 :
1489 : static struct vfs_fn_pointers vfs_um_fns = {
1490 : .connect_fn = um_connect,
1491 :
1492 : /* Disk operations */
1493 :
1494 : .statvfs_fn = um_statvfs,
1495 :
1496 : /* Directory operations */
1497 :
1498 : .fdopendir_fn = um_fdopendir,
1499 : .readdir_fn = um_readdir,
1500 : .rewind_dir_fn = um_rewinddir,
1501 : .mkdirat_fn = um_mkdirat,
1502 : .closedir_fn = um_closedir,
1503 :
1504 : /* File operations */
1505 :
1506 : .openat_fn = um_openat,
1507 : .create_file_fn = um_create_file,
1508 : .renameat_fn = um_renameat,
1509 : .stat_fn = um_stat,
1510 : .lstat_fn = um_lstat,
1511 : .fstat_fn = um_fstat,
1512 : .unlinkat_fn = um_unlinkat,
1513 : .lchown_fn = um_lchown,
1514 : .chdir_fn = um_chdir,
1515 : .symlinkat_fn = um_symlinkat,
1516 : .readlinkat_fn = um_readlinkat,
1517 : .linkat_fn = um_linkat,
1518 : .mknodat_fn = um_mknodat,
1519 : .realpath_fn = um_realpath,
1520 :
1521 : /* EA operations. */
1522 : .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
1523 : .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
1524 : };
1525 :
1526 : static_decl_vfs;
1527 27 : NTSTATUS vfs_unityed_media_init(TALLOC_CTX *ctx)
1528 : {
1529 27 : NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1530 : "unityed_media", &vfs_um_fns);
1531 27 : if (!NT_STATUS_IS_OK(ret)) {
1532 0 : return ret;
1533 : }
1534 :
1535 27 : vfs_um_debug_level = debug_add_class("unityed_media");
1536 :
1537 27 : if (vfs_um_debug_level == -1) {
1538 0 : vfs_um_debug_level = DBGC_VFS;
1539 0 : DEBUG(1, ("unityed_media_init: Couldn't register custom "
1540 : "debugging class.\n"));
1541 : }
1542 :
1543 27 : return ret;
1544 : }
|