From d5fe966589e9c40d751e029c37a990c837b78404 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 4 Oct 2013 13:15:34 +0200 Subject: [PATCH 01/36] shadow_copy2: break overly long lines in shadow_copy2_snapshot_to_gmt() According to coding guidelines. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 01cb88977da5bc44443407b100345531d047c77c) --- source3/modules/vfs_shadow_copy2.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index aa7e50f..dd66010 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1030,7 +1030,8 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle, ZERO_STRUCT(timestamp); if (lp_parm_bool(SNUM(handle->conn), "shadow", "sscanf", false)) { if (sscanf(name, fmt, ×tamp_long) != 1) { - DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no sscanf match %s: %s\n", + DEBUG(10, ("shadow_copy2_snapshot_to_gmt: " + "no sscanf match %s: %s\n", fmt, name)); return false; } @@ -1038,11 +1039,13 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle, gmtime_r(×tamp_t, ×tamp); } else { if (strptime(name, fmt, ×tamp) == NULL) { - DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no match %s: %s\n", + DEBUG(10, ("shadow_copy2_snapshot_to_gmt: " + "no match %s: %s\n", fmt, name)); return false; } - DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name)); + DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", + fmt, name)); if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) { timestamp.tm_isdst = -1; -- 1.8.3.2 From 5e0fa7d44f6fcfd8c60cecd5a54bd1090c5ae70a Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 23 May 2013 23:32:15 +0200 Subject: [PATCH 02/36] shadow_copy2: add comment header describing shadow_copy2_strip_snapshot() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 9361824ddd291cb0e543a5a0829246831fcb9e84) --- source3/modules/vfs_shadow_copy2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index dd66010..8bbb7b8 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -186,6 +186,11 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, snaptime_string); } +/** + * Strip a snapshot component from an filename as + * handed in via the smb layer. + * Returns the parsed timestamp and the stripped filename. + */ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, const char *name, -- 1.8.3.2 From b56a625e005a3e64e45ffa47380f6dad5ff934c6 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 23 May 2013 23:59:49 +0200 Subject: [PATCH 03/36] shadow_copy2: add header comment explaining have_snapdir() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 5b494b3dea559f632d57c9d33172e46e459e852f) --- source3/modules/vfs_shadow_copy2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 8bbb7b8..932f93f 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -963,6 +963,12 @@ done: return result; } +/** + * Check whether a given directory contains a + * snapshot directory as direct subdirectory. + * If yes, return the path of the snapshot-subdir, + * otherwise return NULL. + */ static char *have_snapdir(struct vfs_handle_struct *handle, const char *path) { -- 1.8.3.2 From 4555a8be6f04095df18c879ca0be16c761d2a493 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 24 May 2013 00:01:14 +0200 Subject: [PATCH 04/36] shadow_copy2: add comment block explaining shadow_copy2_find_snapdir() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit b90d1e6ac06fd4c1aaaceadcb711800499334117) --- source3/modules/vfs_shadow_copy2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 932f93f..9f4f111 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -992,6 +992,10 @@ static char *have_snapdir(struct vfs_handle_struct *handle, return NULL; } +/** + * Find the snapshot directory (if any) for the given + * filename (which is relative to the share). + */ static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, struct smb_filename *smb_fname) -- 1.8.3.2 From d3d765d0c9b9f95ddb29f18c3fc2390b75dd874f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 24 May 2013 17:20:42 +0200 Subject: [PATCH 05/36] shadow_copy2: add comment block explaining shadow_copy2_insert_string() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 5da5512985cf65c09abb33abaf5e8dc28167dac3) --- source3/modules/vfs_shadow_copy2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 9f4f111..06e5115 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -141,6 +141,11 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, return true; } +/** + * Given a timstamp, build the string to insert into a path + * as a path component for creating the local path to the + * snapshot at the given timestamp of the input path. + */ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, time_t snapshot) -- 1.8.3.2 From 1bb289dbdf6261c085094721263107c11d1c6878 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 01:13:57 +0200 Subject: [PATCH 06/36] shadow_copy2: add comment block explaining shadow_copy2_convert() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 5c900fd930edd45e9f23b36c1e68e5c2d8b96867) --- source3/modules/vfs_shadow_copy2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 06e5115..70d5174 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -314,6 +314,11 @@ static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx, return path; } +/** + * Convert from a name as handed in via the SMB layer + * and a timestamp into the local path of the snapshot + * of the provided file at the provided time. + */ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, const char *name, time_t timestamp) -- 1.8.3.2 From e8d2b46b65994d2b93471bcbd88f3662116c3f7f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 17:11:44 +0200 Subject: [PATCH 07/36] shadow_copy2: add comment explaining the SMB level GMT format pattern Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 6da7375cd881f85f2873578db7fcfb368deab94f) --- source3/include/smb.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index cfc12a7..e1ab344 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -567,7 +567,15 @@ Offset Data length. #define NOTIFY_ACTION_REMOVED_STREAM 7 #define NOTIFY_ACTION_MODIFIED_STREAM 8 -/* timestamp format used in "previous versions" */ +/* + * Timestamp format used in "previous versions": + * The is the windows-level format of the @GMT- token. + * It is a fixed format not to be confused with the + * format for the POSIX-Level token of the shadow_copy2 + * VFS module that can be configured via the "shadow:format" + * configuration option but defaults to the same format. + * See the shadow_copy2 module. + */ #define GMT_NAME_LEN 24 /* length of a @GMT- name */ #define GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S" -- 1.8.3.2 From 4e8b8b7792dbe231e262edc51cb0d6ccde892d04 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 24 May 2013 01:35:44 +0200 Subject: [PATCH 08/36] shadow_copy2: introduce config struct and function shadow_copy2_connect() This moves the parsing of the config to a central place. So users of configuation don't need to call lp_parm_... all the time. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 1ecef5743583cf617f5506bc2fca3baa70cfb9b3) --- source3/modules/vfs_shadow_copy2.c | 173 +++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 28 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 70d5174..d5b1653 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -107,6 +107,18 @@ #include #include "util_tdb.h" +struct shadow_copy2_config { + char *gmt_format; + bool use_sscanf; + bool use_localtime; + char *snapdir; + bool snapdirseverywhere; + bool crossmountpoints; + bool fixinodes; + char *sort_order; + bool snapdir_absolute; +}; + static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, size_t **poffsets, unsigned *pnum_offsets) @@ -150,23 +162,25 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, time_t snapshot) { - const char *fmt; struct tm snap_tm; fstring snaptime_string; size_t snaptime_len; + struct shadow_copy2_config *config; - fmt = lp_parm_const_string(SNUM(handle->conn), "shadow", - "format", GMT_FORMAT); + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); - if (lp_parm_bool(SNUM(handle->conn), "shadow", "sscanf", false)) { - snaptime_len = snprintf(snaptime_string, sizeof(snaptime_string), fmt, - (unsigned long)snapshot); + if (config->use_sscanf) { + snaptime_len = snprintf(snaptime_string, + sizeof(snaptime_string), + config->gmt_format, + (unsigned long)snapshot); if (snaptime_len <= 0) { DEBUG(10, ("snprintf failed\n")); return NULL; } } else { - if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) { + if (config->use_localtime) { if (localtime_r(&snapshot, &snap_tm) == 0) { DEBUG(10, ("gmtime_r failed\n")); return NULL; @@ -177,18 +191,17 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, return NULL; } } - snaptime_len = strftime(snaptime_string, sizeof(snaptime_string), fmt, - &snap_tm); + snaptime_len = strftime(snaptime_string, + sizeof(snaptime_string), + config->gmt_format, + &snap_tm); if (snaptime_len == 0) { DEBUG(10, ("strftime failed\n")); return NULL; } } return talloc_asprintf(mem_ctx, "/%s/%s", - lp_parm_const_string( - SNUM(handle->conn), "shadow", "snapdir", - ".snapshots"), - snaptime_string); + config->snapdir, snaptime_string); } /** @@ -208,6 +221,10 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, char *q; char *stripped; size_t rest_len, dst_len; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return false); p = strstr_m(name, "@GMT-"); if (p == NULL) { @@ -244,8 +261,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, rest_len = strlen(q); dst_len = (p-name) + rest_len; - if (lp_parm_bool(SNUM(handle->conn), "shadow", "snapdirseverywhere", - false)) { + if (config->snapdirseverywhere) { char *insert; bool have_insert; insert = shadow_copy2_insert_string(talloc_tos(), handle, @@ -334,6 +350,10 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, size_t insertlen; int i, saved_errno; size_t min_offset; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, name); @@ -376,8 +396,7 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, min_offset = 0; - if (!lp_parm_bool(SNUM(handle->conn), "shadow", "crossmountpoints", - false)) { + if (!config->crossmountpoints) { char *mount_point; mount_point = shadow_copy2_find_mount_point(talloc_tos(), @@ -461,7 +480,12 @@ fail: static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf) { - if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) { + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return); + + if (config->fixinodes) { /* some snapshot systems, like GPFS, return the name device:inode for the snapshot files as the current files. That breaks the 'restore' button in the shadow copy @@ -984,12 +1008,14 @@ static char *have_snapdir(struct vfs_handle_struct *handle, { struct smb_filename smb_fname; int ret; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); ZERO_STRUCT(smb_fname); - smb_fname.base_name = talloc_asprintf( - talloc_tos(), "%s/%s", path, - lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", - ".snapshots")); + smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s", + path, config->snapdir); if (smb_fname.base_name == NULL) { return NULL; } @@ -1012,6 +1038,10 @@ static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, { char *path, *p; char *snapdir; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, @@ -1048,12 +1078,15 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle, time_t timestamp_t; unsigned long int timestamp_long; const char *fmt; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); - fmt = lp_parm_const_string(SNUM(handle->conn), "shadow", - "format", GMT_FORMAT); + fmt = config->gmt_format; ZERO_STRUCT(timestamp); - if (lp_parm_bool(SNUM(handle->conn), "shadow", "sscanf", false)) { + if (config->use_sscanf) { if (sscanf(name, fmt, ×tamp_long) != 1) { DEBUG(10, ("shadow_copy2_snapshot_to_gmt: " "no sscanf match %s: %s\n", @@ -1072,7 +1105,7 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle, DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name)); - if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) { + if (config->use_localtime) { timestamp.tm_isdst = -1; timestamp_t = mktime(×tamp); gmtime_r(×tamp_t, ×tamp); @@ -1101,9 +1134,12 @@ static void shadow_copy2_sort_data(vfs_handle_struct *handle, { int (*cmpfunc)(const void *, const void *); const char *sort; + struct shadow_copy2_config *config; - sort = lp_parm_const_string(SNUM(handle->conn), "shadow", - "sort", "desc"); + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return); + + sort = config->sort_order; if (sort == NULL) { return; } @@ -1536,8 +1572,89 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, return ret; } +static int shadow_copy2_connect(struct vfs_handle_struct *handle, + const char *service, const char *user) +{ + struct shadow_copy2_config *config; + int ret; + const char *snapdir; + const char *gmt_format; + const char *sort_order; + + DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n", + (unsigned)handle->conn->cnum, + handle->conn->connectpath)); + + ret = SMB_VFS_NEXT_CONNECT(handle, service, user); + if (ret < 0) { + return ret; + } + + config = talloc_zero(handle->conn, struct shadow_copy2_config); + if (config == NULL) { + DEBUG(0, ("talloc_zero() failed\n")); + errno = ENOMEM; + return -1; + } + + gmt_format = lp_parm_const_string(SNUM(handle->conn), + "shadow", "format", + GMT_FORMAT); + config->gmt_format = talloc_strdup(config, gmt_format); + if (config->gmt_format == NULL) { + DEBUG(0, ("talloc_strdup() failed\n")); + errno = ENOMEM; + return -1; + } + + config->use_sscanf = lp_parm_bool(SNUM(handle->conn), + "shadow", "sscanf", false); + + config->use_localtime = lp_parm_bool(SNUM(handle->conn), + "shadow", "localtime", + false); + + snapdir = lp_parm_const_string(SNUM(handle->conn), + "shadow", "snapdir", + ".snapshots"); + config->snapdir = talloc_strdup(config, snapdir); + if (config->snapdir == NULL) { + DEBUG(0, ("talloc_strdup() failed\n")); + errno = ENOMEM; + return -1; + } + + config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn), + "shadow", + "snapdirseverywhere", + false); + + config->crossmountpoints = lp_parm_bool(SNUM(handle->conn), + "shadow", "crossmountpoints", + false); + + config->fixinodes = lp_parm_bool(SNUM(handle->conn), + "shadow", "fixinodes", + false); + + sort_order = lp_parm_const_string(SNUM(handle->conn), + "shadow", "sort", "desc"); + config->sort_order = talloc_strdup(config, sort_order); + if (config->sort_order == NULL) { + DEBUG(0, ("talloc_strdup() failed\n")); + errno = ENOMEM; + return -1; + } + + SMB_VFS_HANDLE_SET_DATA(handle, config, + NULL, struct shadow_copy2_config, + return -1); + + return 0; +} static struct vfs_fn_pointers vfs_shadow_copy2_fns = { + .connect_fn = shadow_copy2_connect, .opendir_fn = shadow_copy2_opendir, .rename_fn = shadow_copy2_rename, .link_fn = shadow_copy2_link, -- 1.8.3.2 From 46817ab73409a1a0d3e97ecc27f296773f5ba6f2 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 17:10:51 +0200 Subject: [PATCH 09/36] shadow_copy2: introduce the bool "snapdir_absolute" in the config. Not exposed but to be used internally. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 843954989cbec6640d2565d0d23a48f296740a23) --- source3/modules/vfs_shadow_copy2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index d5b1653..0694473 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1646,6 +1646,16 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, return -1; } + if (config->snapdir[0] == '/') { + config->snapdir_absolute = true; + if (config->snapdirseverywhere == true) { + DEBUG(1, (__location__ " Warning: An absolute snapdir " + "is incompatible with 'snapdirseverywhere', " + "setting 'snapdirseverywhere' to false.\n")); + config->snapdirseverywhere = false; + } + } + SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct shadow_copy2_config, return -1); -- 1.8.3.2 From 31fd10549d77dd18a7726dc652ec055272ce43c2 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 30 May 2013 13:19:50 +0200 Subject: [PATCH 10/36] shadow_copy2: disable "snapdir:crossmountpoints" if the snapdir is absolute. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 1e887fcda097b93a879df726f2b7c2c8d3c4cf54) --- source3/modules/vfs_shadow_copy2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 0694473..adcc855 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1654,6 +1654,13 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, "setting 'snapdirseverywhere' to false.\n")); config->snapdirseverywhere = false; } + + if (config->crossmountpoints == true) { + DEBUG(1, (__location__ " Warning: 'crossmountpoints' " + "is not supported with an absolute snapdir. " + "Disabling it.\n")); + config->crossmountpoints = false; + } } SMB_VFS_HANDLE_SET_DATA(handle, config, -- 1.8.3.2 From 3cec3b2324e910eada0830f8bfd7a6ea97bb7faf Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 30 May 2013 17:26:44 +0200 Subject: [PATCH 11/36] shadow_copy2: re-add the basedir option. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable basedir if it is not an absolute path or if snapdirseverywhere or crossmountpoints is enabled. Pair-Programmed-With: Björn Baumbach Signed-off-by: Michael Adam Signed-off-by: Björn Baumbach Reviewed-by: Andrew Bartlett (cherry picked from commit ed751b9ee49d8e4a319759640321e8b49be4f154) --- source3/modules/vfs_shadow_copy2.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index adcc855..d584fa9 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -117,6 +117,8 @@ struct shadow_copy2_config { bool fixinodes; char *sort_order; bool snapdir_absolute; + char *basedir; + char *mount_point; }; static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, @@ -1580,6 +1582,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, const char *snapdir; const char *gmt_format; const char *sort_order; + const char *basedir; DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n", (unsigned)handle->conn->cnum, @@ -1646,6 +1649,59 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, return -1; } + config->mount_point = shadow_copy2_find_mount_point(config, handle); + if (config->mount_point == NULL) { + DEBUG(0, (__location__ ": shadow_copy2_find_mount_point " + "failed: %s\n", strerror(errno))); + return -1; + } + + basedir = lp_parm_const_string(SNUM(handle->conn), + "shadow", "basedir", NULL); + + if (basedir != NULL) { + if (basedir[0] != '/') { + DEBUG(1, (__location__ " Warning: 'basedir' is " + "relative ('%s'), but it has to be an " + "absolute path. Disabling basedir.\n", + basedir)); + } else { + char *p; + p = strstr(basedir, config->mount_point); + if (p != basedir) { + DEBUG(1, ("Warning: basedir (%s) is not a " + "subdirectory of the share root's " + "mount point (%s). " + "Disabling basedir\n", + basedir, config->mount_point)); + } else { + config->basedir = talloc_strdup(config, + basedir); + if (config->basedir == NULL) { + DEBUG(0, ("talloc_strdup() failed\n")); + errno = ENOMEM; + return -1; + } + } + } + } + + if (config->snapdirseverywhere && config->basedir != NULL) { + DEBUG(1, (__location__ " Warning: 'basedir' is incompatible " + "with 'snapdirseverywhere'. Disabling basedir.\n")); + TALLOC_FREE(config->basedir); + } + + if (config->crossmountpoints && config->basedir != NULL) { + DEBUG(1, (__location__ " Warning: 'basedir' is incompatible " + "with 'crossmountpoints'. Disabling basedir.\n")); + TALLOC_FREE(config->basedir); + } + + if (config->basedir == NULL) { + config->basedir = config->mount_point; + } + if (config->snapdir[0] == '/') { config->snapdir_absolute = true; if (config->snapdirseverywhere == true) { -- 1.8.3.2 From ee96c27583b7b26a38d32919772e951cf8152ec4 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 31 May 2013 16:36:33 +0200 Subject: [PATCH 12/36] shadow_copy2: introduce "shadow:mountpoint" option Possiblity to explicitly set the share's mount point. This is useful mainly for debugging and testing purposes. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 2d5a3af4bc44d13877a26fa1857b3ceafe138de8) --- source3/modules/vfs_shadow_copy2.c | 43 +++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index d584fa9..afe2ff4 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1583,6 +1583,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, const char *gmt_format; const char *sort_order; const char *basedir; + const char *mount_point; DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n", (unsigned)handle->conn->cnum, @@ -1649,11 +1650,43 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, return -1; } - config->mount_point = shadow_copy2_find_mount_point(config, handle); - if (config->mount_point == NULL) { - DEBUG(0, (__location__ ": shadow_copy2_find_mount_point " - "failed: %s\n", strerror(errno))); - return -1; + mount_point = lp_parm_const_string(SNUM(handle->conn), + "shadow", "mountpoint", NULL); + if (mount_point != NULL) { + if (mount_point[0] != '/') { + DEBUG(1, (__location__ " Warning: 'mountpoint' is " + "relative ('%s'), but it has to be an " + "absolute path. Ignoring provided value.\n", + mount_point)); + mount_point = NULL; + } else { + char *p; + p = strstr(handle->conn->connectpath, mount_point); + if (p != handle->conn->connectpath) { + DEBUG(1, ("Warning: mount_point (%s) is not a " + "subdirectory of the share root " + "(%s). Ignoring provided value.\n", + mount_point, + handle->conn->connectpath)); + mount_point = NULL; + } + } + } + + if (mount_point != NULL) { + config->mount_point = talloc_strdup(config, mount_point); + if (config->mount_point == NULL) { + DEBUG(0, (__location__ " talloc_strdup() failed\n")); + return -1; + } + } else { + config->mount_point = shadow_copy2_find_mount_point(config, + handle); + if (config->mount_point == NULL) { + DEBUG(0, (__location__ ": shadow_copy2_find_mount_point" + " failed: %s\n", strerror(errno))); + return -1; + } } basedir = lp_parm_const_string(SNUM(handle->conn), -- 1.8.3.2 From f330251398fd38ca478531463a9eccdb7b699f11 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 4 Oct 2013 00:04:06 +0200 Subject: [PATCH 13/36] shadow_copy2: add rel_connectpath to config. This is the share root, relative to the basedir. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit d34dc1b0025d18afc9ce638c7000b702f98b5d03) --- source3/modules/vfs_shadow_copy2.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index afe2ff4..8f2f466 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -119,6 +119,7 @@ struct shadow_copy2_config { bool snapdir_absolute; char *basedir; char *mount_point; + char *rel_connectpath; /* share root, relative to the basedir */ }; static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, @@ -1735,8 +1736,19 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, config->basedir = config->mount_point; } + if (strlen(config->basedir) != strlen(handle->conn->connectpath)) { + config->rel_connectpath = talloc_strdup(config, + handle->conn->connectpath + strlen(config->basedir)); + if (config->rel_connectpath == NULL) { + DEBUG(0, ("talloc_strdup() failed\n")); + errno = ENOMEM; + return -1; + } + } + if (config->snapdir[0] == '/') { config->snapdir_absolute = true; + if (config->snapdirseverywhere == true) { DEBUG(1, (__location__ " Warning: An absolute snapdir " "is incompatible with 'snapdirseverywhere', " -- 1.8.3.2 From 34a5b087ecd5ac8fb371b1a67f2a19b559140936 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 4 Oct 2013 00:07:15 +0200 Subject: [PATCH 14/36] shadow_copy2: add snapshot_basepath to the config. This is the absolute version of snapdir. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit a7ca55c8da6fbe6452a7a0bfc3c84b5941b8aa27) --- source3/modules/vfs_shadow_copy2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 8f2f466..f3be5fe 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -120,6 +120,7 @@ struct shadow_copy2_config { char *basedir; char *mount_point; char *rel_connectpath; /* share root, relative to the basedir */ + char *snapshot_basepath; /* the absolute version of snapdir */ }; static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, @@ -1762,6 +1763,16 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, "Disabling it.\n")); config->crossmountpoints = false; } + + config->snapshot_basepath = config->snapdir; + } else { + config->snapshot_basepath = talloc_asprintf(config, "%s/%s", + config->mount_point, config->snapdir); + if (config->snapshot_basepath == NULL) { + DEBUG(0, ("talloc_asprintf() failed\n")); + errno = ENOMEM; + return -1; + } } SMB_VFS_HANDLE_SET_DATA(handle, config, -- 1.8.3.2 From 9dcef14faed4850817f79f25697233bddc4713c9 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 31 May 2013 17:17:27 +0200 Subject: [PATCH 15/36] shadow_copy2: log resulting config at the end of shadow_copy2_connect() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit c4f9954ebb04da94a5bcd2cb328fb2fbaf9fa062) --- source3/modules/vfs_shadow_copy2.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index f3be5fe..4c8ee25 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1775,6 +1775,35 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, } } + DEBUG(10, ("shadow_copy2_connect: configuration:\n" + " share root: '%s'\n" + " basedir: '%s'\n" + " mountpoint: '%s'\n" + " rel share root: '%s'\n" + " snapdir: '%s'\n" + " snapshot base path: '%s'\n" + " format: '%s'\n" + " use sscanf: %s\n" + " snapdirs everywhere: %s\n" + " cross mountpoints: %s\n" + " fix inodes: %s\n" + " sort order: %s\n" + "", + handle->conn->connectpath, + config->basedir, + config->mount_point, + config->rel_connectpath, + config->snapdir, + config->snapshot_basepath, + config->gmt_format, + config->use_sscanf ? "yes" : "no", + config->snapdirseverywhere ? "yes" : "no", + config->crossmountpoints ? "yes" : "no", + config->fixinodes ? "yes" : "no", + config->sort_order + )); + + SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct shadow_copy2_config, return -1); -- 1.8.3.2 From 32ed3529d3f973d8df4cca221cfb95e3af366cb5 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 1 Jun 2013 02:14:41 +0200 Subject: [PATCH 16/36] shadow_copy2: implement disk_free Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit ea898ea1ac1cc9364c5b7396db3902aeb114cfb8) --- source3/modules/vfs_shadow_copy2.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 4c8ee25..94621873 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1576,6 +1576,42 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, return ret; } +static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, + const char *path, bool small_query, + uint64_t *bsize, uint64_t *dfree, + uint64_t *dsize) +{ + time_t timestamp; + char *stripped; + ssize_t ret; + int saved_errno; + char *conv; + + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, + ×tamp, &stripped)) { + return -1; + } + if (timestamp == 0) { + return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query, + bsize, dfree, dsize); + } + + conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); + TALLOC_FREE(stripped); + if (conv == NULL) { + return -1; + } + + ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, small_query, bsize, dfree, + dsize); + + saved_errno = errno; + TALLOC_FREE(conv); + errno = saved_errno; + + return ret; +} + static int shadow_copy2_connect(struct vfs_handle_struct *handle, const char *service, const char *user) { @@ -1814,6 +1850,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, static struct vfs_fn_pointers vfs_shadow_copy2_fns = { .connect_fn = shadow_copy2_connect, .opendir_fn = shadow_copy2_opendir, + .disk_free_fn = shadow_copy2_disk_free, .rename_fn = shadow_copy2_rename, .link_fn = shadow_copy2_link, .symlink_fn = shadow_copy2_symlink, -- 1.8.3.2 From 580fd7ad5a6c85e68db50a32f4604e0be910b2ee Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 23 May 2013 16:21:46 +0200 Subject: [PATCH 17/36] shadow_copy2: in the classical case, use configured path in shadow_copy2_find_snapdir() There is no point in searching for snapdir if not in snapdirseverywhere mode. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit dbdb436a80e2fb75d9fd8ae17192702123c3b530) --- source3/modules/vfs_shadow_copy2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 94621873..952b010 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1047,6 +1047,13 @@ static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return NULL); + /* + * If the non-snapdisrseverywhere mode, we should not search! + */ + if (!config->snapdirseverywhere) { + return config->snapshot_basepath; + } + path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, smb_fname->base_name); -- 1.8.3.2 From 58627edbc16b9c9593a51386eae60888a4897173 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 28 May 2013 17:01:20 +0200 Subject: [PATCH 18/36] shadow_copy2: make shadow_copy2_find_snapdir() return const char * instead of char *. This eliminates compiler warnings. snapdir is a const string in all occasions. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit e86923eb52633c5b6133c45678355ce69bb43a54) --- source3/modules/vfs_shadow_copy2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 952b010..e227b10 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1036,12 +1036,12 @@ static char *have_snapdir(struct vfs_handle_struct *handle, * Find the snapshot directory (if any) for the given * filename (which is relative to the share). */ -static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, - struct vfs_handle_struct *handle, - struct smb_filename *smb_fname) +static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + struct smb_filename *smb_fname) { char *path, *p; - char *snapdir; + const char *snapdir; struct shadow_copy2_config *config; SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, -- 1.8.3.2 From c8f282ce787fe9402c18b3f51dcd3c6c0ca37482 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 17:12:21 +0200 Subject: [PATCH 19/36] shadow_copy2: shadow_copy2_insert_string(): do not prepend a "/" in absolute mode Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 304a0f531caa5f33f205739470f17e983d25a6b5) --- source3/modules/vfs_shadow_copy2.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index e227b10..97f208e 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -161,6 +161,12 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, * Given a timstamp, build the string to insert into a path * as a path component for creating the local path to the * snapshot at the given timestamp of the input path. + * + * In the case of a parallel snapdir (specified with an + * absolute path), this is the inital portion of the + * local path of any snapshot file. The complete path is + * obtained by appending the portion of the file's path + * below the share root's mountpoint. */ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, @@ -170,6 +176,7 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, fstring snaptime_string; size_t snaptime_len; struct shadow_copy2_config *config; + char *result = NULL; SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return NULL); @@ -204,8 +211,19 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, return NULL; } } - return talloc_asprintf(mem_ctx, "/%s/%s", - config->snapdir, snaptime_string); + + if (config->snapdir_absolute) { + result = talloc_asprintf(mem_ctx, "%s/%s", + config->snapdir, snaptime_string); + } else { + result = talloc_asprintf(mem_ctx, "/%s/%s", + config->snapdir, snaptime_string); + } + if (result == NULL) { + DEBUG(1, (__location__ " talloc_asprintf failed\n")); + } + + return result; } /** -- 1.8.3.2 From bbbb37fea9fb5a929559a1b00b29b97e8eac05f7 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 30 May 2013 23:51:02 +0200 Subject: [PATCH 20/36] shadow_copy2: factor shadow_copy2_posix_gmt_string() out of shadow_copy2_insert_string() for re-use.. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 4cc5140bbe207f08d9b4fb0d119e74cc839e55dd) --- source3/modules/vfs_shadow_copy2.c | 68 ++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 97f208e..ac6cdbb 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -158,60 +158,86 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str, } /** - * Given a timstamp, build the string to insert into a path - * as a path component for creating the local path to the - * snapshot at the given timestamp of the input path. - * - * In the case of a parallel snapdir (specified with an - * absolute path), this is the inital portion of the - * local path of any snapshot file. The complete path is - * obtained by appending the portion of the file's path - * below the share root's mountpoint. + * Given a timstamp, build the posix level GTM-tag string + * based on the configurable format. */ -static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, - struct vfs_handle_struct *handle, - time_t snapshot) +static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle, + time_t snapshot, + char *snaptime_string, + size_t len) { struct tm snap_tm; - fstring snaptime_string; size_t snaptime_len; struct shadow_copy2_config *config; - char *result = NULL; SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, - return NULL); + return 0); if (config->use_sscanf) { snaptime_len = snprintf(snaptime_string, - sizeof(snaptime_string), + len, config->gmt_format, (unsigned long)snapshot); if (snaptime_len <= 0) { DEBUG(10, ("snprintf failed\n")); - return NULL; + return snaptime_len; } } else { if (config->use_localtime) { if (localtime_r(&snapshot, &snap_tm) == 0) { DEBUG(10, ("gmtime_r failed\n")); - return NULL; + return -1; } } else { if (gmtime_r(&snapshot, &snap_tm) == 0) { DEBUG(10, ("gmtime_r failed\n")); - return NULL; + return -1; } } snaptime_len = strftime(snaptime_string, - sizeof(snaptime_string), + len, config->gmt_format, &snap_tm); if (snaptime_len == 0) { DEBUG(10, ("strftime failed\n")); - return NULL; + return 0; } } + return snaptime_len; +} + +/** + * Given a timstamp, build the string to insert into a path + * as a path component for creating the local path to the + * snapshot at the given timestamp of the input path. + * + * In the case of a parallel snapdir (specified with an + * absolute path), this is the inital portion of the + * local path of any snapshot file. The complete path is + * obtained by appending the portion of the file's path + * below the share root's mountpoint. + */ +static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + time_t snapshot) +{ + fstring snaptime_string; + size_t snaptime_len = 0; + char *result = NULL; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); + + snaptime_len = shadow_copy2_posix_gmt_string(handle, + snapshot, + snaptime_string, + sizeof(snaptime_string)); + if (snaptime_len <= 0) { + return NULL; + } + if (config->snapdir_absolute) { result = talloc_asprintf(mem_ctx, "%s/%s", config->snapdir, snaptime_string); -- 1.8.3.2 From 46329d4ec45db7131759576d7fa5bc61c361159b Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 31 May 2013 00:18:52 +0200 Subject: [PATCH 21/36] shadow_copy2: introduce shadow_copy2_snapshot_path() This builds the posix snapshot path for the connection at the provided timestamp. For the non-snapdirseverywhere case. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 38e108563d7e9e14203bf4dabfda09bd1408e980) --- source3/modules/vfs_shadow_copy2.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ac6cdbb..ec60884 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -253,6 +253,43 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx, } /** + * Build the posix snapshot path for the connection + * at the given timestamp, i.e. the absolute posix path + * that contains the snapshot for this file system. + * + * This only applies to classical case, i.e. not + * to the "snapdirseverywhere" mode. + */ +static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + time_t snapshot) +{ + fstring snaptime_string; + size_t snaptime_len = 0; + char *result = NULL; + struct shadow_copy2_config *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, + return NULL); + + snaptime_len = shadow_copy2_posix_gmt_string(handle, + snapshot, + snaptime_string, + sizeof(snaptime_string)); + if (snaptime_len <= 0) { + return NULL; + } + + result = talloc_asprintf(mem_ctx, "%s/%s", + config->snapshot_basepath, snaptime_string); + if (result == NULL) { + DEBUG(1, (__location__ " talloc_asprintf failed\n")); + } + + return result; +} + +/** * Strip a snapshot component from an filename as * handed in via the smb layer. * Returns the parsed timestamp and the stripped filename. -- 1.8.3.2 From 9494a239db78eb9182596ff31797694c724114d8 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 17:14:49 +0200 Subject: [PATCH 22/36] shadow_copy2: add comments explaining decisions in shadow_copy2_strip_snapshot() This should make it more easy to understand what the cases are. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 3d053b1ab3e0b918509e06086a54834a9ae9cdb7) --- source3/modules/vfs_shadow_copy2.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ec60884..ade8c28 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -316,6 +316,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, goto no_snapshot; } if ((p > name) && (p[-1] != '/')) { + /* the GMT-token does not start a path-component */ goto no_snapshot; } q = strptime(p, GMT_FORMAT, &tm); @@ -328,6 +329,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, goto no_snapshot; } if ((p == name) && (q[0] == '\0')) { + /* the name consists of only the GMT token */ if (pstripped != NULL) { stripped = talloc_strdup(mem_ctx, ""); if (stripped == NULL) { @@ -339,6 +341,14 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, return true; } if (q[0] != '/') { + /* + * The GMT token is either at the end of the path + * or it is not a complete path component, i.e. the + * path component continues after the gmt-token. + * + * TODO: Is this correct? Or would the GMT tag as the + * last component be a valid input? + */ goto no_snapshot; } q += 1; -- 1.8.3.2 From 8dbe80761c0741ad34f5b9c17620b4dff0a2b2c1 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 23:57:30 +0200 Subject: [PATCH 23/36] shadow_copy2: add some debug to shadow_copy2_strip_snapshot() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit afcb84e69f46671030710bdda1c8798235b9ace7) --- source3/modules/vfs_shadow_copy2.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ade8c28..17eb8ba 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -311,6 +311,8 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return false); + DEBUG(10, (__location__ ": enter path '%s'\n", name)); + p = strstr_m(name, "@GMT-"); if (p == NULL) { goto no_snapshot; @@ -366,11 +368,19 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, return false; } + DEBUG(10, (__location__ ": snapdirseverywhere mode.\n" + "path '%s'.\n" + "insert string '%s'\n", name, insert)); + have_insert = (strstr(name, insert+1) != NULL); - TALLOC_FREE(insert); if (have_insert) { + DEBUG(10, (__location__ ": insert string '%s' found in " + "path '%s' found in snapdirseverywhere mode " + "==> already converted\n", insert, name)); + TALLOC_FREE(insert); goto no_snapshot; } + TALLOC_FREE(insert); } if (pstripped != NULL) { -- 1.8.3.2 From 2c9b42612d6d96af18efa7af7e3b55f52a677b93 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 17:16:23 +0200 Subject: [PATCH 24/36] shadow_copy2: fix shadow_copy2_strip_snapshot() in the classical case I.e., fix detection of already converted names. This is done by using the shadow_copy2_snapshot_path() function and comparing if the input string starts with that. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 4b8d9c65f45db426716763629f1e22b0eb859a99) --- source3/modules/vfs_shadow_copy2.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 17eb8ba..8c2e767 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -381,6 +381,36 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, goto no_snapshot; } TALLOC_FREE(insert); + } else { + char *snapshot_path; + char *s; + + snapshot_path = shadow_copy2_snapshot_path(talloc_tos(), + handle, + timestamp); + if (snapshot_path == NULL) { + errno = ENOMEM; + return false; + } + + DEBUG(10, (__location__ " path: '%s'.\n" + "snapshot path: '%s'\n", name, snapshot_path)); + + s = strstr(name, snapshot_path); + if (s == name) { + /* + * this starts with "snapshot_basepath/GMT-Token" + * so it is already a converted absolute + * path. Don't process further. + */ + DEBUG(10, (__location__ ": path '%s' starts with " + "snapshot path '%s' (not in " + "snapdirseverywhere mode) ==> " + "already converted\n", name, snapshot_path)); + talloc_free(snapshot_path); + goto no_snapshot; + } + talloc_free(snapshot_path); } if (pstripped != NULL) { -- 1.8.3.2 From 0c8e72db5d3ce31ce521ab31659703a6eb9a3695 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 28 May 2013 16:59:25 +0200 Subject: [PATCH 25/36] shadow_copy2: initialize "converted" string to null in shadow_copy2_convert() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 249e9b4a34d8959bd94735c1921ecfc24d6a2705) --- source3/modules/vfs_shadow_copy2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 8c2e767..ecf448d 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -509,7 +509,7 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, goto fail; } insertlen = talloc_get_size(insert)-1; - converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1); + converted = talloc_zero_array(mem_ctx, char, pathlen + insertlen + 1); if (converted == NULL) { goto fail; } -- 1.8.3.2 From 49326784c81dcfa43fec0456869ac840d9df2aa9 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 29 May 2013 15:06:22 +0200 Subject: [PATCH 26/36] shadow_copy2: add some blank lines for visual separation to shadow_copy2_convert() Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 86988db1f0ebd170d2bc91b6ed78f8845bfd270c) --- source3/modules/vfs_shadow_copy2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ecf448d..95249b2 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -504,11 +504,13 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, &slashes, &num_slashes)) { goto fail; } + insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp); if (insert == NULL) { goto fail; } insertlen = talloc_get_size(insert)-1; + converted = talloc_zero_array(mem_ctx, char, pathlen + insertlen + 1); if (converted == NULL) { goto fail; -- 1.8.3.2 From 8912cdaa6c6c1b215db2bb481cacc50ac81b2a31 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 23 May 2013 16:23:03 +0200 Subject: [PATCH 27/36] shadow_copy2: fix shadow_copy2_convert() in the classical case. I.e. the non-snapdirseverywhere case. This in particular fixes the case of a snapdir hierarchy that is parallel to the share or mountpoint and not subordinate. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 9ab89371c8eddad2f274736b508866e2a92b74a3) --- source3/modules/vfs_shadow_copy2.c | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 95249b2..cdab21e 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -490,6 +490,51 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config, return NULL); + DEBUG(10, ("converting '%s'\n", name)); + + if (!config->snapdirseverywhere) { + int ret; + char *snapshot_path; + + snapshot_path = shadow_copy2_snapshot_path(talloc_tos(), + handle, + timestamp); + if (snapshot_path == NULL) { + goto fail; + } + + if (config->rel_connectpath == NULL) { + converted = talloc_asprintf(mem_ctx, "%s/%s", + snapshot_path, name); + } else { + converted = talloc_asprintf(mem_ctx, "%s/%s/%s", + snapshot_path, + config->rel_connectpath, + name); + } + if (converted == NULL) { + goto fail; + } + + ZERO_STRUCT(converted_fname); + converted_fname.base_name = converted; + + ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname); + DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n", + converted, + ret, ret == 0 ? "ok" : strerror(errno))); + if (ret == 0) { + DEBUG(10, ("Found %s\n", converted)); + result = converted; + converted = NULL; + goto fail; + } else { + errno = ENOENT; + goto fail; + } + /* never reached ... */ + } + path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath, name); if (path == NULL) { @@ -498,8 +543,6 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, } pathlen = talloc_get_size(path)-1; - DEBUG(10, ("converting %s\n", path)); - if (!shadow_copy2_find_slashes(talloc_tos(), path, &slashes, &num_slashes)) { goto fail; -- 1.8.3.2 From 6d06efa4919de7174bf56057f6f0e514ee6bda2e Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 31 May 2013 00:45:16 +0200 Subject: [PATCH 28/36] shadow_copy2: improve debug in shadow_copy2_convert() in snapdirseverywhere mode Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 935120dbc01890e313e2902b13141d4a13fe96d5) --- source3/modules/vfs_shadow_copy2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index cdab21e..950f290 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -613,7 +613,8 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname); - DEBUG(10, ("Trying %s: %d (%s)\n", converted, + DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n", + converted, ret, ret == 0 ? "ok" : strerror(errno))); if (ret == 0) { /* success */ -- 1.8.3.2 From 58617fa8d1710597c4fb594236ee3ed955d8fec6 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 31 May 2013 00:46:01 +0200 Subject: [PATCH 29/36] shadow_copy2: use stored mount_point instead of recalculating. In the case of snapdirseverywhere but NOT crossmountpoints. This spares stat calls. And is the only correct thing to do if the mount point was specified in the configuration. Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett (cherry picked from commit 6ccbc1347d3240fc3c874a1957b654456fb6234c) --- source3/modules/vfs_shadow_copy2.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 950f290..ebc50e9 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -577,15 +577,7 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, min_offset = 0; if (!config->crossmountpoints) { - char *mount_point; - - mount_point = shadow_copy2_find_mount_point(talloc_tos(), - handle); - if (mount_point == NULL) { - goto fail; - } - min_offset = strlen(mount_point); - TALLOC_FREE(mount_point); + min_offset = strlen(config->mount_point); } memcpy(converted, path, pathlen+1); -- 1.8.3.2 From 254b3ac95c2e137ae125ee91fffc747a39596bc8 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 4 Dec 2013 13:40:14 +0100 Subject: [PATCH 30/36] s3:module:shadow_copy2: add my (C) Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke Reviewed-by: Andrew Bartlett (cherry picked from commit b5b5674287c935bf923cf570cf218ffb0ae7ce78) --- source3/modules/vfs_shadow_copy2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ebc50e9..1018bcc 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -5,6 +5,7 @@ * Copyright (C) Ed Plese 2009 * Copyright (C) Volker Lendecke 2011 * Copyright (C) Christian Ambach 2011 + * Copyright (C) Michael Adam 2013 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- 1.8.3.2 From 2395f7380307f53a977e34f0ce26da2ba29e8715 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 4 Dec 2013 15:50:26 +0100 Subject: [PATCH 31/36] s3:modules:shadow_copy2: improve headline comment Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke Reviewed-by: Andrew Bartlett (cherry picked from commit bffaf17d482cb1ad88698ea1a00aa7e4ddb0c0e7) --- source3/modules/vfs_shadow_copy2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 1018bcc..41a2a0e 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1,5 +1,5 @@ /* - * Third attempt at a shadow copy module + * shadow_copy2: a shadow copy module (second implementation) * * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2) * Copyright (C) Ed Plese 2009 -- 1.8.3.2 From 85a691d71532e7a2fe80d42e7e5f89ced497d70a Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 4 Dec 2013 15:55:19 +0100 Subject: [PATCH 32/36] s3:modules:shadow_copy2: remove redundant documentation comment block and refer to the manual page instead Signed-off-by: Michael Adam Reviewed-by: Volker Lendecke Reviewed-by: Andrew Bartlett (cherry picked from commit 6685e6512e03d9420439a730a40fcca3411a48db) --- source3/modules/vfs_shadow_copy2.c | 81 ++------------------------------------ 1 file changed, 4 insertions(+), 77 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 41a2a0e..8243f63 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -23,83 +23,10 @@ */ /* - - This is a 3rd implemetation of a shadow copy module for exposing - snapshots to windows clients as shadow copies. This version has the - following features: - - 1) you don't need to populate your shares with symlinks to the - snapshots. This can be very important when you have thousands of - shares, or use [homes] - - 2) the inode number of the files is altered so it is different - from the original. This allows the 'restore' button to work - without a sharing violation - - 3) shadow copy results can be sorted before being sent to the - client. This is beneficial for filesystems that don't read - directories alphabetically (the default unix). - - 4) vanity naming for snapshots. Snapshots can be named in any - format compatible with str[fp]time conversions. - - 5) time stamps in snapshot names can be represented in localtime - rather than UTC. - - Module options: - - shadow:snapdir = - - This is the directory containing the @GMT-* snapshot directories. If it is an absolute - path it is used as-is. If it is a relative path, then it is taken relative to the mount - point of the filesystem that the root of this share is on - - shadow:basedir = - - This is an optional parameter that specifies the directory that - the snapshots are relative to. It defaults to the filesystem - mount point - - shadow:fixinodes = yes/no - - If you enable shadow:fixinodes then this module will modify the - apparent inode number of files in the snapshot directories using - a hash of the files path. This is needed for snapshot systems - where the snapshots have the same device:inode number as the - original files (such as happens with GPFS snapshots). If you - don't set this option then the 'restore' button in the shadow - copy UI will fail with a sharing violation. - - shadow:sort = asc/desc, or not specified for unsorted (default) - - This is an optional parameter that specifies that the shadow - copy directories should be sorted before sending them to the - client. This can be beneficial as unix filesystems are usually - not listed alphabetically sorted. If enabled, you typically - want to specify descending order. - - shadow:format = - - This is an optional parameter that specifies the format - specification for the naming of snapshots. The format must - be compatible with the conversion specifications recognized - by str[fp]time. The default value is "@GMT-%Y.%m.%d-%H.%M.%S". - - shadow:sscanf = yes/no (default is no) - - The time is the unsigned long integer (%lu) in the format string - rather than a time strptime() can parse. The result must be a unix time_t - time. - - shadow:localtime = yes/no (default is no) - - This is an optional parameter that indicates whether the - snapshot names are in UTC/GMT or the local time. - - - The following command would generate a correctly formatted directory name - for use with the default parameters: - date -u +@GMT-%Y.%m.%d-%H.%M.%S + * This is a second implemetation of a shadow copy module for exposing + * file system snapshots to windows clients as shadow copies. + * + * See the manual page for documentation. */ #include "includes.h" -- 1.8.3.2 From 3e4506799758bf3616e982ce9e8a5105b64bd10b Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 4 Dec 2013 10:27:24 +0100 Subject: [PATCH 33/36] docs: update the manpage of vfs_shadow_copy2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the configuration and all the options available for the shadow_copy2 module. Pair-Programmed-With: Björn Baumbach Signed-off-by: Michael Adam Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Fri Dec 6 22:26:31 CET 2013 on sn-devel-104 (cherry picked from commit f6ac6f20540f81257e1f180454b6a2c1239e85fa) --- docs-xml/manpages/vfs_shadow_copy2.8.xml | 290 ++++++++++++++++++++++++++----- 1 file changed, 242 insertions(+), 48 deletions(-) diff --git a/docs-xml/manpages/vfs_shadow_copy2.8.xml b/docs-xml/manpages/vfs_shadow_copy2.8.xml index b313416..4f60667 100644 --- a/docs-xml/manpages/vfs_shadow_copy2.8.xml +++ b/docs-xml/manpages/vfs_shadow_copy2.8.xml @@ -13,7 +13,8 @@ vfs_shadow_copy2 - Expose snapshots to Windows clients as shadow copies. + Expose snapshots to Windows clients as shadow copies. + @@ -29,21 +30,57 @@ samba 7 suite. - The vfs_shadow_copy2 VFS module functionality - that is similar to Microsoft Shadow Copy services. When setup properly, + + The vfs_shadow_copy2 VFS module offers a + functionality similar to Microsoft Shadow Copy services. + When set up properly, this module allows Microsoft Shadow Copy clients to browse - "shadow copies" on Samba shares. + through file system snapshots as "shadow copies" on Samba shares. - This is a 2nd implementation of a shadow copy module. This - version has the following features: + + This is a second implementation of a shadow copy module + which has the following additional features (compared to the original + shadow_copy + 8 module): + - You don't need to populate your shares with symlinks to the - snapshots. This can be very important when you have thousands of - shares, or use [homes]. - The inode number of the files is altered so it is different - from the original. This allows the 'restore' button to work - without a sharing violation. + + There is no need any more to populate your share's root directory + with symlinks to the snapshots if the file system stores the + snapshots elsewhere. + Instead, you can flexibly configure the module where to look for + the file system snapshots. + This can be very important when you have thousands of + shares, or use [homes]. + + + Snapshot directories need not be in one fixed central place but + can be located anywhere in the directory tree. This mode helps to + support file systems that offer snapshotting of particutlar + subtrees, for example the GPFS independent file sets. + + + Vanity naming for snapshots: snapshots can be named in any format + compatible with with str[fp]time conversions. + + + Timestamps can be represented in localtime rather than UTC. + + + The inode number of the files can optionally be altered to be + different from the original. This fixes the 'restore' button + in the Windows GUI to work without a sharing violation when + serving from file systems, like GPFS, that return the same + device and inode number for the snapshot file and the original. + + + Shadow copy results are by default sorted before being sent to the + client. This is beneficial for filesystems that don't read + directories alphabetically (the default unix). Sort ordering can be + configured and sorting can be turned off completely if the file + system sorts its directory listing. + This module is stackable. @@ -58,25 +95,32 @@ support for this. - Filesystem snapshots must be mounted on + Filesystem snapshots must be available under specially named directories in order to be recognized by - vfs_shadow_copy2. The snapshot mount points must - be immediate children of a the directory being shared. - - The snapshot naming convention is @GMT-YYYY.MM.DD-hh.mm.ss, - where: + vfs_shadow_copy2. These snapshot directory + is typically a direct subdirectory of the share root's mountpoint + but there are other modes that can be configured with the + parameters described in detail below. + + The snapshot at a given point in time is expected in a + subdirectory of the snapshot directory where the snapshot's + directory is expected to be a formatted version of the + snapshot time. The default format which can be changed + with the shadow:format option + is @GMT-YYYY.MM.DD-hh.mm.ss, where: - YYYY is the 4 digit year - MM is the 2 digit month - DD is the 2 digit day - hh is the 2 digit hour - mm is the 2 digit minute - ss is the 2 digit second. - + YYYY is the 4 digit year + MM is the 2 digit month + DD is the 2 digit day + hh is the 2 digit hour + mm is the 2 digit minute + ss is the 2 digit second. + - The vfs_shadow_copy2 snapshot naming convention can be - produced with the following date + The vfs_shadow_copy2 snapshot naming + convention can be produced with the following + date 1 command: TZ=GMT date +@GMT-%Y.%m.%d-%H.%M.%S @@ -89,11 +133,47 @@ + shadow:mountpoint = MOUNTPOINT + + + + With this parameter, one can specify the mount point + of the filesystem that contains the share path. + Usually this mount point is automatically detected. + But for some constellations, in particular tests, + it can be convenient to be able to specify it. + + Example: shadow:mountpoint = /path/to/filesystem + Default: shadow:mountpoint = NOT SPECIFIED + + + + shadow:snapdir = SNAPDIR - Path to the directory where snapshots are kept. - + + Path to the directory where the file system of + the share keeps its snapshots. + If an absolute path is specified, it is used as-is. + If a relative path is specified, then it is taken + relative to the mount point of the filesystem of + the share root. (See shadow:mountpoint.) + + + Note that shadow:snapdirseverywhere + depends on this parameter and needs a relative path. + Setting an absolute path disables + shadow:snapdirseverywhere. + + + Note that the shadow:crossmountpoints + option also requires a relative snapdir. + Setting an absolute path disables + shadow:crossmountpoints. + + Example: shadow:snapdir = /some/absolute/path + Default: shadow:snapdir = .snapshots @@ -101,21 +181,65 @@ shadow:basedir = BASEDIR - Path to the base directory that snapshots are from. - + + The basedir option allows to specify a directory + between the share's mount point and the share root, + relative to which the file system's snapshots are taken. + + + For example, if + + + basedir = mountpoint/rel_basedir + + + share_root = basedir/rel_share_root + + + snapshot_path = mountpoint/snapdir + + + or + snapshot_path = snapdir + if snapdir is absolute + + + then the snapshot of a + file = mountpoint/rel_basedir/rel_share_root/rel_file + at a time TIME will be found under + snapshot_path/FS_GMT_TOKEN(TIME)/rel_share_root/rel_file, + where FS_GMT_TOKEN(TIME) is the timestamp string belonging + to TIME in the format required by the file system. + (See shadow:format.) + + The default for the basedir is the mount point + of the file system of the share root + (see shadow:mountpoint). + + + Note that the shadow:snapdirseverywhere + and shadow:crossmountpoints + options are incompatible with shadow:basedir + and disable the basedir setting. + - shadow:sort = asc/desc, or not specified for unsorted (default) + shadow:sort = asc/desc - By this parameter one can specify that the shadow - copy directories should be sorted before they are sent to the - client. This can be beneficial as unix filesystems are usually - not listed alphabetically sorted. If enabled, you typically - want to specify descending order. - + By default, this module sorts the shadow copy data + alphabetically before sending it to the client. + With this parameter, one can specify the sort order. + Possible known values are desc (descending, the default) + and asc (ascending). If the file system lists directories + alphabetically sorted, one can turn off sorting in this + module by specifying any other value. + + Example: shadow:sort = asc + Example: shadow:sort = none + Default: shadow:sort = desc @@ -124,9 +248,10 @@ This is an optional parameter that indicates whether the - snapshot names are in UTC/GMT or in local time. By default - UTC is expected. + snapshot names are in UTC/GMT or in local time. If it is + disabled then UTC/GMT is expected. + shadow:localtime = no @@ -135,14 +260,28 @@ This is an optional parameter that specifies the format - specification for the naming of snapshots. The format must - be compatible with the conversion specifications recognized - by str[fp]time. The default value is "@GMT-%Y.%m.%d-%H.%M.%S". + specification for the naming of snapshots in the file system. + The format must be compatible with the conversion + specifications recognized by str[fp]time. + Default: shadow:format = "@GMT-%Y.%m.%d-%H.%M.%S" + shadow:sscanf = yes/no + + + This paramter can be used to specify that the time in + format string is given as an unsigned long integer (%lu) + rather than a time strptime() can parse. + The result must be a unix time_t time. + + Default: shadow:sscanf = no + + + + shadow:fixinodes = yes/no @@ -155,23 +294,78 @@ this option then the 'restore' button in the shadow copy UI will fail with a sharing violation. + Default: shadow:fixinodes = no + shadow:snapdirseverywhere = yes/no - If you enable - shadow:snapdirseverywhere then this module will look - out for snapshot directories in the current and all parent - directories of the current working directory. + + If you enable + shadow:snapdirseverywhere + then this module will look + out for snapshot directories in the current working directory + and all parent directories, stopping at the mount point + by default. + But see shadow:crossmountpoints how to change + that behaviour. + + An example where this is needed are independent filesets in IBM's GPFS, but other filesystems might support snapshotting only particular subtrees of the filesystem as well. + + Note that shadow:snapdirseverywhere + depends on shadow:snapdir and needs it to be + a relative path. Setting an absolute snapdir path disables + shadow:snapdirseverywhere. + + + Note that this option is incompatible with the + shadow:basedir option and removes the + shadow:basedir setting by itself. + + Example: shadow:snapdirseverywhere = yes + Default: shadow:snapdirseverywhere = no + + shadow:crossmountpoints = yes/no + + + + This option is effective in the case of + shadow:snapdirseverywhere = yes. + Setting this option makes the module not stop at the + first mount point encountered when looking for snapdirs, + but lets it search potentially all through the path + instead. + + + An example where this is needed are independent filesets in + IBM's GPFS, but other filesystems might support snapshotting + only particular subtrees of the filesystem as well. + + + Note that shadow:snapdirseverywhere + depends on shadow:snapdir and needs it to be + a relative path. Setting an absolute snapdir path disables + shadow:snapdirseverywhere. + + + Note that this option is incompatible with the + shadow:basedir option and removes the + shadow:basedir setting by itself. + + Example: shadow:crossmountpoints = yes + Default: shadow:crossmountpoints = no + + + @@ -209,7 +403,7 @@ VERSION - This man page is correct for version 3.2.7 of the Samba suite. + This man page is correct for version 4.0 of the Samba suite. -- 1.8.3.2 From 4f810e8d20fe7a6ac204e662f5355c02c0f69ba0 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 10 Dec 2013 15:24:31 +0100 Subject: [PATCH 34/36] docs: Fix typos in vfs_shadow_copy2.8.xml. Signed-off-by: Karolin Seeger Reviewed-by: David Disseldorp Autobuild-User(master): David Disseldorp Autobuild-Date(master): Tue Dec 10 18:49:21 CET 2013 on sn-devel-104 (cherry picked from commit c16afddeef2938e218df63b1c669caa5fb65d39c) --- docs-xml/manpages/vfs_shadow_copy2.8.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs-xml/manpages/vfs_shadow_copy2.8.xml b/docs-xml/manpages/vfs_shadow_copy2.8.xml index 4f60667..1cb9aba 100644 --- a/docs-xml/manpages/vfs_shadow_copy2.8.xml +++ b/docs-xml/manpages/vfs_shadow_copy2.8.xml @@ -57,12 +57,12 @@ Snapshot directories need not be in one fixed central place but can be located anywhere in the directory tree. This mode helps to - support file systems that offer snapshotting of particutlar + support file systems that offer snapshotting of particular subtrees, for example the GPFS independent file sets. Vanity naming for snapshots: snapshots can be named in any format - compatible with with str[fp]time conversions. + compatible with str[fp]time conversions. Timestamps can be represented in localtime rather than UTC. -- 1.8.3.2 From 8ccf1e0c86572fe843e560e189cd375aed15cdfb Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 11 Dec 2013 09:34:47 +0100 Subject: [PATCH 35/36] shadow_copy2: revert expensive and unnecessary zero-initialization I was being overly cautious. This is initialization is not necessary, since further down in the for-loop, the memory always gets fully initialized because the insert string is inserted at various slash positions. So this talloc_zero_array can be skipped: this an expensive thing to do in virtually every VFS call. This essentially reverts commit 249e9b4a34d8959bd94735c1921ecfc24d6a2705. Signed-off-by: Michael Adam Reviewed-by: Andreas Schneider (cherry picked from commit 71318d7d685f8e1e112076f84ef2d788acb83547) --- source3/modules/vfs_shadow_copy2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 8243f63..7f5aeb2 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -482,7 +482,7 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, } insertlen = talloc_get_size(insert)-1; - converted = talloc_zero_array(mem_ctx, char, pathlen + insertlen + 1); + converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1); if (converted == NULL) { goto fail; } -- 1.8.3.2 From 9314a71202a7d5532fce3aca5325a5d360ef1027 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 11 Dec 2013 09:41:38 +0100 Subject: [PATCH 36/36] shadow_copy2: add a comment explaining why we don't talloc_zero_array(). Since I stumbled over this slighly sublte point, I thought it is worthwile to point it our in a comment. Signed-off-by: Michael Adam Reviewed-by: Andreas Schneider Autobuild-User(master): Michael Adam Autobuild-Date(master): Wed Dec 11 19:55:20 CET 2013 on sn-devel-104 (cherry picked from commit 27baff0ec96cded0446ecd7739e9d31aaeb90868) --- source3/modules/vfs_shadow_copy2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 7f5aeb2..fca05cf 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -482,6 +482,15 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx, } insertlen = talloc_get_size(insert)-1; + /* + * Note: We deliberatly don't expensively initialize the + * array with talloc_zero here: Putting zero into + * converted[pathlen+insertlen] below is sufficient, because + * in the following for loop, the insert string is inserted + * at various slash places. So the memory up to position + * pathlen+insertlen will always be initialized when the + * converted string is used. + */ converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1); if (converted == NULL) { goto fail; -- 1.8.3.2