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 = ".";
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,
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 = (p-name) + 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, p-name);
586 memcpy(stripped + (p-name), 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,
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, timestamp_dst;
941 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
942 smb_fname_src->base_name,
943 ×tamp_src, NULL)) {
946 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
947 smb_fname_dst->base_name,
948 ×tamp_dst, NULL)) {
951 if (timestamp_src != 0) {
955 if (timestamp_dst != 0) {
959 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
962 static int shadow_copy2_symlink(vfs_handle_struct *handle,
963 const char *oldname, const char *newname)
965 time_t timestamp_old, timestamp_new;
967 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
968 ×tamp_old, NULL)) {
971 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
972 ×tamp_new, NULL)) {
975 if ((timestamp_old != 0) || (timestamp_new != 0)) {
979 return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
982 static int shadow_copy2_link(vfs_handle_struct *handle,
983 const char *oldname, const char *newname)
985 time_t timestamp_old, timestamp_new;
987 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
988 ×tamp_old, NULL)) {
991 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
992 ×tamp_new, NULL)) {
995 if ((timestamp_old != 0) || (timestamp_new != 0)) {
999 return SMB_VFS_NEXT_LINK(handle, oldname, newname);
1002 static int shadow_copy2_stat(vfs_handle_struct *handle,
1003 struct smb_filename *smb_fname)
1006 char *stripped, *tmp;
1007 int ret, saved_errno;
1009 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1010 smb_fname->base_name,
1011 ×tamp, &stripped)) {
1014 if (timestamp == 0) {
1015 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1018 tmp = smb_fname->base_name;
1019 smb_fname->base_name = shadow_copy2_convert(
1020 talloc_tos(), handle, stripped, timestamp);
1021 TALLOC_FREE(stripped);
1023 if (smb_fname->base_name == NULL) {
1024 smb_fname->base_name = tmp;
1028 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1029 saved_errno = errno;
1031 TALLOC_FREE(smb_fname->base_name);
1032 smb_fname->base_name = tmp;
1035 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1037 errno = saved_errno;
1041 static int shadow_copy2_lstat(vfs_handle_struct *handle,
1042 struct smb_filename *smb_fname)
1045 char *stripped, *tmp;
1046 int ret, saved_errno;
1048 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1049 smb_fname->base_name,
1050 ×tamp, &stripped)) {
1053 if (timestamp == 0) {
1054 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1057 tmp = smb_fname->base_name;
1058 smb_fname->base_name = shadow_copy2_convert(
1059 talloc_tos(), handle, stripped, timestamp);
1060 TALLOC_FREE(stripped);
1062 if (smb_fname->base_name == NULL) {
1063 smb_fname->base_name = tmp;
1067 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1068 saved_errno = errno;
1070 TALLOC_FREE(smb_fname->base_name);
1071 smb_fname->base_name = tmp;
1074 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1076 errno = saved_errno;
1080 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
1081 SMB_STRUCT_STAT *sbuf)
1086 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1090 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1091 fsp->fsp_name->base_name,
1092 ×tamp, NULL)) {
1095 if (timestamp != 0) {
1096 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
1101 static int shadow_copy2_open(vfs_handle_struct *handle,
1102 struct smb_filename *smb_fname, files_struct *fsp,
1103 int flags, mode_t mode)
1106 char *stripped, *tmp;
1107 int ret, saved_errno;
1109 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1110 smb_fname->base_name,
1111 ×tamp, &stripped)) {
1114 if (timestamp == 0) {
1115 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1118 tmp = smb_fname->base_name;
1119 smb_fname->base_name = shadow_copy2_convert(
1120 talloc_tos(), handle, stripped, timestamp);
1121 TALLOC_FREE(stripped);
1123 if (smb_fname->base_name == NULL) {
1124 smb_fname->base_name = tmp;
1128 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1129 saved_errno = errno;
1131 TALLOC_FREE(smb_fname->base_name);
1132 smb_fname->base_name = tmp;
1134 errno = saved_errno;
1138 static int shadow_copy2_unlink(vfs_handle_struct *handle,
1139 const struct smb_filename *smb_fname)
1143 int ret, saved_errno;
1144 struct smb_filename *conv;
1146 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1147 smb_fname->base_name,
1148 ×tamp, &stripped)) {
1151 if (timestamp == 0) {
1152 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1154 conv = cp_smb_filename(talloc_tos(), smb_fname);
1159 conv->base_name = shadow_copy2_convert(
1160 conv, handle, stripped, timestamp);
1161 TALLOC_FREE(stripped);
1162 if (conv->base_name == NULL) {
1165 ret = SMB_VFS_NEXT_UNLINK(handle, conv);
1166 saved_errno = errno;
1168 errno = saved_errno;
1172 static int shadow_copy2_chmod(vfs_handle_struct *handle,
1173 const struct smb_filename *smb_fname,
1177 char *stripped = NULL;
1178 int ret, saved_errno;
1180 struct smb_filename *conv_smb_fname;
1182 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1184 smb_fname->base_name,
1189 if (timestamp == 0) {
1190 TALLOC_FREE(stripped);
1191 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1193 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1194 TALLOC_FREE(stripped);
1198 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1203 if (conv_smb_fname == NULL) {
1209 ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode);
1210 saved_errno = errno;
1212 TALLOC_FREE(conv_smb_fname);
1213 errno = saved_errno;
1217 static int shadow_copy2_chown(vfs_handle_struct *handle,
1218 const struct smb_filename *smb_fname,
1224 int ret, saved_errno;
1226 struct smb_filename *conv_smb_fname = NULL;
1228 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1230 smb_fname->base_name,
1235 if (timestamp == 0) {
1236 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1238 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1239 TALLOC_FREE(stripped);
1243 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1248 if (conv_smb_fname == NULL) {
1253 ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid);
1254 saved_errno = errno;
1256 TALLOC_FREE(conv_smb_fname);
1257 errno = saved_errno;
1261 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1266 int ret, saved_errno;
1269 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1270 ×tamp, &stripped)) {
1273 if (timestamp == 0) {
1274 return SMB_VFS_NEXT_CHDIR(handle, fname);
1276 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1277 TALLOC_FREE(stripped);
1281 ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1282 saved_errno = errno;
1284 errno = saved_errno;
1288 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1289 const struct smb_filename *smb_fname,
1290 struct smb_file_time *ft)
1294 int ret, saved_errno;
1295 struct smb_filename *conv;
1297 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1298 smb_fname->base_name,
1299 ×tamp, &stripped)) {
1302 if (timestamp == 0) {
1303 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1305 conv = cp_smb_filename(talloc_tos(), smb_fname);
1310 conv->base_name = shadow_copy2_convert(
1311 conv, handle, stripped, timestamp);
1312 TALLOC_FREE(stripped);
1313 if (conv->base_name == NULL) {
1316 ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1317 saved_errno = errno;
1319 errno = saved_errno;
1323 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1324 const char *fname, char *buf, size_t bufsiz)
1328 int ret, saved_errno;
1331 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1332 ×tamp, &stripped)) {
1335 if (timestamp == 0) {
1336 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1338 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1339 TALLOC_FREE(stripped);
1343 ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1344 saved_errno = errno;
1346 errno = saved_errno;
1350 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1351 const char *fname, mode_t mode, SMB_DEV_T dev)
1355 int ret, saved_errno;
1358 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1359 ×tamp, &stripped)) {
1362 if (timestamp == 0) {
1363 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1365 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1366 TALLOC_FREE(stripped);
1370 ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1371 saved_errno = errno;
1373 errno = saved_errno;
1377 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1381 char *stripped = NULL;
1383 char *result = NULL;
1386 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1387 ×tamp, &stripped)) {
1390 if (timestamp == 0) {
1391 return SMB_VFS_NEXT_REALPATH(handle, fname);
1394 tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1399 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1402 saved_errno = errno;
1404 TALLOC_FREE(stripped);
1405 errno = saved_errno;
1410 * Check whether a given directory contains a
1411 * snapshot directory as direct subdirectory.
1412 * If yes, return the path of the snapshot-subdir,
1413 * otherwise return NULL.
1415 static char *have_snapdir(struct vfs_handle_struct *handle,
1418 struct smb_filename smb_fname;
1420 struct shadow_copy2_private *priv;
1422 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1425 ZERO_STRUCT(smb_fname);
1426 smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1427 path, priv->config->snapdir);
1428 if (smb_fname.base_name == NULL) {
1432 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1433 if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1434 return smb_fname.base_name;
1436 TALLOC_FREE(smb_fname.base_name);
1440 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1443 struct smb_filename smb_fname;
1447 ZERO_STRUCT(smb_fname);
1448 smb_fname.base_name = talloc_asprintf(talloc_tos(),
1451 if (smb_fname.base_name == NULL) {
1455 ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1456 if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1457 TALLOC_FREE(smb_fname.base_name);
1461 status = smbd_check_access_rights(handle->conn,
1465 if (!NT_STATUS_IS_OK(status)) {
1466 DEBUG(0,("user does not have list permission "
1468 smb_fname.base_name));
1469 TALLOC_FREE(smb_fname.base_name);
1472 TALLOC_FREE(smb_fname.base_name);
1477 * Find the snapshot directory (if any) for the given
1478 * filename (which is relative to the share).
1480 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1481 struct vfs_handle_struct *handle,
1482 struct smb_filename *smb_fname)
1485 const char *snapdir;
1486 struct shadow_copy2_config *config;
1487 struct shadow_copy2_private *priv;
1489 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1492 config = priv->config;
1495 * If the non-snapdisrseverywhere mode, we should not search!
1497 if (!config->snapdirseverywhere) {
1498 return config->snapshot_basepath;
1501 path = talloc_asprintf(mem_ctx, "%s/%s",
1502 handle->conn->connectpath,
1503 smb_fname->base_name);
1508 snapdir = have_snapdir(handle, path);
1509 if (snapdir != NULL) {
1514 while ((p = strrchr(path, '/')) && (p > path)) {
1518 snapdir = have_snapdir(handle, path);
1519 if (snapdir != NULL) {
1528 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1530 char *gmt, size_t gmt_len)
1532 struct tm timestamp;
1534 unsigned long int timestamp_long;
1536 struct shadow_copy2_config *config;
1537 struct shadow_copy2_private *priv;
1538 char *tmpstr = NULL;
1540 bool converted = false;
1543 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1546 config = priv->config;
1548 fmt = config->gmt_format;
1551 * If regex is provided, then we will have to parse the
1552 * filename which will contain both the prefix and the time format.
1553 * e.g. <prefix><delimiter><time_format>
1555 if (priv->snaps->regex != NULL) {
1556 tmpstr = talloc_strdup(talloc_tos(), name);
1557 /* point "name" to the time format */
1558 name = strstr(name, priv->config->delimiter);
1562 /* Extract the prefix */
1563 tmp = strstr(tmpstr, priv->config->delimiter);
1567 ret = regexec(priv->snaps->regex, tmpstr, 0, NULL, 0);
1569 DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
1570 "no regex match for %s\n", tmpstr);
1575 ZERO_STRUCT(timestamp);
1576 if (config->use_sscanf) {
1577 if (sscanf(name, fmt, ×tamp_long) != 1) {
1578 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1579 "no sscanf match %s: %s\n",
1583 timestamp_t = timestamp_long;
1584 gmtime_r(×tamp_t, ×tamp);
1586 if (strptime(name, fmt, ×tamp) == NULL) {
1587 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1588 "no match %s: %s\n",
1592 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1595 if (config->use_localtime) {
1596 timestamp.tm_isdst = -1;
1597 timestamp_t = mktime(×tamp);
1598 gmtime_r(×tamp_t, ×tamp);
1602 strftime(gmt, gmt_len, GMT_FORMAT, ×tamp);
1606 TALLOC_FREE(tmpstr);
1610 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1612 return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1615 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1617 return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1621 sort the shadow copy data in ascending or descending order
1623 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1624 struct shadow_copy_data *shadow_copy2_data)
1626 int (*cmpfunc)(const void *, const void *);
1628 struct shadow_copy2_private *priv;
1630 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1633 sort = priv->config->sort_order;
1638 if (strcmp(sort, "asc") == 0) {
1639 cmpfunc = shadow_copy2_label_cmp_asc;
1640 } else if (strcmp(sort, "desc") == 0) {
1641 cmpfunc = shadow_copy2_label_cmp_desc;
1646 if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1647 shadow_copy2_data->labels)
1649 TYPESAFE_QSORT(shadow_copy2_data->labels,
1650 shadow_copy2_data->num_volumes,
1655 static int shadow_copy2_get_shadow_copy_data(
1656 vfs_handle_struct *handle, files_struct *fsp,
1657 struct shadow_copy_data *shadow_copy2_data,
1661 const char *snapdir;
1662 struct smb_filename *snapdir_smb_fname = NULL;
1664 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1665 struct shadow_copy2_private *priv = NULL;
1666 struct shadow_copy2_snapentry *tmpentry = NULL;
1667 bool get_snaplist = false;
1668 bool access_granted = false;
1671 snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1672 if (snapdir == NULL) {
1673 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1674 handle->conn->connectpath));
1679 access_granted = check_access_snapdir(handle, snapdir);
1680 if (!access_granted) {
1681 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1686 snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
1690 fsp->fsp_name->flags);
1691 if (snapdir_smb_fname == NULL) {
1696 p = SMB_VFS_NEXT_OPENDIR(handle, snapdir_smb_fname, NULL, 0);
1699 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1700 " - %s\n", snapdir, strerror(errno)));
1705 if (shadow_copy2_data != NULL) {
1706 shadow_copy2_data->num_volumes = 0;
1707 shadow_copy2_data->labels = NULL;
1710 SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1714 * Normally this function is called twice once with labels = false and
1715 * then with labels = true. When labels is false it will return the
1716 * number of volumes so that the caller can allocate memory for that
1717 * many labels. Therefore to eliminate snaplist both the times it is
1718 * good to check if labels is set or not.
1720 * shadow_copy2_data is NULL when we only want to update the list and
1721 * don't want any labels.
1723 if ((priv->snaps->regex != NULL) && (labels || shadow_copy2_data == NULL)) {
1724 get_snaplist = true;
1725 /* Reset the global snaplist */
1726 shadow_copy2_delete_snaplist(priv);
1728 /* Set the current time as snaplist update time */
1729 time(&(priv->snaps->fetch_time));
1732 while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1733 char snapshot[GMT_NAME_LEN+1];
1734 SHADOW_COPY_LABEL *tlabels;
1737 * ignore names not of the right form in the snapshot
1740 if (!shadow_copy2_snapshot_to_gmt(
1742 snapshot, sizeof(snapshot))) {
1744 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1745 "ignoring %s\n", d->d_name));
1748 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1749 d->d_name, snapshot));
1753 * Create a snap entry for each successful
1756 tmpentry = shadow_copy2_create_snapentry(priv);
1757 if (tmpentry == NULL) {
1758 DBG_ERR("talloc_zero() failed\n");
1761 tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
1762 tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
1765 if (shadow_copy2_data == NULL) {
1770 /* the caller doesn't want the labels */
1771 shadow_copy2_data->num_volumes++;
1775 tlabels = talloc_realloc(shadow_copy2_data,
1776 shadow_copy2_data->labels,
1778 shadow_copy2_data->num_volumes+1);
1779 if (tlabels == NULL) {
1780 DEBUG(0,("shadow_copy2: out of memory\n"));
1781 SMB_VFS_NEXT_CLOSEDIR(handle, p);
1785 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1788 shadow_copy2_data->num_volumes++;
1789 shadow_copy2_data->labels = tlabels;
1792 SMB_VFS_NEXT_CLOSEDIR(handle,p);
1794 shadow_copy2_sort_data(handle, shadow_copy2_data);
1798 TALLOC_FREE(tmp_ctx);
1802 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1803 struct files_struct *fsp,
1804 uint32_t security_info,
1805 TALLOC_CTX *mem_ctx,
1806 struct security_descriptor **ppdesc)
1812 struct smb_filename *smb_fname = NULL;
1814 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1815 fsp->fsp_name->base_name,
1816 ×tamp, &stripped)) {
1817 return map_nt_error_from_unix(errno);
1819 if (timestamp == 0) {
1820 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1824 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1825 TALLOC_FREE(stripped);
1827 return map_nt_error_from_unix(errno);
1829 smb_fname = synthetic_smb_fname(talloc_tos(),
1833 fsp->fsp_name->flags);
1834 if (smb_fname == NULL) {
1836 return NT_STATUS_NO_MEMORY;
1839 status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1842 TALLOC_FREE(smb_fname);
1846 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1847 const struct smb_filename *smb_fname,
1848 uint32_t security_info,
1849 TALLOC_CTX *mem_ctx,
1850 struct security_descriptor **ppdesc)
1856 struct smb_filename *conv_smb_fname = NULL;
1858 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1860 smb_fname->base_name,
1863 return map_nt_error_from_unix(errno);
1865 if (timestamp == 0) {
1866 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1869 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1870 TALLOC_FREE(stripped);
1872 return map_nt_error_from_unix(errno);
1874 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1879 if (conv_smb_fname == NULL) {
1881 return NT_STATUS_NO_MEMORY;
1883 status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv_smb_fname, security_info,
1886 TALLOC_FREE(conv_smb_fname);
1890 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1891 const struct smb_filename *smb_fname,
1896 int ret, saved_errno;
1898 struct smb_filename *conv_smb_fname = NULL;
1900 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1902 smb_fname->base_name,
1907 if (timestamp == 0) {
1908 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1910 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1911 TALLOC_FREE(stripped);
1915 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1920 if (conv_smb_fname == NULL) {
1924 ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode);
1925 saved_errno = errno;
1927 TALLOC_FREE(conv_smb_fname);
1928 errno = saved_errno;
1932 static int shadow_copy2_rmdir(vfs_handle_struct *handle,
1933 const struct smb_filename *smb_fname)
1937 int ret, saved_errno;
1939 struct smb_filename *conv_smb_fname = NULL;
1941 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1943 smb_fname->base_name,
1948 if (timestamp == 0) {
1949 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1951 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1952 TALLOC_FREE(stripped);
1956 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1961 if (conv_smb_fname == NULL) {
1965 ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname);
1966 saved_errno = errno;
1967 TALLOC_FREE(conv_smb_fname);
1969 errno = saved_errno;
1973 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1978 int ret, saved_errno;
1981 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1982 ×tamp, &stripped)) {
1985 if (timestamp == 0) {
1986 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1988 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1989 TALLOC_FREE(stripped);
1993 ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1994 saved_errno = errno;
1996 errno = saved_errno;
2000 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
2001 const char *fname, const char *aname,
2002 void *value, size_t size)
2010 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2011 ×tamp, &stripped)) {
2014 if (timestamp == 0) {
2015 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
2018 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2019 TALLOC_FREE(stripped);
2023 ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
2024 saved_errno = errno;
2026 errno = saved_errno;
2030 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
2032 char *list, size_t size)
2040 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2041 ×tamp, &stripped)) {
2044 if (timestamp == 0) {
2045 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
2047 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2048 TALLOC_FREE(stripped);
2052 ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
2053 saved_errno = errno;
2055 errno = saved_errno;
2059 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
2060 const char *fname, const char *aname)
2064 int ret, saved_errno;
2067 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2068 ×tamp, &stripped)) {
2071 if (timestamp == 0) {
2072 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
2074 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2075 TALLOC_FREE(stripped);
2079 ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
2080 saved_errno = errno;
2082 errno = saved_errno;
2086 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
2088 const char *aname, const void *value,
2089 size_t size, int flags)
2097 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2098 ×tamp, &stripped)) {
2101 if (timestamp == 0) {
2102 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
2105 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2106 TALLOC_FREE(stripped);
2110 ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
2111 saved_errno = errno;
2113 errno = saved_errno;
2117 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
2118 const struct smb_filename *smb_fname,
2126 struct smb_filename *conv_smb_fname = NULL;
2128 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2130 smb_fname->base_name,
2135 if (timestamp == 0) {
2136 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2138 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2139 TALLOC_FREE(stripped);
2143 conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2148 if (conv_smb_fname == NULL) {
2153 ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv_smb_fname, mode);
2154 saved_errno = errno;
2156 TALLOC_FREE(conv_smb_fname);
2157 errno = saved_errno;
2161 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
2164 TALLOC_CTX *mem_ctx,
2173 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
2174 "name=[%s]\n", path, name));
2176 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2177 ×tamp, &stripped)) {
2178 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2181 if (timestamp == 0) {
2182 DEBUG(10, ("timestamp == 0\n"));
2183 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
2184 mem_ctx, found_name);
2186 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2187 TALLOC_FREE(stripped);
2189 DEBUG(10, ("shadow_copy2_convert failed\n"));
2192 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2193 "name=[%s]\n", conv, name));
2194 ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
2195 mem_ctx, found_name);
2196 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
2197 saved_errno = errno;
2199 errno = saved_errno;
2203 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
2207 char *stripped = NULL;
2209 char *result = NULL;
2211 size_t rootpath_len = 0;
2213 DBG_DEBUG("Calc connect path for [%s]\n", fname);
2215 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2216 ×tamp, &stripped)) {
2219 if (timestamp == 0) {
2220 return SMB_VFS_NEXT_CONNECTPATH(handle, fname);
2223 tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
2229 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
2230 (int)rootpath_len, tmp);
2232 tmp[rootpath_len] = '\0';
2233 result = SMB_VFS_NEXT_REALPATH(handle, tmp);
2234 if (result == NULL) {
2238 DBG_DEBUG("connect path is [%s]\n", result);
2241 saved_errno = errno;
2243 TALLOC_FREE(stripped);
2244 errno = saved_errno;
2248 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
2249 const char *path, uint64_t *bsize,
2250 uint64_t *dfree, uint64_t *dsize)
2258 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2259 ×tamp, &stripped)) {
2262 if (timestamp == 0) {
2263 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2264 bsize, dfree, dsize);
2267 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2268 TALLOC_FREE(stripped);
2273 ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
2275 saved_errno = errno;
2277 errno = saved_errno;
2282 static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
2283 enum SMB_QUOTA_TYPE qtype, unid_t id,
2292 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp,
2296 if (timestamp == 0) {
2297 return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
2300 conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2301 TALLOC_FREE(stripped);
2306 ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
2308 saved_errno = errno;
2310 errno = saved_errno;
2315 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
2316 const char *service, const char *user)
2318 struct shadow_copy2_config *config;
2319 struct shadow_copy2_private *priv;
2321 const char *snapdir;
2322 const char *snapprefix = NULL;
2323 const char *delimiter;
2324 const char *gmt_format;
2325 const char *sort_order;
2326 const char *basedir = NULL;
2327 const char *snapsharepath = NULL;
2328 const char *mount_point;
2330 DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
2331 (unsigned)handle->conn->cnum,
2332 handle->conn->connectpath));
2334 ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2339 priv = talloc_zero(handle->conn, struct shadow_copy2_private);
2341 DBG_ERR("talloc_zero() failed\n");
2346 priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info);
2347 if (priv->snaps == NULL) {
2348 DBG_ERR("talloc_zero() failed\n");
2353 config = talloc_zero(priv, struct shadow_copy2_config);
2354 if (config == NULL) {
2355 DEBUG(0, ("talloc_zero() failed\n"));
2360 priv->config = config;
2362 gmt_format = lp_parm_const_string(SNUM(handle->conn),
2365 config->gmt_format = talloc_strdup(config, gmt_format);
2366 if (config->gmt_format == NULL) {
2367 DEBUG(0, ("talloc_strdup() failed\n"));
2372 config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
2373 "shadow", "sscanf", false);
2375 config->use_localtime = lp_parm_bool(SNUM(handle->conn),
2376 "shadow", "localtime",
2379 snapdir = lp_parm_const_string(SNUM(handle->conn),
2380 "shadow", "snapdir",
2382 config->snapdir = talloc_strdup(config, snapdir);
2383 if (config->snapdir == NULL) {
2384 DEBUG(0, ("talloc_strdup() failed\n"));
2389 snapprefix = lp_parm_const_string(SNUM(handle->conn),
2390 "shadow", "snapprefix",
2392 if (snapprefix != NULL) {
2393 priv->snaps->regex = talloc_zero(priv->snaps, regex_t);
2394 if (priv->snaps->regex == NULL) {
2395 DBG_ERR("talloc_zero() failed\n");
2400 /* pre-compute regex rule for matching pattern later */
2401 ret = regcomp(priv->snaps->regex, snapprefix, 0);
2403 DBG_ERR("Failed to create regex object\n");
2408 delimiter = lp_parm_const_string(SNUM(handle->conn),
2409 "shadow", "delimiter",
2411 if (delimiter != NULL) {
2412 priv->config->delimiter = talloc_strdup(priv->config, delimiter);
2413 if (priv->config->delimiter == NULL) {
2414 DBG_ERR("talloc_strdup() failed\n");
2420 config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
2422 "snapdirseverywhere",
2425 config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
2426 "shadow", "crossmountpoints",
2429 if (config->crossmountpoints && !config->snapdirseverywhere) {
2430 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2431 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2434 config->fixinodes = lp_parm_bool(SNUM(handle->conn),
2435 "shadow", "fixinodes",
2438 sort_order = lp_parm_const_string(SNUM(handle->conn),
2439 "shadow", "sort", "desc");
2440 config->sort_order = talloc_strdup(config, sort_order);
2441 if (config->sort_order == NULL) {
2442 DEBUG(0, ("talloc_strdup() failed\n"));
2447 mount_point = lp_parm_const_string(SNUM(handle->conn),
2448 "shadow", "mountpoint", NULL);
2449 if (mount_point != NULL) {
2450 if (mount_point[0] != '/') {
2451 DEBUG(1, (__location__ " Warning: 'mountpoint' is "
2452 "relative ('%s'), but it has to be an "
2453 "absolute path. Ignoring provided value.\n",
2458 p = strstr(handle->conn->connectpath, mount_point);
2459 if (p != handle->conn->connectpath) {
2460 DBG_WARNING("Warning: the share root (%s) is "
2461 "not a subdirectory of the "
2462 "specified mountpoint (%s). "
2463 "Ignoring provided value.\n",
2464 handle->conn->connectpath,
2471 if (mount_point != NULL) {
2472 config->mount_point = talloc_strdup(config, mount_point);
2473 if (config->mount_point == NULL) {
2474 DEBUG(0, (__location__ " talloc_strdup() failed\n"));
2478 config->mount_point = shadow_copy2_find_mount_point(config,
2480 if (config->mount_point == NULL) {
2481 DBG_WARNING("shadow_copy2_find_mount_point "
2482 "of the share root '%s' failed: %s\n",
2483 handle->conn->connectpath, strerror(errno));
2488 basedir = lp_parm_const_string(SNUM(handle->conn),
2489 "shadow", "basedir", NULL);
2491 if (basedir != NULL) {
2492 if (basedir[0] != '/') {
2493 DEBUG(1, (__location__ " Warning: 'basedir' is "
2494 "relative ('%s'), but it has to be an "
2495 "absolute path. Disabling basedir.\n",
2500 p = strstr(basedir, config->mount_point);
2502 DEBUG(1, ("Warning: basedir (%s) is not a "
2503 "subdirectory of the share root's "
2504 "mount point (%s). "
2505 "Disabling basedir\n",
2506 basedir, config->mount_point));
2512 if (config->snapdirseverywhere && basedir != NULL) {
2513 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2514 "with 'snapdirseverywhere'. Disabling basedir.\n"));
2518 snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
2519 "snapsharepath", NULL);
2520 if (snapsharepath != NULL) {
2521 if (snapsharepath[0] == '/') {
2522 DBG_WARNING("Warning: 'snapsharepath' is "
2523 "absolute ('%s'), but it has to be a "
2524 "relative path. Disabling snapsharepath.\n",
2526 snapsharepath = NULL;
2528 if (config->snapdirseverywhere && snapsharepath != NULL) {
2529 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2530 "with 'snapdirseverywhere'. Disabling "
2531 "snapsharepath.\n");
2532 snapsharepath = NULL;
2536 if (basedir != NULL && snapsharepath != NULL) {
2537 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2538 "'basedir'. Disabling snapsharepath\n");
2539 snapsharepath = NULL;
2542 if (snapsharepath != NULL) {
2543 config->rel_connectpath = talloc_strdup(config, snapsharepath);
2544 if (config->rel_connectpath == NULL) {
2545 DBG_ERR("talloc_strdup() failed\n");
2551 if (basedir == NULL) {
2552 basedir = config->mount_point;
2555 if (config->rel_connectpath == NULL &&
2556 strlen(basedir) != strlen(handle->conn->connectpath)) {
2557 config->rel_connectpath = talloc_strdup(config,
2558 handle->conn->connectpath + strlen(basedir));
2559 if (config->rel_connectpath == NULL) {
2560 DEBUG(0, ("talloc_strdup() failed\n"));
2566 if (config->snapdir[0] == '/') {
2567 config->snapdir_absolute = true;
2569 if (config->snapdirseverywhere == true) {
2570 DEBUG(1, (__location__ " Warning: An absolute snapdir "
2571 "is incompatible with 'snapdirseverywhere', "
2572 "setting 'snapdirseverywhere' to false.\n"));
2573 config->snapdirseverywhere = false;
2576 if (config->crossmountpoints == true) {
2577 DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
2578 "is not supported with an absolute snapdir. "
2579 "Disabling it.\n"));
2580 config->crossmountpoints = false;
2583 config->snapshot_basepath = config->snapdir;
2585 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2586 config->mount_point, config->snapdir);
2587 if (config->snapshot_basepath == NULL) {
2588 DEBUG(0, ("talloc_asprintf() failed\n"));
2594 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2595 " share root: '%s'\n"
2596 " mountpoint: '%s'\n"
2597 " rel share root: '%s'\n"
2599 " snapprefix: '%s'\n"
2600 " delimiter: '%s'\n"
2601 " snapshot base path: '%s'\n"
2604 " snapdirs everywhere: %s\n"
2605 " cross mountpoints: %s\n"
2609 handle->conn->connectpath,
2610 config->mount_point,
2611 config->rel_connectpath,
2615 config->snapshot_basepath,
2617 config->use_sscanf ? "yes" : "no",
2618 config->snapdirseverywhere ? "yes" : "no",
2619 config->crossmountpoints ? "yes" : "no",
2620 config->fixinodes ? "yes" : "no",
2625 SMB_VFS_HANDLE_SET_DATA(handle, priv,
2626 NULL, struct shadow_copy2_private,
2632 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2633 .connect_fn = shadow_copy2_connect,
2634 .opendir_fn = shadow_copy2_opendir,
2635 .disk_free_fn = shadow_copy2_disk_free,
2636 .get_quota_fn = shadow_copy2_get_quota,
2637 .rename_fn = shadow_copy2_rename,
2638 .link_fn = shadow_copy2_link,
2639 .symlink_fn = shadow_copy2_symlink,
2640 .stat_fn = shadow_copy2_stat,
2641 .lstat_fn = shadow_copy2_lstat,
2642 .fstat_fn = shadow_copy2_fstat,
2643 .open_fn = shadow_copy2_open,
2644 .unlink_fn = shadow_copy2_unlink,
2645 .chmod_fn = shadow_copy2_chmod,
2646 .chown_fn = shadow_copy2_chown,
2647 .chdir_fn = shadow_copy2_chdir,
2648 .ntimes_fn = shadow_copy2_ntimes,
2649 .readlink_fn = shadow_copy2_readlink,
2650 .mknod_fn = shadow_copy2_mknod,
2651 .realpath_fn = shadow_copy2_realpath,
2652 .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2653 .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2654 .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2655 .mkdir_fn = shadow_copy2_mkdir,
2656 .rmdir_fn = shadow_copy2_rmdir,
2657 .getxattr_fn = shadow_copy2_getxattr,
2658 .listxattr_fn = shadow_copy2_listxattr,
2659 .removexattr_fn = shadow_copy2_removexattr,
2660 .setxattr_fn = shadow_copy2_setxattr,
2661 .chmod_acl_fn = shadow_copy2_chmod_acl,
2662 .chflags_fn = shadow_copy2_chflags,
2663 .get_real_filename_fn = shadow_copy2_get_real_filename,
2664 .connectpath_fn = shadow_copy2_connectpath,
2667 NTSTATUS vfs_shadow_copy2_init(void);
2668 NTSTATUS vfs_shadow_copy2_init(void)
2670 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2671 "shadow_copy2", &vfs_shadow_copy2_fns);