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
9 * Copyright (C) Rajesh Joseph 2016
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * This is a second implemetation of a shadow copy module for exposing
28 * file system snapshots to windows clients as shadow copies.
30 * See the manual page for documentation.
34 #include "smbd/smbd.h"
35 #include "system/filesys.h"
36 #include "include/ntioctl.h"
39 struct shadow_copy2_config {
45 bool snapdirseverywhere;
46 bool crossmountpoints;
49 bool snapdir_absolute;
51 char *rel_connectpath; /* share root, relative to a snapshot root */
52 char *snapshot_basepath; /* the absolute version of snapdir */
55 /* Data-structure to hold the list of snap entries */
56 struct shadow_copy2_snapentry {
59 struct shadow_copy2_snapentry *next;
60 struct shadow_copy2_snapentry *prev;
63 struct shadow_copy2_snaplist_info {
64 struct shadow_copy2_snapentry *snaplist; /* snapshot list */
65 regex_t *regex; /* Regex to filter snaps */
66 time_t fetch_time; /* snaplist update time */
71 * shadow_copy2 private structure. This structure will be
72 * used to keep module specific information
74 struct shadow_copy2_private {
75 struct shadow_copy2_config *config;
76 struct shadow_copy2_snaplist_info *snaps;
79 static int shadow_copy2_get_shadow_copy_data(
80 vfs_handle_struct *handle, files_struct *fsp,
81 struct shadow_copy_data *shadow_copy2_data,
85 *This function will create a new snapshot list entry and
86 * return to the caller. This entry will also be added to
87 * the global snapshot list.
89 * @param[in] priv shadow_copy2 specific data structure
90 * @return Newly created snapshot entry or NULL on failure
92 static struct shadow_copy2_snapentry *shadow_copy2_create_snapentry(
93 struct shadow_copy2_private *priv)
95 struct shadow_copy2_snapentry *tmpentry = NULL;
97 tmpentry = talloc_zero(priv->snaps, struct shadow_copy2_snapentry);
98 if (tmpentry == NULL) {
99 DBG_ERR("talloc_zero() failed\n");
104 DLIST_ADD(priv->snaps->snaplist, tmpentry);
110 *This function will delete the entire snaplist and reset
111 * priv->snaps->snaplist to NULL.
113 * @param[in] priv shadow_copye specific data structure
115 static void shadow_copy2_delete_snaplist(struct shadow_copy2_private *priv)
117 struct shadow_copy2_snapentry *tmp = NULL;
119 while ((tmp = priv->snaps->snaplist) != NULL) {
120 DLIST_REMOVE(priv->snaps->snaplist, tmp);
126 * Given a timestamp this function searches the global snapshot list
127 * and returns the complete snapshot directory name saved in the entry.
129 * @param[in] priv shadow_copy2 specific structure
130 * @param[in] timestamp timestamp corresponding to one of the snapshot
131 * @param[out] snap_str buffer to copy the actual snapshot name
132 * @param[in] len length of snap_str buffer
134 * @return Length of actual snapshot name, and -1 on failure
136 static ssize_t shadow_copy2_saved_snapname(struct shadow_copy2_private *priv,
137 struct tm *timestamp,
138 char *snap_str, size_t len)
140 ssize_t snaptime_len = -1;
141 struct shadow_copy2_snapentry *entry = NULL;
143 snaptime_len = strftime(snap_str, len, GMT_FORMAT, timestamp);
144 if (snaptime_len == 0) {
145 DBG_ERR("strftime failed\n");
151 for (entry = priv->snaps->snaplist; entry; entry = entry->next) {
152 if (strcmp(entry->time_fmt, snap_str) == 0) {
153 snaptime_len = snprintf(snap_str, len, "%s",
165 * This function will check if snaplist is updated or not. If snaplist
166 * is empty then it will create a new list. Each time snaplist is updated
167 * the time is recorded. If the snapshot time is greater than the snaplist
168 * update time then chances are we are working on an older list. Then discard
169 * the old list and fetch a new snaplist.
171 * @param[in] handle VFS handle struct
172 * @param[in] snap_time time of snapshot
174 * @return true if the list is updated else false
176 static bool shadow_copy2_update_snaplist(struct vfs_handle_struct *handle,
180 bool snaplist_updated = false;
181 struct files_struct fsp = {0};
182 struct smb_filename smb_fname = {0};
183 double seconds = 0.0;
184 struct shadow_copy2_private *priv = NULL;
186 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
189 seconds = difftime(snap_time, priv->snaps->fetch_time);
192 * Fetch the snapshot list if either the snaplist is empty or the
193 * required snapshot time is greater than the last fetched snaplist
196 if (seconds > 0 || (priv->snaps->snaplist == NULL)) {
197 smb_fname.base_name = discard_const_p(char, ".");
198 fsp.fsp_name = &smb_fname;
200 ret = shadow_copy2_get_shadow_copy_data(handle, &fsp,
203 snaplist_updated = true;
205 DBG_ERR("Failed to get shadow copy data\n");
210 return snaplist_updated;
213 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
215 unsigned *pnum_offsets)
217 unsigned num_offsets;
224 while ((p = strchr(p, '/')) != NULL) {
229 offsets = talloc_array(mem_ctx, size_t, num_offsets);
230 if (offsets == NULL) {
236 while ((p = strchr(p, '/')) != NULL) {
237 offsets[num_offsets] = p-str;
243 *pnum_offsets = num_offsets;
248 * Given a timestamp, build the posix level GMT-tag string
249 * based on the configurable format.
251 static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
253 char *snaptime_string,
257 ssize_t snaptime_len;
258 struct shadow_copy2_config *config;
259 struct shadow_copy2_private *priv;
261 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
264 config = priv->config;
266 if (config->use_sscanf) {
267 snaptime_len = snprintf(snaptime_string,
270 (unsigned long)snapshot);
271 if (snaptime_len <= 0) {
272 DEBUG(10, ("snprintf failed\n"));
276 if (config->use_localtime) {
277 if (localtime_r(&snapshot, &snap_tm) == 0) {
278 DEBUG(10, ("gmtime_r failed\n"));
282 if (gmtime_r(&snapshot, &snap_tm) == 0) {
283 DEBUG(10, ("gmtime_r failed\n"));
288 if (priv->snaps->regex != NULL) {
289 snaptime_len = shadow_copy2_saved_snapname(priv,
290 &snap_tm, snaptime_string, len);
291 if (snaptime_len >= 0)
295 * If we fail to find the snapshot name, chances are
296 * that we have not updated our snaplist. Make sure the
297 * snaplist is updated.
299 if (!shadow_copy2_update_snaplist(handle, snapshot)) {
300 DBG_DEBUG("shadow_copy2_update_snaplist "
305 return shadow_copy2_saved_snapname(priv,
306 &snap_tm, snaptime_string, len);
309 snaptime_len = strftime(snaptime_string,
313 if (snaptime_len == 0) {
314 DEBUG(10, ("strftime failed\n"));
323 * Given a timestamp, build the string to insert into a path
324 * as a path component for creating the local path to the
325 * snapshot at the given timestamp of the input path.
327 * In the case of a parallel snapdir (specified with an
328 * absolute path), this is the inital portion of the
329 * local path of any snapshot file. The complete path is
330 * obtained by appending the portion of the file's path
331 * below the share root's mountpoint.
333 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
334 struct vfs_handle_struct *handle,
337 fstring snaptime_string;
338 ssize_t snaptime_len = 0;
340 struct shadow_copy2_config *config;
341 struct shadow_copy2_private *priv;
343 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
346 config = priv->config;
348 snaptime_len = shadow_copy2_posix_gmt_string(handle,
351 sizeof(snaptime_string));
352 if (snaptime_len <= 0) {
356 if (config->snapdir_absolute) {
357 result = talloc_asprintf(mem_ctx, "%s/%s",
358 config->snapdir, snaptime_string);
360 result = talloc_asprintf(mem_ctx, "/%s/%s",
361 config->snapdir, snaptime_string);
363 if (result == NULL) {
364 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
371 * Build the posix snapshot path for the connection
372 * at the given timestamp, i.e. the absolute posix path
373 * that contains the snapshot for this file system.
375 * This only applies to classical case, i.e. not
376 * to the "snapdirseverywhere" mode.
378 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
379 struct vfs_handle_struct *handle,
382 fstring snaptime_string;
383 ssize_t snaptime_len = 0;
385 struct shadow_copy2_private *priv;
387 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
390 snaptime_len = shadow_copy2_posix_gmt_string(handle,
393 sizeof(snaptime_string));
394 if (snaptime_len <= 0) {
398 result = talloc_asprintf(mem_ctx, "%s/%s",
399 priv->config->snapshot_basepath, snaptime_string);
400 if (result == NULL) {
401 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
408 * Strip a snapshot component from a filename as
409 * handed in via the smb layer.
410 * Returns the parsed timestamp and the stripped filename.
412 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
413 struct vfs_handle_struct *handle,
419 time_t timestamp = 0;
422 char *stripped = NULL;
423 size_t rest_len, dst_len;
424 struct shadow_copy2_private *priv;
427 ptrdiff_t len_before_gmt;
429 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
432 DEBUG(10, (__location__ ": enter path '%s'\n", name));
434 p = strstr_m(name, "@GMT-");
436 DEBUG(11, ("@GMT not found\n"));
439 if ((p > name) && (p[-1] != '/')) {
440 /* the GMT-token does not start a path-component */
441 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
442 p, name, (int)p[-1]));
447 * Figure out whether we got an already converted string. One
448 * case where this happens is in a smb2 create call with the
449 * mxac create blob set. We do the get_acl call on
450 * fsp->fsp_name, which is already converted. We are converted
451 * if we got a file name of the form ".snapshots/@GMT-",
452 * i.e. ".snapshots/" precedes "p".
455 snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
457 snapdirlen = strlen(snapdir);
458 len_before_gmt = p - name;
460 if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
461 const char *parent_snapdir = p - (snapdirlen+1);
463 DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
465 if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
466 DEBUG(10, ("name=%s is already converted\n", name));
470 q = strptime(p, GMT_FORMAT, &tm);
472 DEBUG(10, ("strptime failed\n"));
476 timestamp = timegm(&tm);
477 if (timestamp == (time_t)-1) {
478 DEBUG(10, ("timestamp==-1\n"));
483 * The name consists of only the GMT token or the GMT
484 * token is at the end of the path. XP seems to send
485 * @GMT- at the end under certain circumstances even
486 * with a path prefix.
488 if (pstripped != NULL) {
489 if (len_before_gmt > 0) {
491 * There is a slash before
492 * the @GMT-. Remove it.
496 stripped = talloc_strndup(mem_ctx, name,
498 if (stripped == NULL) {
501 *pstripped = stripped;
503 *ptimestamp = timestamp;
508 * It is not a complete path component, i.e. the path
509 * component continues after the gmt-token.
511 DEBUG(10, ("q[0] = %d\n", (int)q[0]));
516 rest_len = strlen(q);
517 dst_len = len_before_gmt + rest_len;
519 if (priv->config->snapdirseverywhere) {
522 insert = shadow_copy2_insert_string(talloc_tos(), handle,
524 if (insert == NULL) {
529 DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
531 "insert string '%s'\n", name, insert));
533 have_insert = (strstr(name, insert+1) != NULL);
534 DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
535 (int)have_insert, name, insert+1));
537 DEBUG(10, (__location__ ": insert string '%s' found in "
538 "path '%s' found in snapdirseverywhere mode "
539 "==> already converted\n", insert, name));
548 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
551 if (snapshot_path == NULL) {
556 DEBUG(10, (__location__ " path: '%s'.\n"
557 "snapshot path: '%s'\n", name, snapshot_path));
559 s = strstr(name, snapshot_path);
562 * this starts with "snapshot_basepath/GMT-Token"
563 * so it is already a converted absolute
564 * path. Don't process further.
566 DEBUG(10, (__location__ ": path '%s' starts with "
567 "snapshot path '%s' (not in "
568 "snapdirseverywhere mode) ==> "
569 "already converted\n", name, snapshot_path));
570 talloc_free(snapshot_path);
573 talloc_free(snapshot_path);
576 if (pstripped != NULL) {
577 stripped = talloc_array(mem_ctx, char, dst_len+1);
578 if (stripped == NULL) {
583 memcpy(stripped, name, len_before_gmt);
586 memcpy(stripped + len_before_gmt, q, rest_len);
588 stripped[dst_len] = '\0';
589 *pstripped = stripped;
591 *ptimestamp = timestamp;
598 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
599 vfs_handle_struct *handle)
601 char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
606 if (stat(path, &st) != 0) {
613 while ((p = strrchr(path, '/')) && p > path) {
615 if (stat(path, &st) != 0) {
619 if (st.st_dev != dev) {
629 * Convert from a name as handed in via the SMB layer
630 * and a timestamp into the local path of the snapshot
631 * of the provided file at the provided time.
632 * Also return the path in the snapshot corresponding
633 * to the file's share root.
635 static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
636 struct vfs_handle_struct *handle,
637 const char *name, time_t timestamp,
638 size_t *snaproot_len)
640 struct smb_filename converted_fname;
642 size_t *slashes = NULL;
643 unsigned num_slashes;
647 char *converted = NULL;
648 size_t insertlen, connectlen = 0;
651 struct shadow_copy2_config *config;
652 struct shadow_copy2_private *priv;
653 size_t in_share_offset = 0;
655 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
658 config = priv->config;
660 DEBUG(10, ("converting '%s'\n", name));
662 if (!config->snapdirseverywhere) {
666 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
669 if (snapshot_path == NULL) {
673 if (config->rel_connectpath == NULL) {
674 converted = talloc_asprintf(mem_ctx, "%s/%s",
675 snapshot_path, name);
677 converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
679 config->rel_connectpath,
682 if (converted == NULL) {
686 ZERO_STRUCT(converted_fname);
687 converted_fname.base_name = converted;
689 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
690 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
692 ret, ret == 0 ? "ok" : strerror(errno)));
694 DEBUG(10, ("Found %s\n", converted));
697 if (snaproot_len != NULL) {
698 *snaproot_len = strlen(snapshot_path);
699 if (config->rel_connectpath != NULL) {
701 strlen(config->rel_connectpath) + 1;
709 /* never reached ... */
712 connectlen = strlen(handle->conn->connectpath);
714 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
716 path = talloc_asprintf(
717 mem_ctx, "%s/%s", handle->conn->connectpath, name);
723 pathlen = talloc_get_size(path)-1;
725 if (!shadow_copy2_find_slashes(talloc_tos(), path,
726 &slashes, &num_slashes)) {
730 insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
731 if (insert == NULL) {
734 insertlen = talloc_get_size(insert)-1;
737 * Note: We deliberatly don't expensively initialize the
738 * array with talloc_zero here: Putting zero into
739 * converted[pathlen+insertlen] below is sufficient, because
740 * in the following for loop, the insert string is inserted
741 * at various slash places. So the memory up to position
742 * pathlen+insertlen will always be initialized when the
743 * converted string is used.
745 converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
746 if (converted == NULL) {
750 if (path[pathlen-1] != '/') {
752 * Append a fake slash to find the snapshot root
755 tmp = talloc_realloc(talloc_tos(), slashes,
756 size_t, num_slashes+1);
761 slashes[num_slashes] = pathlen;
767 if (!config->crossmountpoints) {
768 min_offset = strlen(config->mount_point);
771 memcpy(converted, path, pathlen+1);
772 converted[pathlen+insertlen] = '\0';
774 ZERO_STRUCT(converted_fname);
775 converted_fname.base_name = converted;
777 for (i = num_slashes-1; i>=0; i--) {
783 if (offset < min_offset) {
788 if (offset >= connectlen) {
789 in_share_offset = offset;
792 memcpy(converted+offset, insert, insertlen);
795 memcpy(converted+offset, path + slashes[i],
796 pathlen - slashes[i]);
798 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
800 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
802 ret, ret == 0 ? "ok" : strerror(errno)));
805 if (snaproot_len != NULL) {
806 *snaproot_len = in_share_offset + insertlen;
810 if (errno == ENOTDIR) {
812 * This is a valid condition: We appended the
813 * .snaphots/@GMT.. to a file name. Just try
814 * with the upper levels.
818 if (errno != ENOENT) {
819 /* Other problem than "not found" */
828 DEBUG(10, ("Found %s\n", converted));
836 TALLOC_FREE(converted);
838 TALLOC_FREE(slashes);
845 * Convert from a name as handed in via the SMB layer
846 * and a timestamp into the local path of the snapshot
847 * of the provided file at the provided time.
849 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
850 struct vfs_handle_struct *handle,
851 const char *name, time_t timestamp)
853 return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL);
857 modify a sbuf return to ensure that inodes in the shadow directory
858 are different from those in the main directory
860 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
861 SMB_STRUCT_STAT *sbuf)
863 struct shadow_copy2_private *priv;
865 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
868 if (priv->config->fixinodes) {
869 /* some snapshot systems, like GPFS, return the name
870 device:inode for the snapshot files as the current
871 files. That breaks the 'restore' button in the shadow copy
872 GUI, as the client gets a sharing violation.
874 This is a crude way of allowing both files to be
875 open at once. It has a slight chance of inode
876 number collision, but I can't see a better approach
877 without significant VFS changes
879 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
880 .dsize = strlen(fname) };
883 shash = tdb_jenkins_hash(&key) & 0xFF000000;
887 sbuf->st_ex_ino ^= shash;
891 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
892 const struct smb_filename *smb_fname,
896 time_t timestamp = 0;
897 char *stripped = NULL;
901 struct smb_filename *conv_smb_fname = NULL;
903 if (!shadow_copy2_strip_snapshot(talloc_tos(),
905 smb_fname->base_name,
910 if (timestamp == 0) {
911 return SMB_VFS_NEXT_OPENDIR(handle, smb_fname, mask, attr);
913 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
914 TALLOC_FREE(stripped);
918 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
923 if (conv_smb_fname == NULL) {
927 ret = SMB_VFS_NEXT_OPENDIR(handle, conv_smb_fname, mask, attr);
930 TALLOC_FREE(conv_smb_fname);
935 static int shadow_copy2_rename(vfs_handle_struct *handle,
936 const struct smb_filename *smb_fname_src,
937 const struct smb_filename *smb_fname_dst)
939 time_t timestamp_src = 0;
940 time_t timestamp_dst = 0;
942 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
943 smb_fname_src->base_name,
944 ×tamp_src, NULL)) {
947 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
948 smb_fname_dst->base_name,
949 ×tamp_dst, NULL)) {
952 if (timestamp_src != 0) {
956 if (timestamp_dst != 0) {
960 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
963 static int shadow_copy2_symlink(vfs_handle_struct *handle,
964 const char *oldname, const char *newname)
966 time_t timestamp_old = 0;
967 time_t timestamp_new = 0;
969 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
970 ×tamp_old, NULL)) {
973 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
974 ×tamp_new, NULL)) {
977 if ((timestamp_old != 0) || (timestamp_new != 0)) {
981 return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
984 static int shadow_copy2_link(vfs_handle_struct *handle,
985 const char *oldname, const char *newname)
987 time_t timestamp_old = 0;
988 time_t timestamp_new = 0;
990 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
991 ×tamp_old, NULL)) {
994 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
995 ×tamp_new, NULL)) {
998 if ((timestamp_old != 0) || (timestamp_new != 0)) {
1002 return SMB_VFS_NEXT_LINK(handle, oldname, newname);
1005 static int shadow_copy2_stat(vfs_handle_struct *handle,
1006 struct smb_filename *smb_fname)
1008 time_t timestamp = 0;
1009 char *stripped = NULL;
1011 int ret, saved_errno;
1013 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1014 smb_fname->base_name,
1015 ×tamp, &stripped)) {
1018 if (timestamp == 0) {
1019 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1022 tmp = smb_fname->base_name;
1023 smb_fname->base_name = shadow_copy2_convert(
1024 talloc_tos(), handle, stripped, timestamp);
1025 TALLOC_FREE(stripped);
1027 if (smb_fname->base_name == NULL) {
1028 smb_fname->base_name = tmp;
1032 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1033 saved_errno = errno;
1035 TALLOC_FREE(smb_fname->base_name);
1036 smb_fname->base_name = tmp;
1039 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1041 errno = saved_errno;
1045 static int shadow_copy2_lstat(vfs_handle_struct *handle,
1046 struct smb_filename *smb_fname)
1048 time_t timestamp = 0;
1049 char *stripped = NULL;
1051 int ret, saved_errno;
1053 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1054 smb_fname->base_name,
1055 ×tamp, &stripped)) {
1058 if (timestamp == 0) {
1059 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1062 tmp = smb_fname->base_name;
1063 smb_fname->base_name = shadow_copy2_convert(
1064 talloc_tos(), handle, stripped, timestamp);
1065 TALLOC_FREE(stripped);
1067 if (smb_fname->base_name == NULL) {
1068 smb_fname->base_name = tmp;
1072 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1073 saved_errno = errno;
1075 TALLOC_FREE(smb_fname->base_name);
1076 smb_fname->base_name = tmp;
1079 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1081 errno = saved_errno;
1085 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
1086 SMB_STRUCT_STAT *sbuf)
1088 time_t timestamp = 0;
1091 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1095 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1096 fsp->fsp_name->base_name,
1097 ×tamp, NULL)) {
1100 if (timestamp != 0) {
1101 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
1106 static int shadow_copy2_open(vfs_handle_struct *handle,
1107 struct smb_filename *smb_fname, files_struct *fsp,
1108 int flags, mode_t mode)
1110 time_t timestamp = 0;
1111 char *stripped = NULL;
1113 int ret, saved_errno;
1115 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1116 smb_fname->base_name,
1117 ×tamp, &stripped)) {
1120 if (timestamp == 0) {
1121 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1124 tmp = smb_fname->base_name;
1125 smb_fname->base_name = shadow_copy2_convert(
1126 talloc_tos(), handle, stripped, timestamp);
1127 TALLOC_FREE(stripped);
1129 if (smb_fname->base_name == NULL) {
1130 smb_fname->base_name = tmp;
1134 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1135 saved_errno = errno;
1137 TALLOC_FREE(smb_fname->base_name);
1138 smb_fname->base_name = tmp;
1140 errno = saved_errno;
1144 static int shadow_copy2_unlink(vfs_handle_struct *handle,
1145 const struct smb_filename *smb_fname)
1147 time_t timestamp = 0;
1148 char *stripped = NULL;
1149 int ret, saved_errno;
1150 struct smb_filename *conv;
1152 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1153 smb_fname->base_name,
1154 ×tamp, &stripped)) {
1157 if (timestamp == 0) {
1158 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1160 conv = cp_smb_filename(talloc_tos(), smb_fname);
1165 conv->base_name = shadow_copy2_convert(
1166 conv, handle, stripped, timestamp);
1167 TALLOC_FREE(stripped);
1168 if (conv->base_name == NULL) {
1171 ret = SMB_VFS_NEXT_UNLINK(handle, conv);
1172 saved_errno = errno;
1174 errno = saved_errno;
1178 static int shadow_copy2_chmod(vfs_handle_struct *handle,
1179 const struct smb_filename *smb_fname,
1182 time_t timestamp = 0;
1183 char *stripped = NULL;
1184 int ret, saved_errno;
1186 struct smb_filename *conv_smb_fname;
1188 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1190 smb_fname->base_name,
1195 if (timestamp == 0) {
1196 TALLOC_FREE(stripped);
1197 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1199 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1200 TALLOC_FREE(stripped);
1204 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1209 if (conv_smb_fname == NULL) {
1215 ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode);
1216 saved_errno = errno;
1218 TALLOC_FREE(conv_smb_fname);
1219 errno = saved_errno;
1223 static int shadow_copy2_chown(vfs_handle_struct *handle,
1224 const struct smb_filename *smb_fname,
1228 time_t timestamp = 0;
1229 char *stripped = NULL;
1230 int ret, saved_errno;
1232 struct smb_filename *conv_smb_fname = NULL;
1234 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1236 smb_fname->base_name,
1241 if (timestamp == 0) {
1242 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1244 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1245 TALLOC_FREE(stripped);
1249 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1254 if (conv_smb_fname == NULL) {
1259 ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid);
1260 saved_errno = errno;
1262 TALLOC_FREE(conv_smb_fname);
1263 errno = saved_errno;
1267 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1270 time_t timestamp = 0;
1271 char *stripped = NULL;
1272 int ret, saved_errno;
1275 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1276 ×tamp, &stripped)) {
1279 if (timestamp == 0) {
1280 return SMB_VFS_NEXT_CHDIR(handle, fname);
1282 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1283 TALLOC_FREE(stripped);
1287 ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1288 saved_errno = errno;
1290 errno = saved_errno;
1294 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1295 const struct smb_filename *smb_fname,
1296 struct smb_file_time *ft)
1298 time_t timestamp = 0;
1299 char *stripped = NULL;
1300 int ret, saved_errno;
1301 struct smb_filename *conv;
1303 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1304 smb_fname->base_name,
1305 ×tamp, &stripped)) {
1308 if (timestamp == 0) {
1309 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1311 conv = cp_smb_filename(talloc_tos(), smb_fname);
1316 conv->base_name = shadow_copy2_convert(
1317 conv, handle, stripped, timestamp);
1318 TALLOC_FREE(stripped);
1319 if (conv->base_name == NULL) {
1322 ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1323 saved_errno = errno;
1325 errno = saved_errno;
1329 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1330 const char *fname, char *buf, size_t bufsiz)
1332 time_t timestamp = 0;
1333 char *stripped = NULL;
1334 int ret, saved_errno;
1337 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1338 ×tamp, &stripped)) {
1341 if (timestamp == 0) {
1342 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1344 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1345 TALLOC_FREE(stripped);
1349 ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1350 saved_errno = errno;
1352 errno = saved_errno;
1356 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1357 const char *fname, mode_t mode, SMB_DEV_T dev)
1359 time_t timestamp = 0;
1360 char *stripped = NULL;
1361 int ret, saved_errno;
1364 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1365 ×tamp, &stripped)) {
1368 if (timestamp == 0) {
1369 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1371 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1372 TALLOC_FREE(stripped);
1376 ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1377 saved_errno = errno;
1379 errno = saved_errno;
1383 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1386 time_t timestamp = 0;
1387 char *stripped = NULL;
1389 char *result = NULL;
1392 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1393 ×tamp, &stripped)) {
1396 if (timestamp == 0) {
1397 return SMB_VFS_NEXT_REALPATH(handle, fname);
1400 tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1405 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1408 saved_errno = errno;
1410 TALLOC_FREE(stripped);
1411 errno = saved_errno;
1416 * Check whether a given directory contains a
1417 * snapshot directory as direct subdirectory.
1418 * If yes, return the path of the snapshot-subdir,
1419 * otherwise return NULL.
1421 static char *have_snapdir(struct vfs_handle_struct *handle,
1424 struct smb_filename smb_fname;
1426 struct shadow_copy2_private *priv;
1428 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1431 ZERO_STRUCT(smb_fname);
1432 smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1433 path, priv->config->snapdir);
1434 if (smb_fname.base_name == NULL) {
1438 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1439 if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1440 return smb_fname.base_name;
1442 TALLOC_FREE(smb_fname.base_name);
1446 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1449 struct smb_filename smb_fname;
1453 ZERO_STRUCT(smb_fname);
1454 smb_fname.base_name = talloc_asprintf(talloc_tos(),
1457 if (smb_fname.base_name == NULL) {
1461 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1462 if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1463 TALLOC_FREE(smb_fname.base_name);
1467 status = smbd_check_access_rights(handle->conn,
1471 if (!NT_STATUS_IS_OK(status)) {
1472 DEBUG(0,("user does not have list permission "
1474 smb_fname.base_name));
1475 TALLOC_FREE(smb_fname.base_name);
1478 TALLOC_FREE(smb_fname.base_name);
1483 * Find the snapshot directory (if any) for the given
1484 * filename (which is relative to the share).
1486 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1487 struct vfs_handle_struct *handle,
1488 struct smb_filename *smb_fname)
1491 const char *snapdir;
1492 struct shadow_copy2_config *config;
1493 struct shadow_copy2_private *priv;
1495 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1498 config = priv->config;
1501 * If the non-snapdisrseverywhere mode, we should not search!
1503 if (!config->snapdirseverywhere) {
1504 return config->snapshot_basepath;
1507 path = talloc_asprintf(mem_ctx, "%s/%s",
1508 handle->conn->connectpath,
1509 smb_fname->base_name);
1514 snapdir = have_snapdir(handle, path);
1515 if (snapdir != NULL) {
1520 while ((p = strrchr(path, '/')) && (p > path)) {
1524 snapdir = have_snapdir(handle, path);
1525 if (snapdir != NULL) {
1534 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1536 char *gmt, size_t gmt_len)
1538 struct tm timestamp;
1540 unsigned long int timestamp_long;
1542 struct shadow_copy2_config *config;
1543 struct shadow_copy2_private *priv;
1544 char *tmpstr = NULL;
1546 bool converted = false;
1549 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1552 config = priv->config;
1554 fmt = config->gmt_format;
1557 * If regex is provided, then we will have to parse the
1558 * filename which will contain both the prefix and the time format.
1559 * e.g. <prefix><delimiter><time_format>
1561 if (priv->snaps->regex != NULL) {
1562 tmpstr = talloc_strdup(talloc_tos(), name);
1563 /* point "name" to the time format */
1564 name = strstr(name, priv->config->delimiter);
1568 /* Extract the prefix */
1569 tmp = strstr(tmpstr, priv->config->delimiter);
1573 ret = regexec(priv->snaps->regex, tmpstr, 0, NULL, 0);
1575 DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
1576 "no regex match for %s\n", tmpstr);
1581 ZERO_STRUCT(timestamp);
1582 if (config->use_sscanf) {
1583 if (sscanf(name, fmt, ×tamp_long) != 1) {
1584 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1585 "no sscanf match %s: %s\n",
1589 timestamp_t = timestamp_long;
1590 gmtime_r(×tamp_t, ×tamp);
1592 if (strptime(name, fmt, ×tamp) == NULL) {
1593 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1594 "no match %s: %s\n",
1598 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1601 if (config->use_localtime) {
1602 timestamp.tm_isdst = -1;
1603 timestamp_t = mktime(×tamp);
1604 gmtime_r(×tamp_t, ×tamp);
1608 strftime(gmt, gmt_len, GMT_FORMAT, ×tamp);
1612 TALLOC_FREE(tmpstr);
1616 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1618 return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1621 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1623 return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1627 sort the shadow copy data in ascending or descending order
1629 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1630 struct shadow_copy_data *shadow_copy2_data)
1632 int (*cmpfunc)(const void *, const void *);
1634 struct shadow_copy2_private *priv;
1636 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1639 sort = priv->config->sort_order;
1644 if (strcmp(sort, "asc") == 0) {
1645 cmpfunc = shadow_copy2_label_cmp_asc;
1646 } else if (strcmp(sort, "desc") == 0) {
1647 cmpfunc = shadow_copy2_label_cmp_desc;
1652 if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1653 shadow_copy2_data->labels)
1655 TYPESAFE_QSORT(shadow_copy2_data->labels,
1656 shadow_copy2_data->num_volumes,
1661 static int shadow_copy2_get_shadow_copy_data(
1662 vfs_handle_struct *handle, files_struct *fsp,
1663 struct shadow_copy_data *shadow_copy2_data,
1667 const char *snapdir;
1668 struct smb_filename *snapdir_smb_fname = NULL;
1670 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1671 struct shadow_copy2_private *priv = NULL;
1672 struct shadow_copy2_snapentry *tmpentry = NULL;
1673 bool get_snaplist = false;
1674 bool access_granted = false;
1677 snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1678 if (snapdir == NULL) {
1679 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1680 handle->conn->connectpath));
1685 access_granted = check_access_snapdir(handle, snapdir);
1686 if (!access_granted) {
1687 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1692 snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
1696 fsp->fsp_name->flags);
1697 if (snapdir_smb_fname == NULL) {
1702 p = SMB_VFS_NEXT_OPENDIR(handle, snapdir_smb_fname, NULL, 0);
1705 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1706 " - %s\n", snapdir, strerror(errno)));
1711 if (shadow_copy2_data != NULL) {
1712 shadow_copy2_data->num_volumes = 0;
1713 shadow_copy2_data->labels = NULL;
1716 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1720 * Normally this function is called twice once with labels = false and
1721 * then with labels = true. When labels is false it will return the
1722 * number of volumes so that the caller can allocate memory for that
1723 * many labels. Therefore to eliminate snaplist both the times it is
1724 * good to check if labels is set or not.
1726 * shadow_copy2_data is NULL when we only want to update the list and
1727 * don't want any labels.
1729 if ((priv->snaps->regex != NULL) && (labels || shadow_copy2_data == NULL)) {
1730 get_snaplist = true;
1731 /* Reset the global snaplist */
1732 shadow_copy2_delete_snaplist(priv);
1734 /* Set the current time as snaplist update time */
1735 time(&(priv->snaps->fetch_time));
1738 while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1739 char snapshot[GMT_NAME_LEN+1];
1740 SHADOW_COPY_LABEL *tlabels;
1743 * ignore names not of the right form in the snapshot
1746 if (!shadow_copy2_snapshot_to_gmt(
1748 snapshot, sizeof(snapshot))) {
1750 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1751 "ignoring %s\n", d->d_name));
1754 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1755 d->d_name, snapshot));
1759 * Create a snap entry for each successful
1762 tmpentry = shadow_copy2_create_snapentry(priv);
1763 if (tmpentry == NULL) {
1764 DBG_ERR("talloc_zero() failed\n");
1767 tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
1768 tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
1771 if (shadow_copy2_data == NULL) {
1776 /* the caller doesn't want the labels */
1777 shadow_copy2_data->num_volumes++;
1781 tlabels = talloc_realloc(shadow_copy2_data,
1782 shadow_copy2_data->labels,
1784 shadow_copy2_data->num_volumes+1);
1785 if (tlabels == NULL) {
1786 DEBUG(0,("shadow_copy2: out of memory\n"));
1787 SMB_VFS_NEXT_CLOSEDIR(handle, p);
1791 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1794 shadow_copy2_data->num_volumes++;
1795 shadow_copy2_data->labels = tlabels;
1798 SMB_VFS_NEXT_CLOSEDIR(handle,p);
1800 shadow_copy2_sort_data(handle, shadow_copy2_data);
1804 TALLOC_FREE(tmp_ctx);
1808 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1809 struct files_struct *fsp,
1810 uint32_t security_info,
1811 TALLOC_CTX *mem_ctx,
1812 struct security_descriptor **ppdesc)
1814 time_t timestamp = 0;
1815 char *stripped = NULL;
1818 struct smb_filename *smb_fname = NULL;
1820 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1821 fsp->fsp_name->base_name,
1822 ×tamp, &stripped)) {
1823 return map_nt_error_from_unix(errno);
1825 if (timestamp == 0) {
1826 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1830 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1831 TALLOC_FREE(stripped);
1833 return map_nt_error_from_unix(errno);
1835 smb_fname = synthetic_smb_fname(talloc_tos(),
1839 fsp->fsp_name->flags);
1840 if (smb_fname == NULL) {
1842 return NT_STATUS_NO_MEMORY;
1845 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1848 TALLOC_FREE(smb_fname);
1852 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1853 const struct smb_filename *smb_fname,
1854 uint32_t security_info,
1855 TALLOC_CTX *mem_ctx,
1856 struct security_descriptor **ppdesc)
1858 time_t timestamp = 0;
1859 char *stripped = NULL;
1862 struct smb_filename *conv_smb_fname = NULL;
1864 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1866 smb_fname->base_name,
1869 return map_nt_error_from_unix(errno);
1871 if (timestamp == 0) {
1872 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1875 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1876 TALLOC_FREE(stripped);
1878 return map_nt_error_from_unix(errno);
1880 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1885 if (conv_smb_fname == NULL) {
1887 return NT_STATUS_NO_MEMORY;
1889 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv_smb_fname, security_info,
1892 TALLOC_FREE(conv_smb_fname);
1896 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1897 const struct smb_filename *smb_fname,
1900 time_t timestamp = 0;
1901 char *stripped = NULL;
1902 int ret, saved_errno;
1904 struct smb_filename *conv_smb_fname = NULL;
1906 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1908 smb_fname->base_name,
1913 if (timestamp == 0) {
1914 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1916 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1917 TALLOC_FREE(stripped);
1921 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1926 if (conv_smb_fname == NULL) {
1930 ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode);
1931 saved_errno = errno;
1933 TALLOC_FREE(conv_smb_fname);
1934 errno = saved_errno;
1938 static int shadow_copy2_rmdir(vfs_handle_struct *handle,
1939 const struct smb_filename *smb_fname)
1941 time_t timestamp = 0;
1942 char *stripped = NULL;
1943 int ret, saved_errno;
1945 struct smb_filename *conv_smb_fname = NULL;
1947 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1949 smb_fname->base_name,
1954 if (timestamp == 0) {
1955 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1957 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1958 TALLOC_FREE(stripped);
1962 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1967 if (conv_smb_fname == NULL) {
1971 ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname);
1972 saved_errno = errno;
1973 TALLOC_FREE(conv_smb_fname);
1975 errno = saved_errno;
1979 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1982 time_t timestamp = 0;
1983 char *stripped = NULL;
1984 int ret, saved_errno;
1987 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1988 ×tamp, &stripped)) {
1991 if (timestamp == 0) {
1992 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1994 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1995 TALLOC_FREE(stripped);
1999 ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
2000 saved_errno = errno;
2002 errno = saved_errno;
2006 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
2007 const char *fname, const char *aname,
2008 void *value, size_t size)
2010 time_t timestamp = 0;
2011 char *stripped = NULL;
2016 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2017 ×tamp, &stripped)) {
2020 if (timestamp == 0) {
2021 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
2024 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2025 TALLOC_FREE(stripped);
2029 ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
2030 saved_errno = errno;
2032 errno = saved_errno;
2036 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
2038 char *list, size_t size)
2040 time_t timestamp = 0;
2041 char *stripped = NULL;
2046 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2047 ×tamp, &stripped)) {
2050 if (timestamp == 0) {
2051 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
2053 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2054 TALLOC_FREE(stripped);
2058 ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
2059 saved_errno = errno;
2061 errno = saved_errno;
2065 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
2066 const char *fname, const char *aname)
2068 time_t timestamp = 0;
2069 char *stripped = NULL;
2070 int ret, saved_errno;
2073 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2074 ×tamp, &stripped)) {
2077 if (timestamp == 0) {
2078 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
2080 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2081 TALLOC_FREE(stripped);
2085 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
2086 saved_errno = errno;
2088 errno = saved_errno;
2092 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
2094 const char *aname, const void *value,
2095 size_t size, int flags)
2097 time_t timestamp = 0;
2098 char *stripped = NULL;
2103 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2104 ×tamp, &stripped)) {
2107 if (timestamp == 0) {
2108 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
2111 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2112 TALLOC_FREE(stripped);
2116 ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
2117 saved_errno = errno;
2119 errno = saved_errno;
2123 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
2124 const struct smb_filename *smb_fname,
2127 time_t timestamp = 0;
2128 char *stripped = NULL;
2132 struct smb_filename *conv_smb_fname = NULL;
2134 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2136 smb_fname->base_name,
2141 if (timestamp == 0) {
2142 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2144 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2145 TALLOC_FREE(stripped);
2149 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2154 if (conv_smb_fname == NULL) {
2159 ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv_smb_fname, mode);
2160 saved_errno = errno;
2162 TALLOC_FREE(conv_smb_fname);
2163 errno = saved_errno;
2167 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
2170 TALLOC_CTX *mem_ctx,
2173 time_t timestamp = 0;
2174 char *stripped = NULL;
2179 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
2180 "name=[%s]\n", path, name));
2182 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2183 ×tamp, &stripped)) {
2184 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2187 if (timestamp == 0) {
2188 DEBUG(10, ("timestamp == 0\n"));
2189 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
2190 mem_ctx, found_name);
2192 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2193 TALLOC_FREE(stripped);
2195 DEBUG(10, ("shadow_copy2_convert failed\n"));
2198 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2199 "name=[%s]\n", conv, name));
2200 ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
2201 mem_ctx, found_name);
2202 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
2203 saved_errno = errno;
2205 errno = saved_errno;
2209 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
2212 time_t timestamp = 0;
2213 char *stripped = NULL;
2215 char *result = NULL;
2216 char *parent_dir = NULL;
2218 size_t rootpath_len = 0;
2220 DBG_DEBUG("Calc connect path for [%s]\n", fname);
2222 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2223 ×tamp, &stripped)) {
2226 if (timestamp == 0) {
2227 return SMB_VFS_NEXT_CONNECTPATH(handle, fname);
2230 tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
2233 if (errno != ENOENT) {
2238 * If the converted path does not exist, and converting
2239 * the parent yields something that does exist, then
2240 * this path refers to something that has not been
2241 * created yet, relative to the parent path.
2242 * The snapshot finding is relative to the parent.
2243 * (usually snapshots are read/only but this is not
2244 * necessarily true).
2245 * This code also covers getting a wildcard in the
2246 * last component, because this function is called
2247 * prior to sanitizing the path, and in SMB1 we may
2248 * get wildcards in path names.
2250 if (!parent_dirname(talloc_tos(), stripped, &parent_dir,
2256 tmp = shadow_copy2_do_convert(talloc_tos(), handle, parent_dir,
2257 timestamp, &rootpath_len);
2263 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
2264 (int)rootpath_len, tmp);
2266 tmp[rootpath_len] = '\0';
2267 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
2268 if (result == NULL) {
2272 DBG_DEBUG("connect path is [%s]\n", result);
2275 saved_errno = errno;
2277 TALLOC_FREE(stripped);
2278 TALLOC_FREE(parent_dir);
2279 errno = saved_errno;
2283 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
2284 const char *path, uint64_t *bsize,
2285 uint64_t *dfree, uint64_t *dsize)
2287 time_t timestamp = 0;
2288 char *stripped = NULL;
2293 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2294 ×tamp, &stripped)) {
2297 if (timestamp == 0) {
2298 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2299 bsize, dfree, dsize);
2302 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2303 TALLOC_FREE(stripped);
2308 ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
2310 saved_errno = errno;
2312 errno = saved_errno;
2317 static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
2318 enum SMB_QUOTA_TYPE qtype, unid_t id,
2321 time_t timestamp = 0;
2322 char *stripped = NULL;
2327 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp,
2331 if (timestamp == 0) {
2332 return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
2335 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2336 TALLOC_FREE(stripped);
2341 ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
2343 saved_errno = errno;
2345 errno = saved_errno;
2350 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
2351 const char *service, const char *user)
2353 struct shadow_copy2_config *config;
2354 struct shadow_copy2_private *priv;
2356 const char *snapdir;
2357 const char *snapprefix = NULL;
2358 const char *delimiter;
2359 const char *gmt_format;
2360 const char *sort_order;
2361 const char *basedir = NULL;
2362 const char *snapsharepath = NULL;
2363 const char *mount_point;
2365 DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
2366 (unsigned)handle->conn->cnum,
2367 handle->conn->connectpath));
2369 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2374 priv = talloc_zero(handle->conn, struct shadow_copy2_private);
2376 DBG_ERR("talloc_zero() failed\n");
2381 priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info);
2382 if (priv->snaps == NULL) {
2383 DBG_ERR("talloc_zero() failed\n");
2388 config = talloc_zero(priv, struct shadow_copy2_config);
2389 if (config == NULL) {
2390 DEBUG(0, ("talloc_zero() failed\n"));
2395 priv->config = config;
2397 gmt_format = lp_parm_const_string(SNUM(handle->conn),
2400 config->gmt_format = talloc_strdup(config, gmt_format);
2401 if (config->gmt_format == NULL) {
2402 DEBUG(0, ("talloc_strdup() failed\n"));
2407 config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
2408 "shadow", "sscanf", false);
2410 config->use_localtime = lp_parm_bool(SNUM(handle->conn),
2411 "shadow", "localtime",
2414 snapdir = lp_parm_const_string(SNUM(handle->conn),
2415 "shadow", "snapdir",
2417 config->snapdir = talloc_strdup(config, snapdir);
2418 if (config->snapdir == NULL) {
2419 DEBUG(0, ("talloc_strdup() failed\n"));
2424 snapprefix = lp_parm_const_string(SNUM(handle->conn),
2425 "shadow", "snapprefix",
2427 if (snapprefix != NULL) {
2428 priv->snaps->regex = talloc_zero(priv->snaps, regex_t);
2429 if (priv->snaps->regex == NULL) {
2430 DBG_ERR("talloc_zero() failed\n");
2435 /* pre-compute regex rule for matching pattern later */
2436 ret = regcomp(priv->snaps->regex, snapprefix, 0);
2438 DBG_ERR("Failed to create regex object\n");
2443 delimiter = lp_parm_const_string(SNUM(handle->conn),
2444 "shadow", "delimiter",
2446 if (delimiter != NULL) {
2447 priv->config->delimiter = talloc_strdup(priv->config, delimiter);
2448 if (priv->config->delimiter == NULL) {
2449 DBG_ERR("talloc_strdup() failed\n");
2455 config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
2457 "snapdirseverywhere",
2460 config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
2461 "shadow", "crossmountpoints",
2464 if (config->crossmountpoints && !config->snapdirseverywhere) {
2465 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2466 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2469 config->fixinodes = lp_parm_bool(SNUM(handle->conn),
2470 "shadow", "fixinodes",
2473 sort_order = lp_parm_const_string(SNUM(handle->conn),
2474 "shadow", "sort", "desc");
2475 config->sort_order = talloc_strdup(config, sort_order);
2476 if (config->sort_order == NULL) {
2477 DEBUG(0, ("talloc_strdup() failed\n"));
2482 mount_point = lp_parm_const_string(SNUM(handle->conn),
2483 "shadow", "mountpoint", NULL);
2484 if (mount_point != NULL) {
2485 if (mount_point[0] != '/') {
2486 DEBUG(1, (__location__ " Warning: 'mountpoint' is "
2487 "relative ('%s'), but it has to be an "
2488 "absolute path. Ignoring provided value.\n",
2493 p = strstr(handle->conn->connectpath, mount_point);
2494 if (p != handle->conn->connectpath) {
2495 DBG_WARNING("Warning: the share root (%s) is "
2496 "not a subdirectory of the "
2497 "specified mountpoint (%s). "
2498 "Ignoring provided value.\n",
2499 handle->conn->connectpath,
2506 if (mount_point != NULL) {
2507 config->mount_point = talloc_strdup(config, mount_point);
2508 if (config->mount_point == NULL) {
2509 DEBUG(0, (__location__ " talloc_strdup() failed\n"));
2513 config->mount_point = shadow_copy2_find_mount_point(config,
2515 if (config->mount_point == NULL) {
2516 DBG_WARNING("shadow_copy2_find_mount_point "
2517 "of the share root '%s' failed: %s\n",
2518 handle->conn->connectpath, strerror(errno));
2523 basedir = lp_parm_const_string(SNUM(handle->conn),
2524 "shadow", "basedir", NULL);
2526 if (basedir != NULL) {
2527 if (basedir[0] != '/') {
2528 DEBUG(1, (__location__ " Warning: 'basedir' is "
2529 "relative ('%s'), but it has to be an "
2530 "absolute path. Disabling basedir.\n",
2535 p = strstr(basedir, config->mount_point);
2537 DEBUG(1, ("Warning: basedir (%s) is not a "
2538 "subdirectory of the share root's "
2539 "mount point (%s). "
2540 "Disabling basedir\n",
2541 basedir, config->mount_point));
2547 if (config->snapdirseverywhere && basedir != NULL) {
2548 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2549 "with 'snapdirseverywhere'. Disabling basedir.\n"));
2553 snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
2554 "snapsharepath", NULL);
2555 if (snapsharepath != NULL) {
2556 if (snapsharepath[0] == '/') {
2557 DBG_WARNING("Warning: 'snapsharepath' is "
2558 "absolute ('%s'), but it has to be a "
2559 "relative path. Disabling snapsharepath.\n",
2561 snapsharepath = NULL;
2563 if (config->snapdirseverywhere && snapsharepath != NULL) {
2564 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2565 "with 'snapdirseverywhere'. Disabling "
2566 "snapsharepath.\n");
2567 snapsharepath = NULL;
2571 if (basedir != NULL && snapsharepath != NULL) {
2572 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2573 "'basedir'. Disabling snapsharepath\n");
2574 snapsharepath = NULL;
2577 if (snapsharepath != NULL) {
2578 config->rel_connectpath = talloc_strdup(config, snapsharepath);
2579 if (config->rel_connectpath == NULL) {
2580 DBG_ERR("talloc_strdup() failed\n");
2586 if (basedir == NULL) {
2587 basedir = config->mount_point;
2590 if (config->rel_connectpath == NULL &&
2591 strlen(basedir) < strlen(handle->conn->connectpath)) {
2592 config->rel_connectpath = talloc_strdup(config,
2593 handle->conn->connectpath + strlen(basedir));
2594 if (config->rel_connectpath == NULL) {
2595 DEBUG(0, ("talloc_strdup() failed\n"));
2601 if (config->snapdir[0] == '/') {
2602 config->snapdir_absolute = true;
2604 if (config->snapdirseverywhere == true) {
2605 DEBUG(1, (__location__ " Warning: An absolute snapdir "
2606 "is incompatible with 'snapdirseverywhere', "
2607 "setting 'snapdirseverywhere' to false.\n"));
2608 config->snapdirseverywhere = false;
2611 if (config->crossmountpoints == true) {
2612 DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
2613 "is not supported with an absolute snapdir. "
2614 "Disabling it.\n"));
2615 config->crossmountpoints = false;
2618 config->snapshot_basepath = config->snapdir;
2620 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2621 config->mount_point, config->snapdir);
2622 if (config->snapshot_basepath == NULL) {
2623 DEBUG(0, ("talloc_asprintf() failed\n"));
2629 trim_string(config->mount_point, NULL, "/");
2630 trim_string(config->rel_connectpath, "/", "/");
2631 trim_string(config->snapdir, NULL, "/");
2632 trim_string(config->snapshot_basepath, NULL, "/");
2634 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2635 " share root: '%s'\n"
2636 " mountpoint: '%s'\n"
2637 " rel share root: '%s'\n"
2639 " snapprefix: '%s'\n"
2640 " delimiter: '%s'\n"
2641 " snapshot base path: '%s'\n"
2644 " snapdirs everywhere: %s\n"
2645 " cross mountpoints: %s\n"
2649 handle->conn->connectpath,
2650 config->mount_point,
2651 config->rel_connectpath,
2655 config->snapshot_basepath,
2657 config->use_sscanf ? "yes" : "no",
2658 config->snapdirseverywhere ? "yes" : "no",
2659 config->crossmountpoints ? "yes" : "no",
2660 config->fixinodes ? "yes" : "no",
2665 SMB_VFS_HANDLE_SET_DATA(handle, priv,
2666 NULL, struct shadow_copy2_private,
2672 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2673 .connect_fn = shadow_copy2_connect,
2674 .opendir_fn = shadow_copy2_opendir,
2675 .disk_free_fn = shadow_copy2_disk_free,
2676 .get_quota_fn = shadow_copy2_get_quota,
2677 .rename_fn = shadow_copy2_rename,
2678 .link_fn = shadow_copy2_link,
2679 .symlink_fn = shadow_copy2_symlink,
2680 .stat_fn = shadow_copy2_stat,
2681 .lstat_fn = shadow_copy2_lstat,
2682 .fstat_fn = shadow_copy2_fstat,
2683 .open_fn = shadow_copy2_open,
2684 .unlink_fn = shadow_copy2_unlink,
2685 .chmod_fn = shadow_copy2_chmod,
2686 .chown_fn = shadow_copy2_chown,
2687 .chdir_fn = shadow_copy2_chdir,
2688 .ntimes_fn = shadow_copy2_ntimes,
2689 .readlink_fn = shadow_copy2_readlink,
2690 .mknod_fn = shadow_copy2_mknod,
2691 .realpath_fn = shadow_copy2_realpath,
2692 .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2693 .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2694 .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2695 .mkdir_fn = shadow_copy2_mkdir,
2696 .rmdir_fn = shadow_copy2_rmdir,
2697 .getxattr_fn = shadow_copy2_getxattr,
2698 .listxattr_fn = shadow_copy2_listxattr,
2699 .removexattr_fn = shadow_copy2_removexattr,
2700 .setxattr_fn = shadow_copy2_setxattr,
2701 .chmod_acl_fn = shadow_copy2_chmod_acl,
2702 .chflags_fn = shadow_copy2_chflags,
2703 .get_real_filename_fn = shadow_copy2_get_real_filename,
2704 .connectpath_fn = shadow_copy2_connectpath,
2707 NTSTATUS vfs_shadow_copy2_init(void);
2708 NTSTATUS vfs_shadow_copy2_init(void)
2710 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2711 "shadow_copy2", &vfs_shadow_copy2_fns);