[PATCHSET] fix and improve shadow_copy2 [Re: vfs_shadow_copy2] configuration

Michael Adam obnox at samba.org
Fri Oct 4 06:19:23 MDT 2013


Hi,

attached find the polished patchset that
contains all my fixes and improvements for the
shadow_copy2 module.

The code is the same as the one tested before
from the WIP patchset, except for very few minor
cleanups and a couple of omitted debug messages.

Review/comments/push appreciated!

Note: the patchset on top of current master is in my
"master-shadow_copy2 " branch in
git://git.samba.org/obnox/samba/samba-obnox.git

http://gitweb.samba.org/?p=obnox/samba/samba-obnox.git;a=shortlog;h=refs/heads/master-shadow_copy2

A few WIP patches, in particular a started torture
suite for the shadow-copies are in the master-shadow_copy2-wip branch

http://gitweb.samba.org/?p=obnox/samba/samba-obnox.git;a=shortlog;h=refs/heads/master-shadow_copy2-wip

Cheers - Michael

On 2013-09-30 at 09:47 +0200, Michael Adam wrote:
> Hi Dan,
> 
> On 2013-09-30 at 09:32 +0200, Dan Cohen1 wrote:
> > 
> > Thank you for your answer.
> > I've succeeded to clone your repository when using git.samba.org instead 
> > of gitweb.
> 
> Great!
> 
> FYI: I am currently working on polishing my patchset
> for upstream. So expect it to be presented to the list
> and hopefully to land in master in a couple of days' time.
> 
> Cheers - Michael
> 


-------------- next part --------------
From 773a774c440103d52271c3dbd526a2a9a9f673eb Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 4 Oct 2013 13:15:34 +0200
Subject: [PATCH 01/29] shadow_copy2: break overly long lines in
 shadow_copy2_snapshot_to_gmt()

According to coding guidelines.

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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, &timestamp_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(&timestamp_t, &timestamp);
 	} else {
 		if (strptime(name, fmt, &timestamp) == 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.7.9.5


From 495726ac62616a960da6703e223c453a054d0a72 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 23 May 2013 23:32:15 +0200
Subject: [PATCH 02/29] shadow_copy2: add comment header describing
 shadow_copy2_strip_snapshot()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 64daa1fe589a6e3d091f58b55a3e9d4c27227b07 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 23 May 2013 23:59:49 +0200
Subject: [PATCH 03/29] shadow_copy2: add header comment explaining
 have_snapdir()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 7d1d85416fc6dbbaf926384ec1572a02790b84d8 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 24 May 2013 00:01:14 +0200
Subject: [PATCH 04/29] shadow_copy2: add comment block explaining
 shadow_copy2_find_snapdir()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From deb8d4d1c659c8d3d86a9b72eeacab54b5e3617c Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 24 May 2013 17:20:42 +0200
Subject: [PATCH 05/29] shadow_copy2: add comment block explaining
 shadow_copy2_insert_string()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 9f0ac2efce5a3dcb09fd9917653e43af0cd699af Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 01:13:57 +0200
Subject: [PATCH 06/29] shadow_copy2: add comment block explaining
 shadow_copy2_convert()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 165baffc8b30a2e23c601eee3bf56a17502235fd Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 17:11:44 +0200
Subject: [PATCH 07/29] shadow_copy2: add comment explaining the SMB level GMT
 format pattern

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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 1288222..0d07f71 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.7.9.5


From 13eb90c6107d5d6172f5c9d019354b9d0ffee553 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 24 May 2013 01:35:44 +0200
Subject: [PATCH 08/29] 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 <obnox at samba.org>
---
 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 <ccan/hash/hash.h>
 #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, &timestamp_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(&timestamp);
 			gmtime_r(&timestamp_t, &timestamp);
@@ -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.7.9.5


From e85d967881a80d243ca86db3a3c00a619cba4d36 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 17:10:51 +0200
Subject: [PATCH 09/29] shadow_copy2: introduce the bool "snapdir_absolute" in
 the config.

Not exposed but to be used internally.

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 186e8fc2da7cb5c4d10759fb3ca7535f75cd787e Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 30 May 2013 13:19:50 +0200
Subject: [PATCH 10/29] shadow_copy2: disable "snapdir:crossmountpoints" if
 the snapdir is absolute.

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 8fb44b68493be4727c52d16b6a948a07862777cf Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 30 May 2013 17:26:44 +0200
Subject: [PATCH 11/29] 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 <bb at sernet.de>

Signed-off-by: Michael Adam <obnox at samba.org>
Signed-off-by: Bj?rn Baumbach <bb at sernet.de>
---
 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.7.9.5


From 3b48d191df3859d29ca6f1dec89b083913b11a11 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 31 May 2013 16:36:33 +0200
Subject: [PATCH 12/29] 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 <obnox at samba.org>
---
 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.7.9.5


From ed16af5d19beb8cb919c7c9c2b592bc13f995f10 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 4 Oct 2013 00:04:06 +0200
Subject: [PATCH 13/29] shadow_copy2: add rel_connectpath to config.

This is the share root, relative to the basedir.

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From e14b8d4d13c6162123356b62beaf9f08fa9cab8f Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 4 Oct 2013 00:07:15 +0200
Subject: [PATCH 14/29] shadow_copy2: add snapshot_basepath to the config.

This is the absolute version of snapdir.

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 1c71bc97b98f39a93050aa6ec2dfa58295376652 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 31 May 2013 17:17:27 +0200
Subject: [PATCH 15/29] shadow_copy2: log resulting config at the end of
 shadow_copy2_connect()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 38d4e2988d3a3fbe6d9fa50ff0a02f076824301c Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Sat, 1 Jun 2013 02:14:41 +0200
Subject: [PATCH 16/29] shadow_copy2: implement disk_free

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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,
+					 &timestamp, &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.7.9.5


From 129072869111d1dfcc021cf4025603a61c2388b1 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 23 May 2013 16:21:46 +0200
Subject: [PATCH 17/29] 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 <obnox at samba.org>
---
 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.7.9.5


From 38b8ad435983289e53b82e4cb3c485acbb218327 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Tue, 28 May 2013 17:01:20 +0200
Subject: [PATCH 18/29] 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 <obnox at samba.org>
---
 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.7.9.5


From ed0678aac5d00cdfb7acd71f5fdcc63fddfed9c6 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 17:12:21 +0200
Subject: [PATCH 19/29] shadow_copy2: shadow_copy2_insert_string(): do not
 prepend a "/" in absolute mode

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From e8c05b8145bfe496adfb5863e786e0fc469dd55f Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 30 May 2013 23:51:02 +0200
Subject: [PATCH 20/29] shadow_copy2: factor shadow_copy2_posix_gmt_string()
 out of shadow_copy2_insert_string()

for re-use..

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From f61343de07c13d3f032597fb6dd15116daecc4aa Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 31 May 2013 00:18:52 +0200
Subject: [PATCH 21/29] 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 <obnox at samba.org>
---
 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.7.9.5


From f015de0abcdbd4ae1f2771d20d6c2fec7d3539f5 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 17:14:49 +0200
Subject: [PATCH 22/29] 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 <obnox at samba.org>
---
 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.7.9.5


From c766bc5f2776a71604b0e77588631666762efccf Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 23:57:30 +0200
Subject: [PATCH 23/29] shadow_copy2: add some debug to
 shadow_copy2_strip_snapshot()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 96b8901895add35c86a4ce14fa568be014d3895f Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 17:16:23 +0200
Subject: [PATCH 24/29] 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 <obnox at samba.org>
---
 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.7.9.5


From f60e6ad089d20585166e28e85d6756243dd4e9e4 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Tue, 28 May 2013 16:59:25 +0200
Subject: [PATCH 25/29] shadow_copy2: initialize "converted" string to null in
 shadow_copy2_convert()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From fbea75d807172f5d8fc89203608cacfedc2d406c Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Wed, 29 May 2013 15:06:22 +0200
Subject: [PATCH 26/29] shadow_copy2: add some blank lines for visual
 separation to shadow_copy2_convert()

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From 01831ed78aea5ec2a101d8b383683b6c60dab32d Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Thu, 23 May 2013 16:23:03 +0200
Subject: [PATCH 27/29] 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 <obnox at samba.org>
---
 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.7.9.5


From 79ab9a65e4f6c832562ab93a03cbb3985bd032ca Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 31 May 2013 00:45:16 +0200
Subject: [PATCH 28/29] shadow_copy2: improve debug in shadow_copy2_convert()
 in snapdirseverywhere mode

Signed-off-by: Michael Adam <obnox at samba.org>
---
 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.7.9.5


From ace4f13dd42a0508612e1988961994825f215400 Mon Sep 17 00:00:00 2001
From: Michael Adam <obnox at samba.org>
Date: Fri, 31 May 2013 00:46:01 +0200
Subject: [PATCH 29/29] 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 <obnox at samba.org>
---
 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.7.9.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 215 bytes
Desc: Digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20131004/7fe1a8c4/attachment.pgp>


More information about the samba-technical mailing list