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.
33 #include "smbd/smbd.h"
34 #include "system/filesys.h"
35 #include "include/ntioctl.h"
38 struct shadow_copy2_config {
43 bool snapdirseverywhere;
44 bool crossmountpoints;
47 bool snapdir_absolute;
50 char *rel_connectpath; /* share root, relative to the basedir */
51 char *snapshot_basepath; /* the absolute version of snapdir */
54 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
56 unsigned *pnum_offsets)
65 while ((p = strchr(p, '/')) != NULL) {
70 offsets = talloc_array(mem_ctx, size_t, num_offsets);
71 if (offsets == NULL) {
77 while ((p = strchr(p, '/')) != NULL) {
78 offsets[num_offsets] = p-str;
84 *pnum_offsets = num_offsets;
89 * Given a timestamp, build the posix level GMT-tag string
90 * based on the configurable format.
92 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
94 char *snaptime_string,
99 struct shadow_copy2_config *config;
101 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
104 if (config->use_sscanf) {
105 snaptime_len = snprintf(snaptime_string,
108 (unsigned long)snapshot);
109 if (snaptime_len <= 0) {
110 DEBUG(10, ("snprintf failed\n"));
114 if (config->use_localtime) {
115 if (localtime_r(&snapshot, &snap_tm) == 0) {
116 DEBUG(10, ("gmtime_r failed\n"));
120 if (gmtime_r(&snapshot, &snap_tm) == 0) {
121 DEBUG(10, ("gmtime_r failed\n"));
125 snaptime_len = strftime(snaptime_string,
129 if (snaptime_len == 0) {
130 DEBUG(10, ("strftime failed\n"));
139 * Given a timestamp, build the string to insert into a path
140 * as a path component for creating the local path to the
141 * snapshot at the given timestamp of the input path.
143 * In the case of a parallel snapdir (specified with an
144 * absolute path), this is the inital portion of the
145 * local path of any snapshot file. The complete path is
146 * obtained by appending the portion of the file's path
147 * below the share root's mountpoint.
149 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
150 struct vfs_handle_struct *handle,
153 fstring snaptime_string;
154 size_t snaptime_len = 0;
156 struct shadow_copy2_config *config;
158 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
161 snaptime_len = shadow_copy2_posix_gmt_string(handle,
164 sizeof(snaptime_string));
165 if (snaptime_len <= 0) {
169 if (config->snapdir_absolute) {
170 result = talloc_asprintf(mem_ctx, "%s/%s",
171 config->snapdir, snaptime_string);
173 result = talloc_asprintf(mem_ctx, "/%s/%s",
174 config->snapdir, snaptime_string);
176 if (result == NULL) {
177 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
184 * Build the posix snapshot path for the connection
185 * at the given timestamp, i.e. the absolute posix path
186 * that contains the snapshot for this file system.
188 * This only applies to classical case, i.e. not
189 * to the "snapdirseverywhere" mode.
191 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
192 struct vfs_handle_struct *handle,
195 fstring snaptime_string;
196 size_t snaptime_len = 0;
198 struct shadow_copy2_config *config;
200 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
203 snaptime_len = shadow_copy2_posix_gmt_string(handle,
206 sizeof(snaptime_string));
207 if (snaptime_len <= 0) {
211 result = talloc_asprintf(mem_ctx, "%s/%s",
212 config->snapshot_basepath, snaptime_string);
213 if (result == NULL) {
214 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
221 * Strip a snapshot component from a filename as
222 * handed in via the smb layer.
223 * Returns the parsed timestamp and the stripped filename.
225 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
226 struct vfs_handle_struct *handle,
236 size_t rest_len, dst_len;
237 struct shadow_copy2_config *config;
240 ptrdiff_t len_before_gmt;
242 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
245 DEBUG(10, (__location__ ": enter path '%s'\n", name));
247 p = strstr_m(name, "@GMT-");
249 DEBUG(11, ("@GMT not found\n"));
252 if ((p > name) && (p[-1] != '/')) {
253 /* the GMT-token does not start a path-component */
254 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
255 p, name, (int)p[-1]));
260 * Figure out whether we got an already converted string. One
261 * case where this happens is in a smb2 create call with the
262 * mxac create blob set. We do the get_acl call on
263 * fsp->fsp_name, which is already converted. We are converted
264 * if we got a file name of the form ".snapshots/@GMT-",
265 * i.e. ".snapshots/" precedes "p".
268 snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
270 snapdirlen = strlen(snapdir);
271 len_before_gmt = p - name;
273 if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
274 const char *parent_snapdir = p - (snapdirlen+1);
276 DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
278 if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
279 DEBUG(10, ("name=%s is already converted\n", name));
283 q = strptime(p, GMT_FORMAT, &tm);
285 DEBUG(10, ("strptime failed\n"));
289 timestamp = timegm(&tm);
290 if (timestamp == (time_t)-1) {
291 DEBUG(10, ("timestamp==-1\n"));
296 * The name consists of only the GMT token or the GMT
297 * token is at the end of the path. XP seems to send
298 * @GMT- at the end under certain circumstances even
299 * with a path prefix.
301 if (pstripped != NULL) {
302 stripped = talloc_strndup(mem_ctx, name, p - name);
303 if (stripped == NULL) {
306 *pstripped = stripped;
308 *ptimestamp = timestamp;
313 * It is not a complete path component, i.e. the path
314 * component continues after the gmt-token.
316 DEBUG(10, ("q[0] = %d\n", (int)q[0]));
321 rest_len = strlen(q);
322 dst_len = (p-name) + rest_len;
324 if (config->snapdirseverywhere) {
327 insert = shadow_copy2_insert_string(talloc_tos(), handle,
329 if (insert == NULL) {
334 DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
336 "insert string '%s'\n", name, insert));
338 have_insert = (strstr(name, insert+1) != NULL);
339 DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
340 (int)have_insert, name, insert+1));
342 DEBUG(10, (__location__ ": insert string '%s' found in "
343 "path '%s' found in snapdirseverywhere mode "
344 "==> already converted\n", insert, name));
353 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
356 if (snapshot_path == NULL) {
361 DEBUG(10, (__location__ " path: '%s'.\n"
362 "snapshot path: '%s'\n", name, snapshot_path));
364 s = strstr(name, snapshot_path);
367 * this starts with "snapshot_basepath/GMT-Token"
368 * so it is already a converted absolute
369 * path. Don't process further.
371 DEBUG(10, (__location__ ": path '%s' starts with "
372 "snapshot path '%s' (not in "
373 "snapdirseverywhere mode) ==> "
374 "already converted\n", name, snapshot_path));
375 talloc_free(snapshot_path);
378 talloc_free(snapshot_path);
381 if (pstripped != NULL) {
382 stripped = talloc_array(mem_ctx, char, dst_len+1);
383 if (stripped == NULL) {
388 memcpy(stripped, name, p-name);
391 memcpy(stripped + (p-name), q, rest_len);
393 stripped[dst_len] = '\0';
394 *pstripped = stripped;
396 *ptimestamp = timestamp;
403 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
404 vfs_handle_struct *handle)
406 char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
411 if (stat(path, &st) != 0) {
418 while ((p = strrchr(path, '/')) && p > path) {
420 if (stat(path, &st) != 0) {
424 if (st.st_dev != dev) {
434 * Convert from a name as handed in via the SMB layer
435 * and a timestamp into the local path of the snapshot
436 * of the provided file at the provided time.
438 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
439 struct vfs_handle_struct *handle,
440 const char *name, time_t timestamp)
442 struct smb_filename converted_fname;
444 size_t *slashes = NULL;
445 unsigned num_slashes;
449 char *converted = NULL;
453 struct shadow_copy2_config *config;
455 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
458 DEBUG(10, ("converting '%s'\n", name));
460 if (!config->snapdirseverywhere) {
464 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
467 if (snapshot_path == NULL) {
471 if (config->rel_connectpath == NULL) {
472 converted = talloc_asprintf(mem_ctx, "%s/%s",
473 snapshot_path, name);
475 converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
477 config->rel_connectpath,
480 if (converted == NULL) {
484 ZERO_STRUCT(converted_fname);
485 converted_fname.base_name = converted;
487 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
488 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
490 ret, ret == 0 ? "ok" : strerror(errno)));
492 DEBUG(10, ("Found %s\n", converted));
500 /* never reached ... */
504 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
506 path = talloc_asprintf(
507 mem_ctx, "%s/%s", handle->conn->connectpath, name);
513 pathlen = talloc_get_size(path)-1;
515 if (!shadow_copy2_find_slashes(talloc_tos(), path,
516 &slashes, &num_slashes)) {
520 insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
521 if (insert == NULL) {
524 insertlen = talloc_get_size(insert)-1;
527 * Note: We deliberatly don't expensively initialize the
528 * array with talloc_zero here: Putting zero into
529 * converted[pathlen+insertlen] below is sufficient, because
530 * in the following for loop, the insert string is inserted
531 * at various slash places. So the memory up to position
532 * pathlen+insertlen will always be initialized when the
533 * converted string is used.
535 converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
536 if (converted == NULL) {
540 if (path[pathlen-1] != '/') {
542 * Append a fake slash to find the snapshot root
545 tmp = talloc_realloc(talloc_tos(), slashes,
546 size_t, num_slashes+1);
551 slashes[num_slashes] = pathlen;
557 if (!config->crossmountpoints) {
558 min_offset = strlen(config->mount_point);
561 memcpy(converted, path, pathlen+1);
562 converted[pathlen+insertlen] = '\0';
564 ZERO_STRUCT(converted_fname);
565 converted_fname.base_name = converted;
567 for (i = num_slashes-1; i>=0; i--) {
573 if (offset < min_offset) {
578 memcpy(converted+offset, insert, insertlen);
581 memcpy(converted+offset, path + slashes[i],
582 pathlen - slashes[i]);
584 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
586 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
588 ret, ret == 0 ? "ok" : strerror(errno)));
593 if (errno == ENOTDIR) {
595 * This is a valid condition: We appended the
596 * .snaphots/@GMT.. to a file name. Just try
597 * with the upper levels.
601 if (errno != ENOENT) {
602 /* Other problem than "not found" */
611 DEBUG(10, ("Found %s\n", converted));
619 TALLOC_FREE(converted);
621 TALLOC_FREE(slashes);
628 modify a sbuf return to ensure that inodes in the shadow directory
629 are different from those in the main directory
631 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
632 SMB_STRUCT_STAT *sbuf)
634 struct shadow_copy2_config *config;
636 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
639 if (config->fixinodes) {
640 /* some snapshot systems, like GPFS, return the name
641 device:inode for the snapshot files as the current
642 files. That breaks the 'restore' button in the shadow copy
643 GUI, as the client gets a sharing violation.
645 This is a crude way of allowing both files to be
646 open at once. It has a slight chance of inode
647 number collision, but I can't see a better approach
648 without significant VFS changes
650 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
651 .dsize = strlen(fname) };
654 shash = tdb_jenkins_hash(&key) & 0xFF000000;
658 sbuf->st_ex_ino ^= shash;
662 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
673 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
674 ×tamp, &stripped)) {
677 if (timestamp == 0) {
678 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
680 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
681 TALLOC_FREE(stripped);
685 ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
692 static int shadow_copy2_rename(vfs_handle_struct *handle,
693 const struct smb_filename *smb_fname_src,
694 const struct smb_filename *smb_fname_dst)
696 time_t timestamp_src, timestamp_dst;
698 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
699 smb_fname_src->base_name,
700 ×tamp_src, NULL)) {
703 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
704 smb_fname_dst->base_name,
705 ×tamp_dst, NULL)) {
708 if (timestamp_src != 0) {
712 if (timestamp_dst != 0) {
716 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
719 static int shadow_copy2_symlink(vfs_handle_struct *handle,
720 const char *oldname, const char *newname)
722 time_t timestamp_old, timestamp_new;
724 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
725 ×tamp_old, NULL)) {
728 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
729 ×tamp_new, NULL)) {
732 if ((timestamp_old != 0) || (timestamp_new != 0)) {
736 return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
739 static int shadow_copy2_link(vfs_handle_struct *handle,
740 const char *oldname, const char *newname)
742 time_t timestamp_old, timestamp_new;
744 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
745 ×tamp_old, NULL)) {
748 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
749 ×tamp_new, NULL)) {
752 if ((timestamp_old != 0) || (timestamp_new != 0)) {
756 return SMB_VFS_NEXT_LINK(handle, oldname, newname);
759 static int shadow_copy2_stat(vfs_handle_struct *handle,
760 struct smb_filename *smb_fname)
763 char *stripped, *tmp;
764 int ret, saved_errno;
766 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
767 smb_fname->base_name,
768 ×tamp, &stripped)) {
771 if (timestamp == 0) {
772 return SMB_VFS_NEXT_STAT(handle, smb_fname);
775 tmp = smb_fname->base_name;
776 smb_fname->base_name = shadow_copy2_convert(
777 talloc_tos(), handle, stripped, timestamp);
778 TALLOC_FREE(stripped);
780 if (smb_fname->base_name == NULL) {
781 smb_fname->base_name = tmp;
785 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
788 TALLOC_FREE(smb_fname->base_name);
789 smb_fname->base_name = tmp;
792 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
798 static int shadow_copy2_lstat(vfs_handle_struct *handle,
799 struct smb_filename *smb_fname)
802 char *stripped, *tmp;
803 int ret, saved_errno;
805 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
806 smb_fname->base_name,
807 ×tamp, &stripped)) {
810 if (timestamp == 0) {
811 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
814 tmp = smb_fname->base_name;
815 smb_fname->base_name = shadow_copy2_convert(
816 talloc_tos(), handle, stripped, timestamp);
817 TALLOC_FREE(stripped);
819 if (smb_fname->base_name == NULL) {
820 smb_fname->base_name = tmp;
824 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
827 TALLOC_FREE(smb_fname->base_name);
828 smb_fname->base_name = tmp;
831 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
837 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
838 SMB_STRUCT_STAT *sbuf)
843 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
847 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
848 fsp->fsp_name->base_name,
852 if (timestamp != 0) {
853 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
858 static int shadow_copy2_open(vfs_handle_struct *handle,
859 struct smb_filename *smb_fname, files_struct *fsp,
860 int flags, mode_t mode)
863 char *stripped, *tmp;
864 int ret, saved_errno;
866 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
867 smb_fname->base_name,
868 ×tamp, &stripped)) {
871 if (timestamp == 0) {
872 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
875 tmp = smb_fname->base_name;
876 smb_fname->base_name = shadow_copy2_convert(
877 talloc_tos(), handle, stripped, timestamp);
878 TALLOC_FREE(stripped);
880 if (smb_fname->base_name == NULL) {
881 smb_fname->base_name = tmp;
885 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
888 TALLOC_FREE(smb_fname->base_name);
889 smb_fname->base_name = tmp;
895 static int shadow_copy2_unlink(vfs_handle_struct *handle,
896 const struct smb_filename *smb_fname)
900 int ret, saved_errno;
901 struct smb_filename *conv;
903 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
904 smb_fname->base_name,
905 ×tamp, &stripped)) {
908 if (timestamp == 0) {
909 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
911 conv = cp_smb_filename(talloc_tos(), smb_fname);
916 conv->base_name = shadow_copy2_convert(
917 conv, handle, stripped, timestamp);
918 TALLOC_FREE(stripped);
919 if (conv->base_name == NULL) {
922 ret = SMB_VFS_NEXT_UNLINK(handle, conv);
929 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
934 int ret, saved_errno;
937 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
938 ×tamp, &stripped)) {
941 if (timestamp == 0) {
942 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
944 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
945 TALLOC_FREE(stripped);
949 ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
956 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
957 uid_t uid, gid_t gid)
961 int ret, saved_errno;
964 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
965 ×tamp, &stripped)) {
968 if (timestamp == 0) {
969 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
971 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
972 TALLOC_FREE(stripped);
976 ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
983 static int shadow_copy2_chdir(vfs_handle_struct *handle,
988 int ret, saved_errno;
991 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
992 ×tamp, &stripped)) {
995 if (timestamp == 0) {
996 return SMB_VFS_NEXT_CHDIR(handle, fname);
998 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
999 TALLOC_FREE(stripped);
1003 ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1004 saved_errno = errno;
1006 errno = saved_errno;
1010 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1011 const struct smb_filename *smb_fname,
1012 struct smb_file_time *ft)
1016 int ret, saved_errno;
1017 struct smb_filename *conv;
1019 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1020 smb_fname->base_name,
1021 ×tamp, &stripped)) {
1024 if (timestamp == 0) {
1025 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1027 conv = cp_smb_filename(talloc_tos(), smb_fname);
1032 conv->base_name = shadow_copy2_convert(
1033 conv, handle, stripped, timestamp);
1034 TALLOC_FREE(stripped);
1035 if (conv->base_name == NULL) {
1038 ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1039 saved_errno = errno;
1041 errno = saved_errno;
1045 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1046 const char *fname, char *buf, size_t bufsiz)
1050 int ret, saved_errno;
1053 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1054 ×tamp, &stripped)) {
1057 if (timestamp == 0) {
1058 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1060 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1061 TALLOC_FREE(stripped);
1065 ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1066 saved_errno = errno;
1068 errno = saved_errno;
1072 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1073 const char *fname, mode_t mode, SMB_DEV_T dev)
1077 int ret, saved_errno;
1080 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1081 ×tamp, &stripped)) {
1084 if (timestamp == 0) {
1085 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1087 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1088 TALLOC_FREE(stripped);
1092 ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1093 saved_errno = errno;
1095 errno = saved_errno;
1099 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1103 char *stripped = NULL;
1105 char *result = NULL;
1106 char *inserted = NULL;
1107 char *inserted_to, *inserted_end;
1110 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1111 ×tamp, &stripped)) {
1114 if (timestamp == 0) {
1115 return SMB_VFS_NEXT_REALPATH(handle, fname);
1118 tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1123 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1124 if (result == NULL) {
1129 * Take away what we've inserted. This removes the @GMT-thingy
1130 * completely, but will give a path under the share root.
1132 inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
1133 if (inserted == NULL) {
1136 inserted_to = strstr_m(result, inserted);
1137 if (inserted_to == NULL) {
1138 DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
1141 inserted_end = inserted_to + talloc_get_size(inserted) - 1;
1142 memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
1145 saved_errno = errno;
1146 TALLOC_FREE(inserted);
1148 TALLOC_FREE(stripped);
1149 errno = saved_errno;
1154 * Check whether a given directory contains a
1155 * snapshot directory as direct subdirectory.
1156 * If yes, return the path of the snapshot-subdir,
1157 * otherwise return NULL.
1159 static char *have_snapdir(struct vfs_handle_struct *handle,
1162 struct smb_filename smb_fname;
1164 struct shadow_copy2_config *config;
1166 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1169 ZERO_STRUCT(smb_fname);
1170 smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1171 path, config->snapdir);
1172 if (smb_fname.base_name == NULL) {
1176 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1177 if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1178 return smb_fname.base_name;
1180 TALLOC_FREE(smb_fname.base_name);
1184 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1187 struct smb_filename smb_fname;
1191 ZERO_STRUCT(smb_fname);
1192 smb_fname.base_name = talloc_asprintf(talloc_tos(),
1195 if (smb_fname.base_name == NULL) {
1199 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1200 if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1201 TALLOC_FREE(smb_fname.base_name);
1205 status = smbd_check_access_rights(handle->conn,
1209 if (!NT_STATUS_IS_OK(status)) {
1210 DEBUG(0,("user does not have list permission "
1212 smb_fname.base_name));
1213 TALLOC_FREE(smb_fname.base_name);
1216 TALLOC_FREE(smb_fname.base_name);
1221 * Find the snapshot directory (if any) for the given
1222 * filename (which is relative to the share).
1224 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1225 struct vfs_handle_struct *handle,
1226 struct smb_filename *smb_fname)
1229 const char *snapdir;
1230 struct shadow_copy2_config *config;
1232 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1236 * If the non-snapdisrseverywhere mode, we should not search!
1238 if (!config->snapdirseverywhere) {
1239 return config->snapshot_basepath;
1242 path = talloc_asprintf(mem_ctx, "%s/%s",
1243 handle->conn->connectpath,
1244 smb_fname->base_name);
1249 snapdir = have_snapdir(handle, path);
1250 if (snapdir != NULL) {
1255 while ((p = strrchr(path, '/')) && (p > path)) {
1259 snapdir = have_snapdir(handle, path);
1260 if (snapdir != NULL) {
1269 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1271 char *gmt, size_t gmt_len)
1273 struct tm timestamp;
1275 unsigned long int timestamp_long;
1277 struct shadow_copy2_config *config;
1279 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1282 fmt = config->gmt_format;
1284 ZERO_STRUCT(timestamp);
1285 if (config->use_sscanf) {
1286 if (sscanf(name, fmt, ×tamp_long) != 1) {
1287 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1288 "no sscanf match %s: %s\n",
1292 timestamp_t = timestamp_long;
1293 gmtime_r(×tamp_t, ×tamp);
1295 if (strptime(name, fmt, ×tamp) == NULL) {
1296 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1297 "no match %s: %s\n",
1301 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1304 if (config->use_localtime) {
1305 timestamp.tm_isdst = -1;
1306 timestamp_t = mktime(×tamp);
1307 gmtime_r(×tamp_t, ×tamp);
1311 strftime(gmt, gmt_len, GMT_FORMAT, ×tamp);
1315 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1317 return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1320 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1322 return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1326 sort the shadow copy data in ascending or descending order
1328 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1329 struct shadow_copy_data *shadow_copy2_data)
1331 int (*cmpfunc)(const void *, const void *);
1333 struct shadow_copy2_config *config;
1335 SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1338 sort = config->sort_order;
1343 if (strcmp(sort, "asc") == 0) {
1344 cmpfunc = shadow_copy2_label_cmp_asc;
1345 } else if (strcmp(sort, "desc") == 0) {
1346 cmpfunc = shadow_copy2_label_cmp_desc;
1351 if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1352 shadow_copy2_data->labels)
1354 TYPESAFE_QSORT(shadow_copy2_data->labels,
1355 shadow_copy2_data->num_volumes,
1360 static int shadow_copy2_get_shadow_copy_data(
1361 vfs_handle_struct *handle, files_struct *fsp,
1362 struct shadow_copy_data *shadow_copy2_data,
1366 const char *snapdir;
1368 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1371 snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1372 if (snapdir == NULL) {
1373 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1374 handle->conn->connectpath));
1376 talloc_free(tmp_ctx);
1379 ret = check_access_snapdir(handle, snapdir);
1381 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1383 talloc_free(tmp_ctx);
1387 p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1390 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1391 " - %s\n", snapdir, strerror(errno)));
1392 talloc_free(tmp_ctx);
1397 shadow_copy2_data->num_volumes = 0;
1398 shadow_copy2_data->labels = NULL;
1400 while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1401 char snapshot[GMT_NAME_LEN+1];
1402 SHADOW_COPY_LABEL *tlabels;
1405 * ignore names not of the right form in the snapshot
1408 if (!shadow_copy2_snapshot_to_gmt(
1410 snapshot, sizeof(snapshot))) {
1412 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1413 "ignoring %s\n", d->d_name));
1416 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1417 d->d_name, snapshot));
1420 /* the caller doesn't want the labels */
1421 shadow_copy2_data->num_volumes++;
1425 tlabels = talloc_realloc(shadow_copy2_data,
1426 shadow_copy2_data->labels,
1428 shadow_copy2_data->num_volumes+1);
1429 if (tlabels == NULL) {
1430 DEBUG(0,("shadow_copy2: out of memory\n"));
1431 SMB_VFS_NEXT_CLOSEDIR(handle, p);
1432 talloc_free(tmp_ctx);
1436 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1439 shadow_copy2_data->num_volumes++;
1440 shadow_copy2_data->labels = tlabels;
1443 SMB_VFS_NEXT_CLOSEDIR(handle,p);
1445 shadow_copy2_sort_data(handle, shadow_copy2_data);
1447 talloc_free(tmp_ctx);
1451 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1452 struct files_struct *fsp,
1453 uint32_t security_info,
1454 TALLOC_CTX *mem_ctx,
1455 struct security_descriptor **ppdesc)
1462 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1463 fsp->fsp_name->base_name,
1464 ×tamp, &stripped)) {
1465 return map_nt_error_from_unix(errno);
1467 if (timestamp == 0) {
1468 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1472 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1473 TALLOC_FREE(stripped);
1475 return map_nt_error_from_unix(errno);
1477 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1483 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1485 uint32_t security_info,
1486 TALLOC_CTX *mem_ctx,
1487 struct security_descriptor **ppdesc)
1494 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1495 ×tamp, &stripped)) {
1496 return map_nt_error_from_unix(errno);
1498 if (timestamp == 0) {
1499 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1502 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1503 TALLOC_FREE(stripped);
1505 return map_nt_error_from_unix(errno);
1507 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1513 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1514 const char *fname, mode_t mode)
1518 int ret, saved_errno;
1521 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1522 ×tamp, &stripped)) {
1525 if (timestamp == 0) {
1526 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1528 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1529 TALLOC_FREE(stripped);
1533 ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1534 saved_errno = errno;
1536 errno = saved_errno;
1540 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1544 int ret, saved_errno;
1547 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1548 ×tamp, &stripped)) {
1551 if (timestamp == 0) {
1552 return SMB_VFS_NEXT_RMDIR(handle, fname);
1554 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1555 TALLOC_FREE(stripped);
1559 ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1560 saved_errno = errno;
1562 errno = saved_errno;
1566 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1571 int ret, saved_errno;
1574 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1575 ×tamp, &stripped)) {
1578 if (timestamp == 0) {
1579 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1581 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1582 TALLOC_FREE(stripped);
1586 ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1587 saved_errno = errno;
1589 errno = saved_errno;
1593 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1594 const char *fname, const char *aname,
1595 void *value, size_t size)
1603 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1604 ×tamp, &stripped)) {
1607 if (timestamp == 0) {
1608 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1611 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1612 TALLOC_FREE(stripped);
1616 ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1617 saved_errno = errno;
1619 errno = saved_errno;
1623 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1625 char *list, size_t size)
1633 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1634 ×tamp, &stripped)) {
1637 if (timestamp == 0) {
1638 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1640 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1641 TALLOC_FREE(stripped);
1645 ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1646 saved_errno = errno;
1648 errno = saved_errno;
1652 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1653 const char *fname, const char *aname)
1657 int ret, saved_errno;
1660 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1661 ×tamp, &stripped)) {
1664 if (timestamp == 0) {
1665 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1667 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1668 TALLOC_FREE(stripped);
1672 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1673 saved_errno = errno;
1675 errno = saved_errno;
1679 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1681 const char *aname, const void *value,
1682 size_t size, int flags)
1690 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1691 ×tamp, &stripped)) {
1694 if (timestamp == 0) {
1695 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1698 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1699 TALLOC_FREE(stripped);
1703 ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1704 saved_errno = errno;
1706 errno = saved_errno;
1710 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1711 const char *fname, mode_t mode)
1719 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1720 ×tamp, &stripped)) {
1723 if (timestamp == 0) {
1724 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1726 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1727 TALLOC_FREE(stripped);
1731 ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1732 saved_errno = errno;
1734 errno = saved_errno;
1738 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1741 TALLOC_CTX *mem_ctx,
1750 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
1751 "name=[%s]\n", path, name));
1753 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1754 ×tamp, &stripped)) {
1755 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
1758 if (timestamp == 0) {
1759 DEBUG(10, ("timestamp == 0\n"));
1760 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1761 mem_ctx, found_name);
1763 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1764 TALLOC_FREE(stripped);
1766 DEBUG(10, ("shadow_copy2_convert failed\n"));
1769 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
1770 "name=[%s]\n", conv, name));
1771 ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1772 mem_ctx, found_name);
1773 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
1774 saved_errno = errno;
1776 errno = saved_errno;
1780 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
1781 const char *path, uint64_t *bsize,
1782 uint64_t *dfree, uint64_t *dsize)
1790 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1791 ×tamp, &stripped)) {
1794 if (timestamp == 0) {
1795 return SMB_VFS_NEXT_DISK_FREE(handle, path,
1796 bsize, dfree, dsize);
1799 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1800 TALLOC_FREE(stripped);
1805 ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
1807 saved_errno = errno;
1809 errno = saved_errno;
1814 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
1815 const char *service, const char *user)
1817 struct shadow_copy2_config *config;
1819 const char *snapdir;
1820 const char *gmt_format;
1821 const char *sort_order;
1822 const char *basedir;
1823 const char *mount_point;
1825 DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
1826 (unsigned)handle->conn->cnum,
1827 handle->conn->connectpath));
1829 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1834 config = talloc_zero(handle->conn, struct shadow_copy2_config);
1835 if (config == NULL) {
1836 DEBUG(0, ("talloc_zero() failed\n"));
1841 gmt_format = lp_parm_const_string(SNUM(handle->conn),
1844 config->gmt_format = talloc_strdup(config, gmt_format);
1845 if (config->gmt_format == NULL) {
1846 DEBUG(0, ("talloc_strdup() failed\n"));
1851 config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
1852 "shadow", "sscanf", false);
1854 config->use_localtime = lp_parm_bool(SNUM(handle->conn),
1855 "shadow", "localtime",
1858 snapdir = lp_parm_const_string(SNUM(handle->conn),
1859 "shadow", "snapdir",
1861 config->snapdir = talloc_strdup(config, snapdir);
1862 if (config->snapdir == NULL) {
1863 DEBUG(0, ("talloc_strdup() failed\n"));
1868 config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
1870 "snapdirseverywhere",
1873 config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
1874 "shadow", "crossmountpoints",
1877 config->fixinodes = lp_parm_bool(SNUM(handle->conn),
1878 "shadow", "fixinodes",
1881 sort_order = lp_parm_const_string(SNUM(handle->conn),
1882 "shadow", "sort", "desc");
1883 config->sort_order = talloc_strdup(config, sort_order);
1884 if (config->sort_order == NULL) {
1885 DEBUG(0, ("talloc_strdup() failed\n"));
1890 mount_point = lp_parm_const_string(SNUM(handle->conn),
1891 "shadow", "mountpoint", NULL);
1892 if (mount_point != NULL) {
1893 if (mount_point[0] != '/') {
1894 DEBUG(1, (__location__ " Warning: 'mountpoint' is "
1895 "relative ('%s'), but it has to be an "
1896 "absolute path. Ignoring provided value.\n",
1901 p = strstr(handle->conn->connectpath, mount_point);
1902 if (p != handle->conn->connectpath) {
1903 DEBUG(1, ("Warning: mount_point (%s) is not a "
1904 "subdirectory of the share root "
1905 "(%s). Ignoring provided value.\n",
1907 handle->conn->connectpath));
1913 if (mount_point != NULL) {
1914 config->mount_point = talloc_strdup(config, mount_point);
1915 if (config->mount_point == NULL) {
1916 DEBUG(0, (__location__ " talloc_strdup() failed\n"));
1920 config->mount_point = shadow_copy2_find_mount_point(config,
1922 if (config->mount_point == NULL) {
1923 DBG_WARNING("shadow_copy2_find_mount_point "
1924 "of the share root '%s' failed: %s\n",
1925 handle->conn->connectpath, strerror(errno));
1930 basedir = lp_parm_const_string(SNUM(handle->conn),
1931 "shadow", "basedir", NULL);
1933 if (basedir != NULL) {
1934 if (basedir[0] != '/') {
1935 DEBUG(1, (__location__ " Warning: 'basedir' is "
1936 "relative ('%s'), but it has to be an "
1937 "absolute path. Disabling basedir.\n",
1941 p = strstr(basedir, config->mount_point);
1943 DEBUG(1, ("Warning: basedir (%s) is not a "
1944 "subdirectory of the share root's "
1945 "mount point (%s). "
1946 "Disabling basedir\n",
1947 basedir, config->mount_point));
1949 config->basedir = talloc_strdup(config,
1951 if (config->basedir == NULL) {
1952 DEBUG(0, ("talloc_strdup() failed\n"));
1960 if (config->snapdirseverywhere && config->basedir != NULL) {
1961 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1962 "with 'snapdirseverywhere'. Disabling basedir.\n"));
1963 TALLOC_FREE(config->basedir);
1966 if (config->crossmountpoints && config->basedir != NULL) {
1967 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1968 "with 'crossmountpoints'. Disabling basedir.\n"));
1969 TALLOC_FREE(config->basedir);
1972 if (config->basedir == NULL) {
1973 config->basedir = config->mount_point;
1976 if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
1977 config->rel_connectpath = talloc_strdup(config,
1978 handle->conn->connectpath + strlen(config->basedir));
1979 if (config->rel_connectpath == NULL) {
1980 DEBUG(0, ("talloc_strdup() failed\n"));
1986 if (config->snapdir[0] == '/') {
1987 config->snapdir_absolute = true;
1989 if (config->snapdirseverywhere == true) {
1990 DEBUG(1, (__location__ " Warning: An absolute snapdir "
1991 "is incompatible with 'snapdirseverywhere', "
1992 "setting 'snapdirseverywhere' to false.\n"));
1993 config->snapdirseverywhere = false;
1996 if (config->crossmountpoints == true) {
1997 DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
1998 "is not supported with an absolute snapdir. "
1999 "Disabling it.\n"));
2000 config->crossmountpoints = false;
2003 config->snapshot_basepath = config->snapdir;
2005 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2006 config->mount_point, config->snapdir);
2007 if (config->snapshot_basepath == NULL) {
2008 DEBUG(0, ("talloc_asprintf() failed\n"));
2014 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2015 " share root: '%s'\n"
2017 " mountpoint: '%s'\n"
2018 " rel share root: '%s'\n"
2020 " snapshot base path: '%s'\n"
2023 " snapdirs everywhere: %s\n"
2024 " cross mountpoints: %s\n"
2028 handle->conn->connectpath,
2030 config->mount_point,
2031 config->rel_connectpath,
2033 config->snapshot_basepath,
2035 config->use_sscanf ? "yes" : "no",
2036 config->snapdirseverywhere ? "yes" : "no",
2037 config->crossmountpoints ? "yes" : "no",
2038 config->fixinodes ? "yes" : "no",
2043 SMB_VFS_HANDLE_SET_DATA(handle, config,
2044 NULL, struct shadow_copy2_config,
2050 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2051 .connect_fn = shadow_copy2_connect,
2052 .opendir_fn = shadow_copy2_opendir,
2053 .disk_free_fn = shadow_copy2_disk_free,
2054 .rename_fn = shadow_copy2_rename,
2055 .link_fn = shadow_copy2_link,
2056 .symlink_fn = shadow_copy2_symlink,
2057 .stat_fn = shadow_copy2_stat,
2058 .lstat_fn = shadow_copy2_lstat,
2059 .fstat_fn = shadow_copy2_fstat,
2060 .open_fn = shadow_copy2_open,
2061 .unlink_fn = shadow_copy2_unlink,
2062 .chmod_fn = shadow_copy2_chmod,
2063 .chown_fn = shadow_copy2_chown,
2064 .chdir_fn = shadow_copy2_chdir,
2065 .ntimes_fn = shadow_copy2_ntimes,
2066 .readlink_fn = shadow_copy2_readlink,
2067 .mknod_fn = shadow_copy2_mknod,
2068 .realpath_fn = shadow_copy2_realpath,
2069 .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2070 .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2071 .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2072 .mkdir_fn = shadow_copy2_mkdir,
2073 .rmdir_fn = shadow_copy2_rmdir,
2074 .getxattr_fn = shadow_copy2_getxattr,
2075 .listxattr_fn = shadow_copy2_listxattr,
2076 .removexattr_fn = shadow_copy2_removexattr,
2077 .setxattr_fn = shadow_copy2_setxattr,
2078 .chmod_acl_fn = shadow_copy2_chmod_acl,
2079 .chflags_fn = shadow_copy2_chflags,
2080 .get_real_filename_fn = shadow_copy2_get_real_filename,
2083 NTSTATUS vfs_shadow_copy2_init(void);
2084 NTSTATUS vfs_shadow_copy2_init(void)
2086 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2087 "shadow_copy2", &vfs_shadow_copy2_fns);