s3: VFS: Don't allow symlink, link or rename on already converted paths.
[Samba.git] / source3 / modules / vfs_shadow_copy2.c
blob1345ca24d4591f1857c6d266e2b6c39ef6ec7cd8
1 /*
2 * shadow_copy2: a shadow copy module (second implementation)
4 * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2)
5 * Copyright (C) Ed Plese 2009
6 * Copyright (C) Volker Lendecke 2011
7 * Copyright (C) Christian Ambach 2011
8 * Copyright (C) Michael Adam 2013
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * This is a second implemetation of a shadow copy module for exposing
27 * file system snapshots to windows clients as shadow copies.
29 * See the manual page for documentation.
32 #include "includes.h"
33 #include "smbd/smbd.h"
34 #include "system/filesys.h"
35 #include "include/ntioctl.h"
36 #include "util_tdb.h"
37 #include "lib/util_path.h"
39 struct shadow_copy2_config {
40 char *gmt_format;
41 bool use_sscanf;
42 bool use_localtime;
43 char *snapdir;
44 bool snapdirseverywhere;
45 bool crossmountpoints;
46 bool fixinodes;
47 char *sort_order;
48 bool snapdir_absolute;
49 char *mount_point;
50 char *rel_connectpath; /* share root, relative to a snapshot root */
51 char *snapshot_basepath; /* the absolute version of snapdir */
52 char *shadow_cwd; /* Absolute $cwd path. */
53 /* Absolute connectpath - can vary depending on $cwd. */
54 char *shadow_connectpath;
55 /* malloc'ed realpath return. */
56 char *shadow_realpath;
59 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
60 size_t **poffsets,
61 unsigned *pnum_offsets)
63 unsigned num_offsets;
64 size_t *offsets;
65 const char *p;
67 num_offsets = 0;
69 p = str;
70 while ((p = strchr(p, '/')) != NULL) {
71 num_offsets += 1;
72 p += 1;
75 offsets = talloc_array(mem_ctx, size_t, num_offsets);
76 if (offsets == NULL) {
77 return false;
80 p = str;
81 num_offsets = 0;
82 while ((p = strchr(p, '/')) != NULL) {
83 offsets[num_offsets] = p-str;
84 num_offsets += 1;
85 p += 1;
88 *poffsets = offsets;
89 *pnum_offsets = num_offsets;
90 return true;
93 /**
94 * Given a timestamp, build the posix level GMT-tag string
95 * based on the configurable format.
97 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
98 time_t snapshot,
99 char *snaptime_string,
100 size_t len)
102 struct tm snap_tm;
103 size_t snaptime_len;
104 struct shadow_copy2_config *config;
106 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
107 return 0);
109 if (config->use_sscanf) {
110 snaptime_len = snprintf(snaptime_string,
111 len,
112 config->gmt_format,
113 (unsigned long)snapshot);
114 if (snaptime_len <= 0) {
115 DEBUG(10, ("snprintf failed\n"));
116 return snaptime_len;
118 } else {
119 if (config->use_localtime) {
120 if (localtime_r(&snapshot, &snap_tm) == 0) {
121 DEBUG(10, ("gmtime_r failed\n"));
122 return -1;
124 } else {
125 if (gmtime_r(&snapshot, &snap_tm) == 0) {
126 DEBUG(10, ("gmtime_r failed\n"));
127 return -1;
130 snaptime_len = strftime(snaptime_string,
131 len,
132 config->gmt_format,
133 &snap_tm);
134 if (snaptime_len == 0) {
135 DEBUG(10, ("strftime failed\n"));
136 return 0;
140 return snaptime_len;
144 * Given a timestamp, build the string to insert into a path
145 * as a path component for creating the local path to the
146 * snapshot at the given timestamp of the input path.
148 * In the case of a parallel snapdir (specified with an
149 * absolute path), this is the inital portion of the
150 * local path of any snapshot file. The complete path is
151 * obtained by appending the portion of the file's path
152 * below the share root's mountpoint.
154 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
155 struct vfs_handle_struct *handle,
156 time_t snapshot)
158 fstring snaptime_string;
159 size_t snaptime_len = 0;
160 char *result = NULL;
161 struct shadow_copy2_config *config;
163 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
164 return NULL);
166 snaptime_len = shadow_copy2_posix_gmt_string(handle,
167 snapshot,
168 snaptime_string,
169 sizeof(snaptime_string));
170 if (snaptime_len <= 0) {
171 return NULL;
174 if (config->snapdir_absolute) {
175 result = talloc_asprintf(mem_ctx, "%s/%s",
176 config->snapdir, snaptime_string);
177 } else {
178 result = talloc_asprintf(mem_ctx, "/%s/%s",
179 config->snapdir, snaptime_string);
181 if (result == NULL) {
182 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
185 return result;
189 * Build the posix snapshot path for the connection
190 * at the given timestamp, i.e. the absolute posix path
191 * that contains the snapshot for this file system.
193 * This only applies to classical case, i.e. not
194 * to the "snapdirseverywhere" mode.
196 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
197 struct vfs_handle_struct *handle,
198 time_t snapshot)
200 fstring snaptime_string;
201 size_t snaptime_len = 0;
202 char *result = NULL;
203 struct shadow_copy2_config *config;
205 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
206 return NULL);
208 snaptime_len = shadow_copy2_posix_gmt_string(handle,
209 snapshot,
210 snaptime_string,
211 sizeof(snaptime_string));
212 if (snaptime_len <= 0) {
213 return NULL;
216 result = talloc_asprintf(mem_ctx, "%s/%s",
217 config->snapshot_basepath, snaptime_string);
218 if (result == NULL) {
219 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
222 return result;
225 static char *make_path_absolute(TALLOC_CTX *mem_ctx,
226 struct shadow_copy2_config *config,
227 const char *name)
229 char *newpath = NULL;
230 char *abs_path = NULL;
232 if (name[0] != '/') {
233 newpath = talloc_asprintf(mem_ctx,
234 "%s/%s",
235 config->shadow_cwd,
236 name);
237 if (newpath == NULL) {
238 return NULL;
240 name = newpath;
242 abs_path = canonicalize_absolute_path(mem_ctx, name);
243 TALLOC_FREE(newpath);
244 return abs_path;
247 /* Return a $cwd-relative path. */
248 static bool make_relative_path(const char *cwd, char *abs_path)
250 size_t cwd_len = strlen(cwd);
251 size_t abs_len = strlen(abs_path);
253 if (abs_len < cwd_len) {
254 return false;
256 if (memcmp(abs_path, cwd, cwd_len) != 0) {
257 return false;
259 if (abs_path[cwd_len] != '/' && abs_path[cwd_len] != '\0') {
260 return false;
262 if (abs_path[cwd_len] == '/') {
263 cwd_len++;
265 memmove(abs_path, &abs_path[cwd_len], abs_len + 1 - cwd_len);
266 return true;
269 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
270 const char *name,
271 char *gmt, size_t gmt_len);
274 * Check if an incoming filename is already a snapshot converted pathname.
276 * If so, it returns the pathname truncated at the snapshot point which
277 * will be used as the connectpath.
280 static int check_for_converted_path(TALLOC_CTX *mem_ctx,
281 struct vfs_handle_struct *handle,
282 struct shadow_copy2_config *config,
283 char *abs_path,
284 bool *ppath_already_converted,
285 char **pconnectpath)
287 size_t snapdirlen = 0;
288 char *p = strstr_m(abs_path, config->snapdir);
289 char *q = NULL;
290 char *connect_path = NULL;
291 char snapshot[GMT_NAME_LEN+1];
293 *ppath_already_converted = false;
295 if (p == NULL) {
296 /* Must at least contain shadow:snapdir. */
297 return 0;
300 if (config->snapdir[0] == '/' &&
301 p != abs_path) {
302 /* Absolute shadow:snapdir must be at the start. */
303 return 0;
306 snapdirlen = strlen(config->snapdir);
307 if (p[snapdirlen] != '/') {
308 /* shadow:snapdir must end as a separate component. */
309 return 0;
312 if (p > abs_path && p[-1] != '/') {
313 /* shadow:snapdir must start as a separate component. */
314 return 0;
317 p += snapdirlen;
318 p++; /* Move past the / */
321 * Need to return up to the next path
322 * component after the time.
323 * This will be used as the connectpath.
325 q = strchr(p, '/');
326 if (q == NULL) {
328 * No next path component.
329 * Use entire string.
331 connect_path = talloc_strdup(mem_ctx,
332 abs_path);
333 } else {
334 connect_path = talloc_strndup(mem_ctx,
335 abs_path,
336 q - abs_path);
338 if (connect_path == NULL) {
339 return ENOMEM;
343 * Point p at the same offset in connect_path as
344 * it is in abs_path.
347 p = &connect_path[p - abs_path];
350 * Now ensure there is a time string at p.
351 * The SMB-format @GMT-token string is returned
352 * in snapshot.
355 if (!shadow_copy2_snapshot_to_gmt(handle,
357 snapshot,
358 sizeof(snapshot))) {
359 TALLOC_FREE(connect_path);
360 return 0;
363 if (pconnectpath != NULL) {
364 *pconnectpath = connect_path;
367 *ppath_already_converted = true;
369 DBG_DEBUG("path |%s| is already converted. "
370 "connect path = |%s|\n",
371 abs_path,
372 connect_path);
374 return 0;
378 * This function does two things.
380 * 1). Checks if an incoming filename is already a
381 * snapshot converted pathname.
382 * If so, it returns the pathname truncated
383 * at the snapshot point which will be used
384 * as the connectpath, and then does an early return.
386 * 2). Checks if an incoming filename contains an
387 * SMB-layer @GMT- style timestamp.
388 * If so, it strips the timestamp, and returns
389 * both the timestamp and the stripped path
390 * (making it cwd-relative).
393 static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
394 struct vfs_handle_struct *handle,
395 const char *orig_name,
396 time_t *ptimestamp,
397 char **pstripped,
398 char **psnappath)
400 struct tm tm;
401 time_t timestamp = 0;
402 const char *p;
403 char *q;
404 char *stripped = NULL;
405 size_t rest_len, dst_len;
406 struct shadow_copy2_config *config;
407 ptrdiff_t len_before_gmt;
408 const char *name = orig_name;
409 char *abs_path = NULL;
410 bool ret = true;
411 bool already_converted = false;
412 int err = 0;
414 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
415 return false);
417 DEBUG(10, (__location__ ": enter path '%s'\n", name));
419 abs_path = make_path_absolute(mem_ctx, config, name);
420 if (abs_path == NULL) {
421 ret = false;
422 goto out;
424 name = abs_path;
426 DEBUG(10, (__location__ ": abs path '%s'\n", name));
428 err = check_for_converted_path(mem_ctx,
429 handle,
430 config,
431 abs_path,
432 &already_converted,
433 psnappath);
434 if (err != 0) {
435 /* error in conversion. */
436 ret = false;
437 goto out;
440 if (already_converted) {
441 goto out;
445 * From here we're only looking to strip an
446 * SMB-layer @GMT- token.
449 p = strstr_m(name, "@GMT-");
450 if (p == NULL) {
451 DEBUG(11, ("@GMT not found\n"));
452 goto out;
454 if ((p > name) && (p[-1] != '/')) {
455 /* the GMT-token does not start a path-component */
456 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
457 p, name, (int)p[-1]));
458 goto out;
461 len_before_gmt = p - name;
463 q = strptime(p, GMT_FORMAT, &tm);
464 if (q == NULL) {
465 DEBUG(10, ("strptime failed\n"));
466 goto out;
468 tm.tm_isdst = -1;
469 timestamp = timegm(&tm);
470 if (timestamp == (time_t)-1) {
471 DEBUG(10, ("timestamp==-1\n"));
472 goto out;
474 if (q[0] == '\0') {
476 * The name consists of only the GMT token or the GMT
477 * token is at the end of the path. XP seems to send
478 * @GMT- at the end under certain circumstances even
479 * with a path prefix.
481 if (pstripped != NULL) {
482 if (len_before_gmt > 0) {
484 * There is a slash before
485 * the @GMT-. Remove it.
487 len_before_gmt -= 1;
489 stripped = talloc_strndup(mem_ctx, name, p - name);
490 if (stripped == NULL) {
491 ret = false;
492 goto out;
494 if (orig_name[0] != '/') {
495 if (make_relative_path(config->shadow_cwd,
496 stripped) == false) {
497 DEBUG(10, (__location__ ": path '%s' "
498 "doesn't start with cwd '%s\n",
499 stripped, config->shadow_cwd));
500 ret = false;
501 errno = ENOENT;
502 goto out;
505 *pstripped = stripped;
507 *ptimestamp = timestamp;
508 goto out;
510 if (q[0] != '/') {
512 * It is not a complete path component, i.e. the path
513 * component continues after the gmt-token.
515 DEBUG(10, ("q[0] = %d\n", (int)q[0]));
516 goto out;
518 q += 1;
520 rest_len = strlen(q);
521 dst_len = (p-name) + rest_len;
523 if (pstripped != NULL) {
524 stripped = talloc_array(mem_ctx, char, dst_len+1);
525 if (stripped == NULL) {
526 ret = false;
527 goto out;
529 if (p > name) {
530 memcpy(stripped, name, p-name);
532 if (rest_len > 0) {
533 memcpy(stripped + (p-name), q, rest_len);
535 stripped[dst_len] = '\0';
536 if (orig_name[0] != '/') {
537 if (make_relative_path(config->shadow_cwd,
538 stripped) == false) {
539 DEBUG(10, (__location__ ": path '%s' "
540 "doesn't start with cwd '%s\n",
541 stripped, config->shadow_cwd));
542 ret = false;
543 errno = ENOENT;
544 goto out;
547 *pstripped = stripped;
549 *ptimestamp = timestamp;
550 ret = true;
552 out:
553 TALLOC_FREE(abs_path);
554 return ret;
557 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
558 struct vfs_handle_struct *handle,
559 const char *orig_name,
560 time_t *ptimestamp,
561 char **pstripped)
563 return shadow_copy2_strip_snapshot_internal(mem_ctx,
564 handle,
565 orig_name,
566 ptimestamp,
567 pstripped,
568 NULL);
571 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
572 vfs_handle_struct *handle)
574 char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
575 dev_t dev;
576 struct stat st;
577 char *p;
579 if (stat(path, &st) != 0) {
580 talloc_free(path);
581 return NULL;
584 dev = st.st_dev;
586 while ((p = strrchr(path, '/')) && p > path) {
587 *p = 0;
588 if (stat(path, &st) != 0) {
589 talloc_free(path);
590 return NULL;
592 if (st.st_dev != dev) {
593 *p = '/';
594 break;
598 return path;
602 * Convert from a name as handed in via the SMB layer
603 * and a timestamp into the local path of the snapshot
604 * of the provided file at the provided time.
605 * Also return the path in the snapshot corresponding
606 * to the file's share root.
608 static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
609 struct vfs_handle_struct *handle,
610 const char *name, time_t timestamp,
611 size_t *snaproot_len)
613 struct smb_filename converted_fname;
614 char *result = NULL;
615 size_t *slashes = NULL;
616 unsigned num_slashes;
617 char *path = NULL;
618 size_t pathlen;
619 char *insert = NULL;
620 char *converted = NULL;
621 size_t insertlen, connectlen = 0;
622 int saved_errno = 0;
623 int i;
624 size_t min_offset;
625 struct shadow_copy2_config *config;
626 size_t in_share_offset = 0;
628 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
629 return NULL);
631 DEBUG(10, ("converting '%s'\n", name));
633 if (!config->snapdirseverywhere) {
634 int ret;
635 char *snapshot_path;
637 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
638 handle,
639 timestamp);
640 if (snapshot_path == NULL) {
641 goto fail;
644 if (config->rel_connectpath == NULL) {
645 converted = talloc_asprintf(mem_ctx, "%s/%s",
646 snapshot_path, name);
647 } else {
648 converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
649 snapshot_path,
650 config->rel_connectpath,
651 name);
653 if (converted == NULL) {
654 goto fail;
657 ZERO_STRUCT(converted_fname);
658 converted_fname.base_name = converted;
660 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
661 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
662 converted,
663 ret, ret == 0 ? "ok" : strerror(errno)));
664 if (ret == 0) {
665 DEBUG(10, ("Found %s\n", converted));
666 result = converted;
667 converted = NULL;
668 if (snaproot_len != NULL) {
669 *snaproot_len = strlen(snapshot_path);
670 if (config->rel_connectpath != NULL) {
671 *snaproot_len +=
672 strlen(config->rel_connectpath) + 1;
675 goto fail;
676 } else {
677 errno = ENOENT;
678 goto fail;
680 /* never reached ... */
683 connectlen = strlen(handle->conn->connectpath);
684 if (name[0] == 0) {
685 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
686 } else {
687 path = talloc_asprintf(
688 mem_ctx, "%s/%s", handle->conn->connectpath, name);
690 if (path == NULL) {
691 errno = ENOMEM;
692 goto fail;
694 pathlen = talloc_get_size(path)-1;
696 if (!shadow_copy2_find_slashes(talloc_tos(), path,
697 &slashes, &num_slashes)) {
698 goto fail;
701 insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
702 if (insert == NULL) {
703 goto fail;
705 insertlen = talloc_get_size(insert)-1;
708 * Note: We deliberatly don't expensively initialize the
709 * array with talloc_zero here: Putting zero into
710 * converted[pathlen+insertlen] below is sufficient, because
711 * in the following for loop, the insert string is inserted
712 * at various slash places. So the memory up to position
713 * pathlen+insertlen will always be initialized when the
714 * converted string is used.
716 converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
717 if (converted == NULL) {
718 goto fail;
721 if (path[pathlen-1] != '/') {
723 * Append a fake slash to find the snapshot root
725 size_t *tmp;
726 tmp = talloc_realloc(talloc_tos(), slashes,
727 size_t, num_slashes+1);
728 if (tmp == NULL) {
729 goto fail;
731 slashes = tmp;
732 slashes[num_slashes] = pathlen;
733 num_slashes += 1;
736 min_offset = 0;
738 if (!config->crossmountpoints) {
739 min_offset = strlen(config->mount_point);
742 memcpy(converted, path, pathlen+1);
743 converted[pathlen+insertlen] = '\0';
745 ZERO_STRUCT(converted_fname);
746 converted_fname.base_name = converted;
748 for (i = num_slashes-1; i>=0; i--) {
749 int ret;
750 size_t offset;
752 offset = slashes[i];
754 if (offset < min_offset) {
755 errno = ENOENT;
756 goto fail;
759 if (offset >= connectlen) {
760 in_share_offset = offset;
763 memcpy(converted+offset, insert, insertlen);
765 offset += insertlen;
766 memcpy(converted+offset, path + slashes[i],
767 pathlen - slashes[i]);
769 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
771 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
772 converted,
773 ret, ret == 0 ? "ok" : strerror(errno)));
774 if (ret == 0) {
775 /* success */
776 if (snaproot_len != NULL) {
777 *snaproot_len = in_share_offset + insertlen;
779 break;
781 if (errno == ENOTDIR) {
783 * This is a valid condition: We appended the
784 * .snaphots/@GMT.. to a file name. Just try
785 * with the upper levels.
787 continue;
789 if (errno != ENOENT) {
790 /* Other problem than "not found" */
791 goto fail;
795 if (i >= 0) {
797 * Found something
799 DEBUG(10, ("Found %s\n", converted));
800 result = converted;
801 converted = NULL;
802 } else {
803 errno = ENOENT;
805 fail:
806 if (result == NULL) {
807 saved_errno = errno;
809 TALLOC_FREE(converted);
810 TALLOC_FREE(insert);
811 TALLOC_FREE(slashes);
812 TALLOC_FREE(path);
813 if (saved_errno != 0) {
814 errno = saved_errno;
816 return result;
820 * Convert from a name as handed in via the SMB layer
821 * and a timestamp into the local path of the snapshot
822 * of the provided file at the provided time.
824 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
825 struct vfs_handle_struct *handle,
826 const char *name, time_t timestamp)
828 return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL);
832 modify a sbuf return to ensure that inodes in the shadow directory
833 are different from those in the main directory
835 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
836 SMB_STRUCT_STAT *sbuf)
838 struct shadow_copy2_config *config;
840 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
841 return);
843 if (config->fixinodes) {
844 /* some snapshot systems, like GPFS, return the name
845 device:inode for the snapshot files as the current
846 files. That breaks the 'restore' button in the shadow copy
847 GUI, as the client gets a sharing violation.
849 This is a crude way of allowing both files to be
850 open at once. It has a slight chance of inode
851 number collision, but I can't see a better approach
852 without significant VFS changes
854 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
855 .dsize = strlen(fname) };
856 uint32_t shash;
858 shash = tdb_jenkins_hash(&key) & 0xFF000000;
859 if (shash == 0) {
860 shash = 1;
862 sbuf->st_ex_ino ^= shash;
866 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
867 const char *fname,
868 const char *mask,
869 uint32_t attr)
871 time_t timestamp = 0;
872 char *stripped = NULL;
873 DIR *ret;
874 int saved_errno = 0;
875 char *conv;
877 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
878 &timestamp, &stripped)) {
879 return NULL;
881 if (timestamp == 0) {
882 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
884 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
885 TALLOC_FREE(stripped);
886 if (conv == NULL) {
887 return NULL;
889 ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
890 if (ret == NULL) {
891 saved_errno = errno;
893 TALLOC_FREE(conv);
894 if (saved_errno != 0) {
895 errno = saved_errno;
897 return ret;
900 static int shadow_copy2_rename(vfs_handle_struct *handle,
901 const struct smb_filename *smb_fname_src,
902 const struct smb_filename *smb_fname_dst)
904 time_t timestamp_src = 0;
905 time_t timestamp_dst = 0;
906 char *snappath_src = NULL;
907 char *snappath_dst = NULL;
909 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
910 smb_fname_src->base_name,
911 &timestamp_src, NULL, &snappath_src)) {
912 return -1;
914 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
915 smb_fname_dst->base_name,
916 &timestamp_dst, NULL, &snappath_dst)) {
917 return -1;
919 if (timestamp_src != 0) {
920 errno = EXDEV;
921 return -1;
923 if (timestamp_dst != 0) {
924 errno = EROFS;
925 return -1;
928 * Don't allow rename on already converted paths.
930 if (snappath_src != NULL) {
931 errno = EXDEV;
932 return -1;
934 if (snappath_dst != NULL) {
935 errno = EROFS;
936 return -1;
938 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
941 static int shadow_copy2_symlink(vfs_handle_struct *handle,
942 const char *oldname, const char *newname)
944 time_t timestamp_old = 0;
945 time_t timestamp_new = 0;
946 char *snappath_old = NULL;
947 char *snappath_new = NULL;
949 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname,
950 &timestamp_old, NULL, &snappath_old)) {
951 return -1;
953 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname,
954 &timestamp_new, NULL, &snappath_new)) {
955 return -1;
957 if ((timestamp_old != 0) || (timestamp_new != 0)) {
958 errno = EROFS;
959 return -1;
962 * Don't allow symlinks on already converted paths.
964 if ((snappath_old != NULL) || (snappath_new != NULL)) {
965 errno = EROFS;
966 return -1;
968 return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
971 static int shadow_copy2_link(vfs_handle_struct *handle,
972 const char *oldname, const char *newname)
974 time_t timestamp_old = 0;
975 time_t timestamp_new = 0;
976 char *snappath_old = NULL;
977 char *snappath_new = NULL;
979 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname,
980 &timestamp_old, NULL, &snappath_old)) {
981 return -1;
983 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname,
984 &timestamp_new, NULL, &snappath_new)) {
985 return -1;
987 if ((timestamp_old != 0) || (timestamp_new != 0)) {
988 errno = EROFS;
989 return -1;
992 * Don't allow links on already converted paths.
994 if ((snappath_old != NULL) || (snappath_new != NULL)) {
995 errno = EROFS;
996 return -1;
998 return SMB_VFS_NEXT_LINK(handle, oldname, newname);
1001 static int shadow_copy2_stat(vfs_handle_struct *handle,
1002 struct smb_filename *smb_fname)
1004 time_t timestamp = 0;
1005 char *stripped = NULL;
1006 char *tmp;
1007 int saved_errno = 0;
1008 int ret;
1010 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1011 smb_fname->base_name,
1012 &timestamp, &stripped)) {
1013 return -1;
1015 if (timestamp == 0) {
1016 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1019 tmp = smb_fname->base_name;
1020 smb_fname->base_name = shadow_copy2_convert(
1021 talloc_tos(), handle, stripped, timestamp);
1022 TALLOC_FREE(stripped);
1024 if (smb_fname->base_name == NULL) {
1025 smb_fname->base_name = tmp;
1026 return -1;
1029 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1030 if (ret == -1) {
1031 saved_errno = errno;
1034 TALLOC_FREE(smb_fname->base_name);
1035 smb_fname->base_name = tmp;
1037 if (ret == 0) {
1038 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1040 if (saved_errno != 0) {
1041 errno = saved_errno;
1043 return ret;
1046 static int shadow_copy2_lstat(vfs_handle_struct *handle,
1047 struct smb_filename *smb_fname)
1049 time_t timestamp = 0;
1050 char *stripped = NULL;
1051 char *tmp;
1052 int saved_errno = 0;
1053 int ret;
1055 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1056 smb_fname->base_name,
1057 &timestamp, &stripped)) {
1058 return -1;
1060 if (timestamp == 0) {
1061 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1064 tmp = smb_fname->base_name;
1065 smb_fname->base_name = shadow_copy2_convert(
1066 talloc_tos(), handle, stripped, timestamp);
1067 TALLOC_FREE(stripped);
1069 if (smb_fname->base_name == NULL) {
1070 smb_fname->base_name = tmp;
1071 return -1;
1074 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1075 if (ret == -1) {
1076 saved_errno = errno;
1079 TALLOC_FREE(smb_fname->base_name);
1080 smb_fname->base_name = tmp;
1082 if (ret == 0) {
1083 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1085 if (saved_errno != 0) {
1086 errno = saved_errno;
1088 return ret;
1091 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
1092 SMB_STRUCT_STAT *sbuf)
1094 time_t timestamp = 0;
1095 int ret;
1097 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1098 if (ret == -1) {
1099 return ret;
1101 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1102 fsp->fsp_name->base_name,
1103 &timestamp, NULL)) {
1104 return 0;
1106 if (timestamp != 0) {
1107 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
1109 return 0;
1112 static int shadow_copy2_open(vfs_handle_struct *handle,
1113 struct smb_filename *smb_fname, files_struct *fsp,
1114 int flags, mode_t mode)
1116 time_t timestamp = 0;
1117 char *stripped = NULL;
1118 char *tmp;
1119 int saved_errno = 0;
1120 int ret;
1122 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1123 smb_fname->base_name,
1124 &timestamp, &stripped)) {
1125 return -1;
1127 if (timestamp == 0) {
1128 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1131 tmp = smb_fname->base_name;
1132 smb_fname->base_name = shadow_copy2_convert(
1133 talloc_tos(), handle, stripped, timestamp);
1134 TALLOC_FREE(stripped);
1136 if (smb_fname->base_name == NULL) {
1137 smb_fname->base_name = tmp;
1138 return -1;
1141 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1142 if (ret == -1) {
1143 saved_errno = errno;
1146 TALLOC_FREE(smb_fname->base_name);
1147 smb_fname->base_name = tmp;
1149 if (saved_errno != 0) {
1150 errno = saved_errno;
1152 return ret;
1155 static int shadow_copy2_unlink(vfs_handle_struct *handle,
1156 const struct smb_filename *smb_fname)
1158 time_t timestamp = 0;
1159 char *stripped = NULL;
1160 int saved_errno = 0;
1161 int ret;
1162 struct smb_filename *conv;
1164 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1165 smb_fname->base_name,
1166 &timestamp, &stripped)) {
1167 return -1;
1169 if (timestamp == 0) {
1170 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1172 conv = cp_smb_filename(talloc_tos(), smb_fname);
1173 if (conv == NULL) {
1174 errno = ENOMEM;
1175 return -1;
1177 conv->base_name = shadow_copy2_convert(
1178 conv, handle, stripped, timestamp);
1179 TALLOC_FREE(stripped);
1180 if (conv->base_name == NULL) {
1181 return -1;
1183 ret = SMB_VFS_NEXT_UNLINK(handle, conv);
1184 if (ret == -1) {
1185 saved_errno = errno;
1187 TALLOC_FREE(conv);
1188 if (saved_errno != 0) {
1189 errno = saved_errno;
1191 return ret;
1194 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
1195 mode_t mode)
1197 time_t timestamp = 0;
1198 char *stripped = NULL;
1199 int saved_errno = 0;
1200 int ret;
1201 char *conv;
1203 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1204 &timestamp, &stripped)) {
1205 return -1;
1207 if (timestamp == 0) {
1208 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
1210 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1211 TALLOC_FREE(stripped);
1212 if (conv == NULL) {
1213 return -1;
1215 ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
1216 if (ret == -1) {
1217 saved_errno = errno;
1219 TALLOC_FREE(conv);
1220 if (saved_errno != 0) {
1221 errno = saved_errno;
1223 return ret;
1226 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
1227 uid_t uid, gid_t gid)
1229 time_t timestamp = 0;
1230 char *stripped = NULL;
1231 int saved_errno = 0;
1232 int ret;
1233 char *conv;
1235 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1236 &timestamp, &stripped)) {
1237 return -1;
1239 if (timestamp == 0) {
1240 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
1242 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1243 TALLOC_FREE(stripped);
1244 if (conv == NULL) {
1245 return -1;
1247 ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
1248 if (ret == -1) {
1249 saved_errno = errno;
1251 TALLOC_FREE(conv);
1252 if (saved_errno != 0) {
1253 errno = saved_errno;
1255 return ret;
1258 static void store_cwd_data(vfs_handle_struct *handle,
1259 const char *connectpath)
1261 struct shadow_copy2_config *config = NULL;
1262 char *cwd = NULL;
1264 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1265 return);
1267 TALLOC_FREE(config->shadow_cwd);
1268 cwd = SMB_VFS_NEXT_GETWD(handle);
1269 if (cwd == NULL) {
1270 smb_panic("getwd failed\n");
1272 DBG_DEBUG("shadow cwd = %s\n", cwd);
1273 config->shadow_cwd = talloc_strdup(config, cwd);
1274 SAFE_FREE(cwd);
1275 if (config->shadow_cwd == NULL) {
1276 smb_panic("talloc failed\n");
1278 TALLOC_FREE(config->shadow_connectpath);
1279 if (connectpath) {
1280 DBG_DEBUG("shadow conectpath = %s\n", connectpath);
1281 config->shadow_connectpath = talloc_strdup(config, connectpath);
1282 if (config->shadow_connectpath == NULL) {
1283 smb_panic("talloc failed\n");
1288 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1289 const char *fname)
1291 time_t timestamp = 0;
1292 char *stripped = NULL;
1293 char *snappath = NULL;
1294 int ret = -1;
1295 int saved_errno = 0;
1296 char *conv = NULL;
1297 size_t rootpath_len = 0;
1299 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, fname,
1300 &timestamp, &stripped, &snappath)) {
1301 return -1;
1303 if (stripped != NULL) {
1304 conv = shadow_copy2_do_convert(talloc_tos(),
1305 handle,
1306 stripped,
1307 timestamp,
1308 &rootpath_len);
1309 TALLOC_FREE(stripped);
1310 if (conv == NULL) {
1311 return -1;
1313 fname = conv;
1316 ret = SMB_VFS_NEXT_CHDIR(handle, fname);
1317 if (ret == -1) {
1318 saved_errno = errno;
1321 if (ret == 0) {
1322 if (conv != NULL && rootpath_len != 0) {
1323 conv[rootpath_len] = '\0';
1324 } else if (snappath != 0) {
1325 TALLOC_FREE(conv);
1326 conv = snappath;
1328 store_cwd_data(handle, conv);
1331 TALLOC_FREE(stripped);
1332 TALLOC_FREE(conv);
1334 if (saved_errno != 0) {
1335 errno = saved_errno;
1337 return ret;
1340 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1341 const struct smb_filename *smb_fname,
1342 struct smb_file_time *ft)
1344 time_t timestamp = 0;
1345 char *stripped = NULL;
1346 int saved_errno = 0;
1347 int ret;
1348 struct smb_filename *conv;
1350 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1351 smb_fname->base_name,
1352 &timestamp, &stripped)) {
1353 return -1;
1355 if (timestamp == 0) {
1356 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1358 conv = cp_smb_filename(talloc_tos(), smb_fname);
1359 if (conv == NULL) {
1360 errno = ENOMEM;
1361 return -1;
1363 conv->base_name = shadow_copy2_convert(
1364 conv, handle, stripped, timestamp);
1365 TALLOC_FREE(stripped);
1366 if (conv->base_name == NULL) {
1367 return -1;
1369 ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1370 if (ret == -1) {
1371 saved_errno = errno;
1373 TALLOC_FREE(conv);
1374 if (saved_errno != 0) {
1375 errno = saved_errno;
1377 return ret;
1380 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1381 const char *fname, char *buf, size_t bufsiz)
1383 time_t timestamp = 0;
1384 char *stripped = NULL;
1385 int saved_errno = 0;
1386 int ret;
1387 char *conv;
1389 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1390 &timestamp, &stripped)) {
1391 return -1;
1393 if (timestamp == 0) {
1394 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1396 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1397 TALLOC_FREE(stripped);
1398 if (conv == NULL) {
1399 return -1;
1401 ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1402 if (ret == -1) {
1403 saved_errno = errno;
1405 TALLOC_FREE(conv);
1406 if (saved_errno != 0) {
1407 errno = saved_errno;
1409 return ret;
1412 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1413 const char *fname, mode_t mode, SMB_DEV_T dev)
1415 time_t timestamp = 0;
1416 char *stripped = NULL;
1417 int saved_errno = 0;
1418 int ret;
1419 char *conv;
1421 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1422 &timestamp, &stripped)) {
1423 return -1;
1425 if (timestamp == 0) {
1426 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1428 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1429 TALLOC_FREE(stripped);
1430 if (conv == NULL) {
1431 return -1;
1433 ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1434 if (ret == -1) {
1435 saved_errno = errno;
1437 TALLOC_FREE(conv);
1438 if (saved_errno != 0) {
1439 errno = saved_errno;
1441 return ret;
1444 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1445 const char *fname)
1447 time_t timestamp = 0;
1448 char *stripped = NULL;
1449 char *tmp = NULL;
1450 char *result = NULL;
1451 int saved_errno = 0;
1453 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1454 &timestamp, &stripped)) {
1455 goto done;
1457 if (timestamp == 0) {
1458 return SMB_VFS_NEXT_REALPATH(handle, fname);
1461 tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1462 if (tmp == NULL) {
1463 goto done;
1466 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1468 done:
1469 if (result == NULL) {
1470 saved_errno = errno;
1472 TALLOC_FREE(tmp);
1473 TALLOC_FREE(stripped);
1474 if (saved_errno != 0) {
1475 errno = saved_errno;
1477 return result;
1481 * Check whether a given directory contains a
1482 * snapshot directory as direct subdirectory.
1483 * If yes, return the path of the snapshot-subdir,
1484 * otherwise return NULL.
1486 static char *have_snapdir(struct vfs_handle_struct *handle,
1487 const char *path)
1489 struct smb_filename smb_fname;
1490 int ret;
1491 struct shadow_copy2_config *config;
1493 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1494 return NULL);
1496 ZERO_STRUCT(smb_fname);
1497 smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1498 path, config->snapdir);
1499 if (smb_fname.base_name == NULL) {
1500 return NULL;
1503 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1504 if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1505 return smb_fname.base_name;
1507 TALLOC_FREE(smb_fname.base_name);
1508 return NULL;
1511 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1512 const char *path)
1514 struct smb_filename smb_fname;
1515 int ret;
1516 NTSTATUS status;
1518 ZERO_STRUCT(smb_fname);
1519 smb_fname.base_name = talloc_asprintf(talloc_tos(),
1520 "%s",
1521 path);
1522 if (smb_fname.base_name == NULL) {
1523 return false;
1526 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1527 if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1528 TALLOC_FREE(smb_fname.base_name);
1529 return false;
1532 status = smbd_check_access_rights(handle->conn,
1533 &smb_fname,
1534 false,
1535 SEC_DIR_LIST);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 DEBUG(0,("user does not have list permission "
1538 "on snapdir %s\n",
1539 smb_fname.base_name));
1540 TALLOC_FREE(smb_fname.base_name);
1541 return false;
1543 TALLOC_FREE(smb_fname.base_name);
1544 return true;
1548 * Find the snapshot directory (if any) for the given
1549 * filename (which is relative to the share).
1551 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1552 struct vfs_handle_struct *handle,
1553 struct smb_filename *smb_fname)
1555 char *path, *p;
1556 const char *snapdir;
1557 struct shadow_copy2_config *config;
1559 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1560 return NULL);
1563 * If the non-snapdisrseverywhere mode, we should not search!
1565 if (!config->snapdirseverywhere) {
1566 return config->snapshot_basepath;
1569 path = talloc_asprintf(mem_ctx, "%s/%s",
1570 handle->conn->connectpath,
1571 smb_fname->base_name);
1572 if (path == NULL) {
1573 return NULL;
1576 snapdir = have_snapdir(handle, path);
1577 if (snapdir != NULL) {
1578 TALLOC_FREE(path);
1579 return snapdir;
1582 while ((p = strrchr(path, '/')) && (p > path)) {
1584 p[0] = '\0';
1586 snapdir = have_snapdir(handle, path);
1587 if (snapdir != NULL) {
1588 TALLOC_FREE(path);
1589 return snapdir;
1592 TALLOC_FREE(path);
1593 return NULL;
1596 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1597 const char *name,
1598 char *gmt, size_t gmt_len)
1600 struct tm timestamp;
1601 time_t timestamp_t;
1602 unsigned long int timestamp_long;
1603 const char *fmt;
1604 struct shadow_copy2_config *config;
1606 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1607 return NULL);
1609 fmt = config->gmt_format;
1611 ZERO_STRUCT(timestamp);
1612 if (config->use_sscanf) {
1613 if (sscanf(name, fmt, &timestamp_long) != 1) {
1614 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1615 "no sscanf match %s: %s\n",
1616 fmt, name));
1617 return false;
1619 timestamp_t = timestamp_long;
1620 gmtime_r(&timestamp_t, &timestamp);
1621 } else {
1622 if (strptime(name, fmt, &timestamp) == NULL) {
1623 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1624 "no match %s: %s\n",
1625 fmt, name));
1626 return false;
1628 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1629 fmt, name));
1631 if (config->use_localtime) {
1632 timestamp.tm_isdst = -1;
1633 timestamp_t = mktime(&timestamp);
1634 gmtime_r(&timestamp_t, &timestamp);
1638 strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1639 return true;
1642 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1644 return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1647 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1649 return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1653 sort the shadow copy data in ascending or descending order
1655 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1656 struct shadow_copy_data *shadow_copy2_data)
1658 int (*cmpfunc)(const void *, const void *);
1659 const char *sort;
1660 struct shadow_copy2_config *config;
1662 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1663 return);
1665 sort = config->sort_order;
1666 if (sort == NULL) {
1667 return;
1670 if (strcmp(sort, "asc") == 0) {
1671 cmpfunc = shadow_copy2_label_cmp_asc;
1672 } else if (strcmp(sort, "desc") == 0) {
1673 cmpfunc = shadow_copy2_label_cmp_desc;
1674 } else {
1675 return;
1678 if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1679 shadow_copy2_data->labels)
1681 TYPESAFE_QSORT(shadow_copy2_data->labels,
1682 shadow_copy2_data->num_volumes,
1683 cmpfunc);
1687 static int shadow_copy2_get_shadow_copy_data(
1688 vfs_handle_struct *handle, files_struct *fsp,
1689 struct shadow_copy_data *shadow_copy2_data,
1690 bool labels)
1692 DIR *p;
1693 const char *snapdir;
1694 struct dirent *d;
1695 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1696 bool ret;
1698 snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1699 if (snapdir == NULL) {
1700 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1701 handle->conn->connectpath));
1702 errno = EINVAL;
1703 talloc_free(tmp_ctx);
1704 return -1;
1706 ret = check_access_snapdir(handle, snapdir);
1707 if (!ret) {
1708 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1709 errno = EACCES;
1710 talloc_free(tmp_ctx);
1711 return -1;
1714 p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1716 if (!p) {
1717 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1718 " - %s\n", snapdir, strerror(errno)));
1719 talloc_free(tmp_ctx);
1720 errno = ENOSYS;
1721 return -1;
1724 shadow_copy2_data->num_volumes = 0;
1725 shadow_copy2_data->labels = NULL;
1727 while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1728 char snapshot[GMT_NAME_LEN+1];
1729 SHADOW_COPY_LABEL *tlabels;
1732 * ignore names not of the right form in the snapshot
1733 * directory
1735 if (!shadow_copy2_snapshot_to_gmt(
1736 handle, d->d_name,
1737 snapshot, sizeof(snapshot))) {
1739 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1740 "ignoring %s\n", d->d_name));
1741 continue;
1743 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1744 d->d_name, snapshot));
1746 if (!labels) {
1747 /* the caller doesn't want the labels */
1748 shadow_copy2_data->num_volumes++;
1749 continue;
1752 tlabels = talloc_realloc(shadow_copy2_data,
1753 shadow_copy2_data->labels,
1754 SHADOW_COPY_LABEL,
1755 shadow_copy2_data->num_volumes+1);
1756 if (tlabels == NULL) {
1757 DEBUG(0,("shadow_copy2: out of memory\n"));
1758 SMB_VFS_NEXT_CLOSEDIR(handle, p);
1759 talloc_free(tmp_ctx);
1760 return -1;
1763 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1764 sizeof(*tlabels));
1766 shadow_copy2_data->num_volumes++;
1767 shadow_copy2_data->labels = tlabels;
1770 SMB_VFS_NEXT_CLOSEDIR(handle,p);
1772 shadow_copy2_sort_data(handle, shadow_copy2_data);
1774 talloc_free(tmp_ctx);
1775 return 0;
1778 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1779 struct files_struct *fsp,
1780 uint32_t security_info,
1781 TALLOC_CTX *mem_ctx,
1782 struct security_descriptor **ppdesc)
1784 time_t timestamp = 0;
1785 char *stripped = NULL;
1786 NTSTATUS status;
1787 char *conv;
1789 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1790 fsp->fsp_name->base_name,
1791 &timestamp, &stripped)) {
1792 return map_nt_error_from_unix(errno);
1794 if (timestamp == 0) {
1795 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1796 mem_ctx,
1797 ppdesc);
1799 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1800 TALLOC_FREE(stripped);
1801 if (conv == NULL) {
1802 return map_nt_error_from_unix(errno);
1804 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1805 mem_ctx, ppdesc);
1806 TALLOC_FREE(conv);
1807 return status;
1810 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1811 const char *fname,
1812 uint32_t security_info,
1813 TALLOC_CTX *mem_ctx,
1814 struct security_descriptor **ppdesc)
1816 time_t timestamp = 0;
1817 char *stripped = NULL;
1818 NTSTATUS status;
1819 char *conv;
1821 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1822 &timestamp, &stripped)) {
1823 return map_nt_error_from_unix(errno);
1825 if (timestamp == 0) {
1826 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1827 mem_ctx, ppdesc);
1829 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1830 TALLOC_FREE(stripped);
1831 if (conv == NULL) {
1832 return map_nt_error_from_unix(errno);
1834 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1835 mem_ctx, ppdesc);
1836 TALLOC_FREE(conv);
1837 return status;
1840 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1841 const char *fname, mode_t mode)
1843 time_t timestamp = 0;
1844 char *stripped = NULL;
1845 int saved_errno = 0;
1846 int ret;
1847 char *conv;
1849 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1850 &timestamp, &stripped)) {
1851 return -1;
1853 if (timestamp == 0) {
1854 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1856 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1857 TALLOC_FREE(stripped);
1858 if (conv == NULL) {
1859 return -1;
1861 ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1862 if (ret == -1) {
1863 saved_errno = errno;
1865 TALLOC_FREE(conv);
1866 if (saved_errno != 0) {
1867 errno = saved_errno;
1869 return ret;
1872 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1874 time_t timestamp = 0;
1875 char *stripped = NULL;
1876 int saved_errno = 0;
1877 int ret;
1878 char *conv;
1880 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1881 &timestamp, &stripped)) {
1882 return -1;
1884 if (timestamp == 0) {
1885 return SMB_VFS_NEXT_RMDIR(handle, fname);
1887 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1888 TALLOC_FREE(stripped);
1889 if (conv == NULL) {
1890 return -1;
1892 ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1893 if (ret == -1) {
1894 saved_errno = errno;
1896 TALLOC_FREE(conv);
1897 if (saved_errno != 0) {
1898 errno = saved_errno;
1900 return ret;
1903 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1904 unsigned int flags)
1906 time_t timestamp = 0;
1907 char *stripped = NULL;
1908 int saved_errno = 0;
1909 int ret;
1910 char *conv;
1912 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1913 &timestamp, &stripped)) {
1914 return -1;
1916 if (timestamp == 0) {
1917 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1919 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1920 TALLOC_FREE(stripped);
1921 if (conv == NULL) {
1922 return -1;
1924 ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1925 if (ret == -1) {
1926 saved_errno = errno;
1928 TALLOC_FREE(conv);
1929 if (saved_errno != 0) {
1930 errno = saved_errno;
1932 return ret;
1935 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1936 const char *fname, const char *aname,
1937 void *value, size_t size)
1939 time_t timestamp = 0;
1940 char *stripped = NULL;
1941 ssize_t ret;
1942 int saved_errno = 0;
1943 char *conv;
1945 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1946 &timestamp, &stripped)) {
1947 return -1;
1949 if (timestamp == 0) {
1950 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1951 size);
1953 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1954 TALLOC_FREE(stripped);
1955 if (conv == NULL) {
1956 return -1;
1958 ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1959 if (ret == -1) {
1960 saved_errno = errno;
1962 TALLOC_FREE(conv);
1963 if (saved_errno != 0) {
1964 errno = saved_errno;
1966 return ret;
1969 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1970 const char *fname,
1971 char *list, size_t size)
1973 time_t timestamp = 0;
1974 char *stripped = NULL;
1975 ssize_t ret;
1976 int saved_errno = 0;
1977 char *conv;
1979 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1980 &timestamp, &stripped)) {
1981 return -1;
1983 if (timestamp == 0) {
1984 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1986 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1987 TALLOC_FREE(stripped);
1988 if (conv == NULL) {
1989 return -1;
1991 ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1992 if (ret == -1) {
1993 saved_errno = errno;
1995 TALLOC_FREE(conv);
1996 if (saved_errno != 0) {
1997 errno = saved_errno;
1999 return ret;
2002 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
2003 const char *fname, const char *aname)
2005 time_t timestamp = 0;
2006 char *stripped = NULL;
2007 int saved_errno = 0;
2008 int ret;
2009 char *conv;
2011 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2012 &timestamp, &stripped)) {
2013 return -1;
2015 if (timestamp == 0) {
2016 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
2018 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2019 TALLOC_FREE(stripped);
2020 if (conv == NULL) {
2021 return -1;
2023 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
2024 if (ret == -1) {
2025 saved_errno = errno;
2027 TALLOC_FREE(conv);
2028 if (saved_errno != 0) {
2029 errno = saved_errno;
2031 return ret;
2034 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
2035 const char *fname,
2036 const char *aname, const void *value,
2037 size_t size, int flags)
2039 time_t timestamp = 0;
2040 char *stripped = NULL;
2041 ssize_t ret;
2042 int saved_errno = 0;
2043 char *conv;
2045 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2046 &timestamp, &stripped)) {
2047 return -1;
2049 if (timestamp == 0) {
2050 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
2051 flags);
2053 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2054 TALLOC_FREE(stripped);
2055 if (conv == NULL) {
2056 return -1;
2058 ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
2059 if (ret == -1) {
2060 saved_errno = errno;
2062 TALLOC_FREE(conv);
2063 if (saved_errno != 0) {
2064 errno = saved_errno;
2066 return ret;
2069 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
2070 const char *fname, mode_t mode)
2072 time_t timestamp = 0;
2073 char *stripped = NULL;
2074 ssize_t ret;
2075 int saved_errno = 0;
2076 char *conv;
2078 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2079 &timestamp, &stripped)) {
2080 return -1;
2082 if (timestamp == 0) {
2083 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
2085 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2086 TALLOC_FREE(stripped);
2087 if (conv == NULL) {
2088 return -1;
2090 ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
2091 if (ret == -1) {
2092 saved_errno = errno;
2094 TALLOC_FREE(conv);
2095 if (saved_errno != 0) {
2096 errno = saved_errno;
2098 return ret;
2101 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
2102 const char *path,
2103 const char *name,
2104 TALLOC_CTX *mem_ctx,
2105 char **found_name)
2107 time_t timestamp = 0;
2108 char *stripped = NULL;
2109 ssize_t ret;
2110 int saved_errno = 0;
2111 char *conv;
2113 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
2114 "name=[%s]\n", path, name));
2116 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2117 &timestamp, &stripped)) {
2118 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2119 return -1;
2121 if (timestamp == 0) {
2122 DEBUG(10, ("timestamp == 0\n"));
2123 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
2124 mem_ctx, found_name);
2126 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2127 TALLOC_FREE(stripped);
2128 if (conv == NULL) {
2129 DEBUG(10, ("shadow_copy2_convert failed\n"));
2130 return -1;
2132 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2133 "name=[%s]\n", conv, name));
2134 ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
2135 mem_ctx, found_name);
2136 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
2137 if (ret == -1) {
2138 saved_errno = errno;
2140 TALLOC_FREE(conv);
2141 if (saved_errno != 0) {
2142 errno = saved_errno;
2144 return ret;
2147 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
2148 const char *fname)
2150 time_t timestamp = 0;
2151 char *stripped = NULL;
2152 char *tmp = NULL;
2153 char *result = NULL;
2154 char *parent_dir = NULL;
2155 int saved_errno = 0;
2156 size_t rootpath_len = 0;
2157 struct shadow_copy2_config *config = NULL;
2159 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
2160 return NULL);
2162 DBG_DEBUG("Calc connect path for [%s]\n", fname);
2164 if (config->shadow_connectpath != NULL) {
2165 DBG_DEBUG("cached connect path is [%s]\n",
2166 config->shadow_connectpath);
2167 return config->shadow_connectpath;
2170 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2171 &timestamp, &stripped)) {
2172 goto done;
2174 if (timestamp == 0) {
2175 return SMB_VFS_NEXT_CONNECTPATH(handle, fname);
2178 tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
2179 &rootpath_len);
2180 if (tmp == NULL) {
2181 if (errno != ENOENT) {
2182 goto done;
2186 * If the converted path does not exist, and converting
2187 * the parent yields something that does exist, then
2188 * this path refers to something that has not been
2189 * created yet, relative to the parent path.
2190 * The snapshot finding is relative to the parent.
2191 * (usually snapshots are read/only but this is not
2192 * necessarily true).
2193 * This code also covers getting a wildcard in the
2194 * last component, because this function is called
2195 * prior to sanitizing the path, and in SMB1 we may
2196 * get wildcards in path names.
2198 if (!parent_dirname(talloc_tos(), stripped, &parent_dir,
2199 NULL)) {
2200 errno = ENOMEM;
2201 goto done;
2204 tmp = shadow_copy2_do_convert(talloc_tos(), handle, parent_dir,
2205 timestamp, &rootpath_len);
2206 if (tmp == NULL) {
2207 goto done;
2211 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
2212 (int)rootpath_len, tmp);
2214 tmp[rootpath_len] = '\0';
2215 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
2216 if (result == NULL) {
2217 goto done;
2221 * SMB_VFS_NEXT_REALPATH returns a malloc'ed string.
2222 * Don't leak memory.
2224 SAFE_FREE(config->shadow_realpath);
2225 config->shadow_realpath = result;
2227 DBG_DEBUG("connect path is [%s]\n", result);
2229 done:
2230 if (result == NULL) {
2231 saved_errno = errno;
2233 TALLOC_FREE(tmp);
2234 TALLOC_FREE(stripped);
2235 TALLOC_FREE(parent_dir);
2236 if (saved_errno != 0) {
2237 errno = saved_errno;
2239 return result;
2242 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
2243 const char *path, uint64_t *bsize,
2244 uint64_t *dfree, uint64_t *dsize)
2246 time_t timestamp = 0;
2247 char *stripped = NULL;
2248 ssize_t ret;
2249 int saved_errno = 0;
2250 char *conv;
2252 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2253 &timestamp, &stripped)) {
2254 return -1;
2256 if (timestamp == 0) {
2257 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2258 bsize, dfree, dsize);
2261 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2262 TALLOC_FREE(stripped);
2263 if (conv == NULL) {
2264 return -1;
2267 ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
2269 if (ret == -1) {
2270 saved_errno = errno;
2272 TALLOC_FREE(conv);
2273 if (saved_errno != 0) {
2274 errno = saved_errno;
2277 return ret;
2280 static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
2281 enum SMB_QUOTA_TYPE qtype, unid_t id,
2282 SMB_DISK_QUOTA *dq)
2284 time_t timestamp = 0;
2285 char *stripped = NULL;
2286 int ret;
2287 int saved_errno = 0;
2288 char *conv;
2290 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, &timestamp,
2291 &stripped)) {
2292 return -1;
2294 if (timestamp == 0) {
2295 return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
2298 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2299 TALLOC_FREE(stripped);
2300 if (conv == NULL) {
2301 return -1;
2304 ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
2306 if (ret == -1) {
2307 saved_errno = errno;
2309 TALLOC_FREE(conv);
2310 if (saved_errno != 0) {
2311 errno = saved_errno;
2314 return ret;
2317 static int shadow_copy2_config_destructor(struct shadow_copy2_config *config)
2319 SAFE_FREE(config->shadow_realpath);
2320 return 0;
2323 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
2324 const char *service, const char *user)
2326 struct shadow_copy2_config *config;
2327 int ret;
2328 const char *snapdir;
2329 const char *gmt_format;
2330 const char *sort_order;
2331 const char *basedir = NULL;
2332 const char *snapsharepath = NULL;
2333 const char *mount_point;
2335 DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
2336 (unsigned)handle->conn->cnum,
2337 handle->conn->connectpath));
2339 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2340 if (ret < 0) {
2341 return ret;
2344 config = talloc_zero(handle->conn, struct shadow_copy2_config);
2345 if (config == NULL) {
2346 DEBUG(0, ("talloc_zero() failed\n"));
2347 errno = ENOMEM;
2348 return -1;
2351 talloc_set_destructor(config, shadow_copy2_config_destructor);
2353 gmt_format = lp_parm_const_string(SNUM(handle->conn),
2354 "shadow", "format",
2355 GMT_FORMAT);
2356 config->gmt_format = talloc_strdup(config, gmt_format);
2357 if (config->gmt_format == NULL) {
2358 DEBUG(0, ("talloc_strdup() failed\n"));
2359 errno = ENOMEM;
2360 return -1;
2363 /* config->gmt_format must not contain a path separator. */
2364 if (strchr(config->gmt_format, '/') != NULL) {
2365 DEBUG(0, ("shadow:format %s must not contain a /"
2366 "character. Unable to initialize module.\n",
2367 config->gmt_format));
2368 errno = EINVAL;
2369 return -1;
2372 config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
2373 "shadow", "sscanf", false);
2375 config->use_localtime = lp_parm_bool(SNUM(handle->conn),
2376 "shadow", "localtime",
2377 false);
2379 snapdir = lp_parm_const_string(SNUM(handle->conn),
2380 "shadow", "snapdir",
2381 ".snapshots");
2382 config->snapdir = talloc_strdup(config, snapdir);
2383 if (config->snapdir == NULL) {
2384 DEBUG(0, ("talloc_strdup() failed\n"));
2385 errno = ENOMEM;
2386 return -1;
2389 config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
2390 "shadow",
2391 "snapdirseverywhere",
2392 false);
2394 config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
2395 "shadow", "crossmountpoints",
2396 false);
2398 if (config->crossmountpoints && !config->snapdirseverywhere) {
2399 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2400 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2403 config->fixinodes = lp_parm_bool(SNUM(handle->conn),
2404 "shadow", "fixinodes",
2405 false);
2407 sort_order = lp_parm_const_string(SNUM(handle->conn),
2408 "shadow", "sort", "desc");
2409 config->sort_order = talloc_strdup(config, sort_order);
2410 if (config->sort_order == NULL) {
2411 DEBUG(0, ("talloc_strdup() failed\n"));
2412 errno = ENOMEM;
2413 return -1;
2416 mount_point = lp_parm_const_string(SNUM(handle->conn),
2417 "shadow", "mountpoint", NULL);
2418 if (mount_point != NULL) {
2419 if (mount_point[0] != '/') {
2420 DEBUG(1, (__location__ " Warning: 'mountpoint' is "
2421 "relative ('%s'), but it has to be an "
2422 "absolute path. Ignoring provided value.\n",
2423 mount_point));
2424 mount_point = NULL;
2425 } else {
2426 char *p;
2427 p = strstr(handle->conn->connectpath, mount_point);
2428 if (p != handle->conn->connectpath) {
2429 DBG_WARNING("Warning: the share root (%s) is "
2430 "not a subdirectory of the "
2431 "specified mountpoint (%s). "
2432 "Ignoring provided value.\n",
2433 handle->conn->connectpath,
2434 mount_point);
2435 mount_point = NULL;
2440 if (mount_point != NULL) {
2441 config->mount_point = talloc_strdup(config, mount_point);
2442 if (config->mount_point == NULL) {
2443 DEBUG(0, (__location__ " talloc_strdup() failed\n"));
2444 return -1;
2446 } else {
2447 config->mount_point = shadow_copy2_find_mount_point(config,
2448 handle);
2449 if (config->mount_point == NULL) {
2450 DBG_WARNING("shadow_copy2_find_mount_point "
2451 "of the share root '%s' failed: %s\n",
2452 handle->conn->connectpath, strerror(errno));
2453 return -1;
2457 basedir = lp_parm_const_string(SNUM(handle->conn),
2458 "shadow", "basedir", NULL);
2460 if (basedir != NULL) {
2461 if (basedir[0] != '/') {
2462 DEBUG(1, (__location__ " Warning: 'basedir' is "
2463 "relative ('%s'), but it has to be an "
2464 "absolute path. Disabling basedir.\n",
2465 basedir));
2466 basedir = NULL;
2467 } else {
2468 char *p;
2469 p = strstr(basedir, config->mount_point);
2470 if (p != basedir) {
2471 DEBUG(1, ("Warning: basedir (%s) is not a "
2472 "subdirectory of the share root's "
2473 "mount point (%s). "
2474 "Disabling basedir\n",
2475 basedir, config->mount_point));
2476 basedir = NULL;
2481 if (config->snapdirseverywhere && basedir != NULL) {
2482 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2483 "with 'snapdirseverywhere'. Disabling basedir.\n"));
2484 basedir = NULL;
2487 snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
2488 "snapsharepath", NULL);
2489 if (snapsharepath != NULL) {
2490 if (snapsharepath[0] == '/') {
2491 DBG_WARNING("Warning: 'snapsharepath' is "
2492 "absolute ('%s'), but it has to be a "
2493 "relative path. Disabling snapsharepath.\n",
2494 snapsharepath);
2495 snapsharepath = NULL;
2497 if (config->snapdirseverywhere && snapsharepath != NULL) {
2498 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2499 "with 'snapdirseverywhere'. Disabling "
2500 "snapsharepath.\n");
2501 snapsharepath = NULL;
2505 if (basedir != NULL && snapsharepath != NULL) {
2506 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2507 "'basedir'. Disabling snapsharepath\n");
2508 snapsharepath = NULL;
2511 if (snapsharepath != NULL) {
2512 config->rel_connectpath = talloc_strdup(config, snapsharepath);
2513 if (config->rel_connectpath == NULL) {
2514 DBG_ERR("talloc_strdup() failed\n");
2515 errno = ENOMEM;
2516 return -1;
2520 if (basedir == NULL) {
2521 basedir = config->mount_point;
2524 if (config->rel_connectpath == NULL &&
2525 strlen(basedir) < strlen(handle->conn->connectpath)) {
2526 config->rel_connectpath = talloc_strdup(config,
2527 handle->conn->connectpath + strlen(basedir));
2528 if (config->rel_connectpath == NULL) {
2529 DEBUG(0, ("talloc_strdup() failed\n"));
2530 errno = ENOMEM;
2531 return -1;
2535 if (config->snapdir[0] == '/') {
2536 config->snapdir_absolute = true;
2538 if (config->snapdirseverywhere == true) {
2539 DEBUG(1, (__location__ " Warning: An absolute snapdir "
2540 "is incompatible with 'snapdirseverywhere', "
2541 "setting 'snapdirseverywhere' to false.\n"));
2542 config->snapdirseverywhere = false;
2545 if (config->crossmountpoints == true) {
2546 DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
2547 "is not supported with an absolute snapdir. "
2548 "Disabling it.\n"));
2549 config->crossmountpoints = false;
2552 config->snapshot_basepath = config->snapdir;
2553 } else {
2554 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2555 config->mount_point, config->snapdir);
2556 if (config->snapshot_basepath == NULL) {
2557 DEBUG(0, ("talloc_asprintf() failed\n"));
2558 errno = ENOMEM;
2559 return -1;
2563 trim_string(config->mount_point, NULL, "/");
2564 trim_string(config->rel_connectpath, "/", "/");
2565 trim_string(config->snapdir, NULL, "/");
2566 trim_string(config->snapshot_basepath, NULL, "/");
2568 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2569 " share root: '%s'\n"
2570 " mountpoint: '%s'\n"
2571 " rel share root: '%s'\n"
2572 " snapdir: '%s'\n"
2573 " snapshot base path: '%s'\n"
2574 " format: '%s'\n"
2575 " use sscanf: %s\n"
2576 " snapdirs everywhere: %s\n"
2577 " cross mountpoints: %s\n"
2578 " fix inodes: %s\n"
2579 " sort order: %s\n"
2581 handle->conn->connectpath,
2582 config->mount_point,
2583 config->rel_connectpath,
2584 config->snapdir,
2585 config->snapshot_basepath,
2586 config->gmt_format,
2587 config->use_sscanf ? "yes" : "no",
2588 config->snapdirseverywhere ? "yes" : "no",
2589 config->crossmountpoints ? "yes" : "no",
2590 config->fixinodes ? "yes" : "no",
2591 config->sort_order
2595 SMB_VFS_HANDLE_SET_DATA(handle, config,
2596 NULL, struct shadow_copy2_config,
2597 return -1);
2599 return 0;
2602 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2603 .connect_fn = shadow_copy2_connect,
2604 .opendir_fn = shadow_copy2_opendir,
2605 .disk_free_fn = shadow_copy2_disk_free,
2606 .get_quota_fn = shadow_copy2_get_quota,
2607 .rename_fn = shadow_copy2_rename,
2608 .link_fn = shadow_copy2_link,
2609 .symlink_fn = shadow_copy2_symlink,
2610 .stat_fn = shadow_copy2_stat,
2611 .lstat_fn = shadow_copy2_lstat,
2612 .fstat_fn = shadow_copy2_fstat,
2613 .open_fn = shadow_copy2_open,
2614 .unlink_fn = shadow_copy2_unlink,
2615 .chmod_fn = shadow_copy2_chmod,
2616 .chown_fn = shadow_copy2_chown,
2617 .chdir_fn = shadow_copy2_chdir,
2618 .ntimes_fn = shadow_copy2_ntimes,
2619 .readlink_fn = shadow_copy2_readlink,
2620 .mknod_fn = shadow_copy2_mknod,
2621 .realpath_fn = shadow_copy2_realpath,
2622 .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2623 .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2624 .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2625 .mkdir_fn = shadow_copy2_mkdir,
2626 .rmdir_fn = shadow_copy2_rmdir,
2627 .getxattr_fn = shadow_copy2_getxattr,
2628 .listxattr_fn = shadow_copy2_listxattr,
2629 .removexattr_fn = shadow_copy2_removexattr,
2630 .setxattr_fn = shadow_copy2_setxattr,
2631 .chmod_acl_fn = shadow_copy2_chmod_acl,
2632 .chflags_fn = shadow_copy2_chflags,
2633 .get_real_filename_fn = shadow_copy2_get_real_filename,
2634 .connectpath_fn = shadow_copy2_connectpath,
2637 NTSTATUS vfs_shadow_copy2_init(void);
2638 NTSTATUS vfs_shadow_copy2_init(void)
2640 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2641 "shadow_copy2", &vfs_shadow_copy2_fns);