[PATCH] shadow_copy2: Allow configurable prefix for snapshots

Michael Adam obnox at samba.org
Wed Jul 27 14:57:15 UTC 2016


pushed the attached patchset to autobuild

Michael

On 2016-07-27 at 15:59 +0200, Michael Adam wrote:
> On 2016-07-22 at 15:35 +0200, Michael Adam wrote:
> > On 2016-07-22 at 12:00 +0300, Uri Simchoni wrote:
> > > Hi Rajesh,
> > > 
> > > RB+ me.
> > > 
> > > Can I get another Team reviewer?
> > 
> > I have started to (re-)review.
> > 
> > Thanks for the excellent review comments, btw, Uri!
> > I will comment or push later today.
> 
> Reviewed-by: me.
> 
> I have made a few super minor comment formatting
> adjustments (we usually do this as a function
> header comment block:
> 
> /**
>  * comment
>  * comment
>  * ...
>  */
> ) But otherwise this looks great.
> Ah, I fixed a xml tag mixup
> (variablelist closed too early) in the manpage
> as already spotted by Ira.
> 
> Gonna push after a local build/test.
> 
> Cheers - Michael
> 


-------------- next part --------------
From fd13744138aaabd2b82225ba0323581091764e75 Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Mon, 11 Jul 2016 12:28:46 +0000
Subject: [PATCH 1/7] shadow_copy2: Fix shadow_copy2_posix_gmt_string return
 type

This function returns -1 on error but the return type is
size_t which is unsigned.

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 source3/modules/vfs_shadow_copy2.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 43bc89d..115da71 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -88,13 +88,13 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
  * Given a timestamp, build the posix level GMT-tag string
  * based on the configurable format.
  */
-static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
+static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
 					    time_t snapshot,
 					    char *snaptime_string,
 					    size_t len)
 {
 	struct tm snap_tm;
-	size_t snaptime_len;
+	ssize_t snaptime_len;
 	struct shadow_copy2_config *config;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
@@ -107,7 +107,7 @@ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
 					(unsigned long)snapshot);
 		if (snaptime_len <= 0) {
 			DEBUG(10, ("snprintf failed\n"));
-			return snaptime_len;
+			return -1;
 		}
 	} else {
 		if (config->use_localtime) {
@@ -127,7 +127,7 @@ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
 					&snap_tm);
 		if (snaptime_len == 0) {
 			DEBUG(10, ("strftime failed\n"));
-			return 0;
+			return -1;
 		}
 	}
 
@@ -150,7 +150,7 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
 					time_t snapshot)
 {
 	fstring snaptime_string;
-	size_t snaptime_len = 0;
+	ssize_t snaptime_len = 0;
 	char *result = NULL;
 	struct shadow_copy2_config *config;
 
@@ -192,7 +192,7 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
 					time_t snapshot)
 {
 	fstring snaptime_string;
-	size_t snaptime_len = 0;
+	ssize_t snaptime_len = 0;
 	char *result = NULL;
 	struct shadow_copy2_config *config;
 
-- 
2.5.5


From a605ae4da80e3c088df6eacb62a0643d85d3353c Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Tue, 12 Jul 2016 09:33:29 +0000
Subject: [PATCH 2/7] shadow_copy2: Add test cases to cover shadow:format

Added test cases which will filter snapshot names based
on shadow:format option in smb.conf

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 selftest/target/Samba3.pm                | 44 ++++++++++++++++++++++++++++++++
 source3/script/tests/test_shadow_copy.sh | 35 +++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 5076c43..5c3f8e1 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1694,6 +1694,50 @@ sub provision($$$$$$$$)
 	shadow:snapdir = $shadow_tstdir/.snapshots
 	shadow:snapsharepath = share
 
+[shadow_fmt0]
+	comment = Testing shadow:format with default option
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:format = \@GMT-%Y.%m.%d-%H.%M.%S
+
+[shadow_fmt1]
+	comment = Testing shadow:format with only date component
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:format = \@GMT-%Y-%m-%d
+
+[shadow_fmt2]
+	comment = Testing shadow:format with some hardcoded prefix
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:format = snap\@GMT-%Y.%m.%d-%H.%M.%S
+
+[shadow_fmt3]
+	comment = Testing shadow:format with modified format
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:format = \@GMT-%Y.%m.%d-%H_%M_%S-snap
+
 [shadow_wl]
 	path = $shadow_shrdir
 	comment = previous versions with wide links allowed
diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
index 171008d..ef1f4e4 100755
--- a/source3/script/tests/test_shadow_copy.sh
+++ b/source3/script/tests/test_shadow_copy.sh
@@ -34,6 +34,12 @@ SNAPSHOTS[6]='@GMT-2021.10.31-19.40.30'
 SNAPSHOTS[7]='@GMT-2022.10.31-19.40.30'
 SNAPSHOTS[8]='@GMT-2023.10.31-19.40.30'
 SNAPSHOTS[9]='@GMT-2024.10.31-19.40.30'
+SNAPSHOTS[10]='@GMT-2010-11-11'
+SNAPSHOTS[11]='@GMT-2011.11.11-11.40.30'
+SNAPSHOTS[12]='snap at GMT-2012.11.11-11.40.30'
+SNAPSHOTS[13]='@GMT-2013.11.11-11_40_33-snap'
+SNAPSHOTS[14]='@GMT-2014.11.11-11.40.30'
+SNAPSHOTS[15]='daily at GMT-2015.11.11-11.40.30'
 
 # build a hierarchy of files, symlinks, and directories
 build_files()
@@ -261,6 +267,29 @@ test_shadow_copy_everywhere()
 
 }
 
+test_shadow_copy_format()
+{
+    local share     #share to contact
+    local where     #where to place snapshots
+    local prefix    #prefix to files inside snapshot
+    local ncopies_allowd
+    local msg
+
+    share=$1
+    where=$2
+    prefix=$3
+    ncopies_allowed=$4
+    msg=$5
+
+    #delete snapshots from previous tests
+    find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+    build_snapshots $WORKDIR/$where "$prefix" 10 15
+
+    testit "$msg - regular file" \
+        test_count_versions $share foo $ncopies_allowed || \
+        failed=`expr $failed + 1`
+}
+
 #build "latest" files
 build_files $WORKDIR/mount base/share "latest"
 
@@ -288,4 +317,10 @@ test_shadow_copy_fixed shadow7 mount/base/share "" "'everywhere' share snapshots
 # a test for snapshots everywhere - multiple snapshot locations
 test_shadow_copy_everywhere shadow7
 
+# tests for testing snapshot selection via shadow:format
+test_shadow_copy_format shadow_fmt0 mount/base share 3 "basic shadow:format test"
+test_shadow_copy_format shadow_fmt1 mount/base share 2 "shadow:format with only date"
+test_shadow_copy_format shadow_fmt2 mount/base share 2 "shadow:format with some prefix"
+test_shadow_copy_format shadow_fmt3 mount/base share 2 "shadow:format with modified format"
+
 exit $failed
-- 
2.5.5


From ab6d08cf71e391ce53167a45aa7bdefedfd8bc25 Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Mon, 11 Jul 2016 11:27:37 +0000
Subject: [PATCH 3/7] shadow_copy2: create structure to store module specific
 information

Create a separate structure to store module specific information. Currently
only config values are saved. As of now there is no cleaner way to store run-time
information or other module specific information in shadow_copy2 module.

Therefore created a new structure to store all module specific information
including config.

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 source3/modules/vfs_shadow_copy2.c | 80 +++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 115da71..0185842 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -50,6 +50,15 @@ struct shadow_copy2_config {
 	char *snapshot_basepath; /* the absolute version of snapdir */
 };
 
+
+/*
+ * shadow_copy2 private structure. This structure will be
+ * used to keep module specific information
+ */
+struct shadow_copy2_private {
+	struct shadow_copy2_config 	*config;
+};
+
 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
 				      size_t **poffsets,
 				      unsigned *pnum_offsets)
@@ -96,10 +105,13 @@ static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
 	struct tm snap_tm;
 	ssize_t snaptime_len;
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return 0);
 
+	config = priv->config;
+
 	if (config->use_sscanf) {
 		snaptime_len = snprintf(snaptime_string,
 					len,
@@ -153,10 +165,13 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
 	ssize_t snaptime_len = 0;
 	char *result = NULL;
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
+	config = priv->config;
+
 	snaptime_len = shadow_copy2_posix_gmt_string(handle,
 						     snapshot,
 						     snaptime_string,
@@ -194,9 +209,9 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
 	fstring snaptime_string;
 	ssize_t snaptime_len = 0;
 	char *result = NULL;
-	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
 	snaptime_len = shadow_copy2_posix_gmt_string(handle,
@@ -208,7 +223,7 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
 	}
 
 	result = talloc_asprintf(mem_ctx, "%s/%s",
-				 config->snapshot_basepath, snaptime_string);
+				 priv->config->snapshot_basepath, snaptime_string);
 	if (result == NULL) {
 		DEBUG(1, (__location__ " talloc_asprintf failed\n"));
 	}
@@ -233,12 +248,12 @@ 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;
+	struct shadow_copy2_private *priv;
 	const char *snapdir;
 	ssize_t snapdirlen;
 	ptrdiff_t len_before_gmt;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return false);
 
 	DEBUG(10, (__location__ ": enter path '%s'\n", name));
@@ -320,7 +335,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
 	rest_len = strlen(q);
 	dst_len = (p-name) + rest_len;
 
-	if (config->snapdirseverywhere) {
+	if (priv->config->snapdirseverywhere) {
 		char *insert;
 		bool have_insert;
 		insert = shadow_copy2_insert_string(talloc_tos(), handle,
@@ -453,11 +468,14 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
 	int i, saved_errno;
 	size_t min_offset;
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 	size_t in_share_offset = 0;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
+	config = priv->config;
+
 	DEBUG(10, ("converting '%s'\n", name));
 
 	if (!config->snapdirseverywhere) {
@@ -661,12 +679,12 @@ static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
 			 SMB_STRUCT_STAT *sbuf)
 {
-	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return);
 
-	if (config->fixinodes) {
+	if (priv->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
@@ -1218,14 +1236,14 @@ static char *have_snapdir(struct vfs_handle_struct *handle,
 {
 	struct smb_filename smb_fname;
 	int ret;
-	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
 	ZERO_STRUCT(smb_fname);
 	smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
-					      path, config->snapdir);
+					      path, priv->config->snapdir);
 	if (smb_fname.base_name == NULL) {
 		return NULL;
 	}
@@ -1285,10 +1303,13 @@ static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
 	char *path, *p;
 	const char *snapdir;
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
+	config = priv->config;
+
 	/*
 	 * If the non-snapdisrseverywhere mode, we should not search!
 	 */
@@ -1332,10 +1353,13 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
 	unsigned long int timestamp_long;
 	const char *fmt;
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
 
+	config = priv->config;
+
 	fmt = config->gmt_format;
 
 	ZERO_STRUCT(timestamp);
@@ -1387,12 +1411,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;
+	struct shadow_copy2_private *priv;
 
-	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return);
 
-	sort = config->sort_order;
+	sort = priv->config->sort_order;
 	if (sort == NULL) {
 		return;
 	}
@@ -2034,6 +2058,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 				const char *service, const char *user)
 {
 	struct shadow_copy2_config *config;
+	struct shadow_copy2_private *priv;
 	int ret;
 	const char *snapdir;
 	const char *gmt_format;
@@ -2051,13 +2076,22 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		return ret;
 	}
 
-	config = talloc_zero(handle->conn, struct shadow_copy2_config);
+	priv = talloc_zero(handle->conn, struct shadow_copy2_private);
+	if (priv == NULL) {
+		DEBUG(0, ("talloc_zero() failed\n"));
+		errno = ENOMEM;
+		return -1;
+	}
+
+	config = talloc_zero(priv, struct shadow_copy2_config);
 	if (config == NULL) {
 		DEBUG(0, ("talloc_zero() failed\n"));
 		errno = ENOMEM;
 		return -1;
 	}
 
+	priv->config = config;
+
 	gmt_format = lp_parm_const_string(SNUM(handle->conn),
 					  "shadow", "format",
 					  GMT_FORMAT);
@@ -2286,8 +2320,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		   ));
 
 
-	SMB_VFS_HANDLE_SET_DATA(handle, config,
-				NULL, struct shadow_copy2_config,
+	SMB_VFS_HANDLE_SET_DATA(handle, priv,
+				NULL, struct shadow_copy2_private,
 				return -1);
 
 	return 0;
-- 
2.5.5


From fa1b0d9b82bbf5e64cc06bf1a8718d5b06796ab9 Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Wed, 13 Jul 2016 18:59:18 +0000
Subject: [PATCH 4/7] shadow_copy2: allow configurable prefix for snapshot name

With growing number of snapshots file-systems need some mechanism
to differentiate one set of snapshots from other, e.g. monthly, weekly,
manual, special events, etc. Therefore these file-systems provide
different ways to tag snapshots, e.g. provide a configurable way to
name snapshots, which is not just based on time. With only shadow:format
it is very difficult to filter these snapshots.

As part of this change added two new options, shadow:snapprefix and
shadow:delimiter, in shadow_copy2 config. This option will accept regular
expression (BRE) as input. With this optional parameter, one can specify a
variable prefix component for names of the snapshot directories in the
file-system. If this parameter is set, together with the shadow:format and
shadow:delimiter parameters it determines the possible names of snapshot
directories in the file-system.

e.g.
shadow:snapprefix = [a-z]*[0-9]

When this option is provided then shadow:format option should always
start with <delimiter> string. This delimiter is configurable via a new option,
i.e. shadow:delimiter. Default value for this is "_GMT",
e.g. _GMT-%Y.%m.%d-%H.%M.%S

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 source3/modules/vfs_shadow_copy2.c | 310 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 303 insertions(+), 7 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 0185842..123901c 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -6,6 +6,7 @@
  * Copyright (C) Volker Lendecke   2011
  * Copyright (C) Christian Ambach  2011
  * Copyright (C) Michael Adam      2013
+ * Copyright (C) Rajesh Joseph     2016
  *
  * 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
@@ -40,6 +41,7 @@ struct shadow_copy2_config {
 	bool use_sscanf;
 	bool use_localtime;
 	char *snapdir;
+	char *delimiter;
 	bool snapdirseverywhere;
 	bool crossmountpoints;
 	bool fixinodes;
@@ -50,15 +52,164 @@ struct shadow_copy2_config {
 	char *snapshot_basepath; /* the absolute version of snapdir */
 };
 
+/* Data-structure to hold the list of snap entries */
+struct shadow_copy2_snapentry {
+	char *snapname;
+	char *time_fmt;
+	struct shadow_copy2_snapentry *next;
+	struct shadow_copy2_snapentry *prev;
+};
+
+struct shadow_copy2_snaplist_info {
+	struct shadow_copy2_snapentry *snaplist; /* snapshot list */
+	regex_t *regex; /* Regex to filter snaps */
+	time_t fetch_time; /* snaplist update time */
+};
+
 
 /*
  * shadow_copy2 private structure. This structure will be
  * used to keep module specific information
  */
 struct shadow_copy2_private {
-	struct shadow_copy2_config 	*config;
+	struct shadow_copy2_config *config;
+	struct shadow_copy2_snaplist_info *snaps;
 };
 
+static int shadow_copy2_get_shadow_copy_data(
+	vfs_handle_struct *handle, files_struct *fsp,
+	struct shadow_copy_data *shadow_copy2_data,
+	bool labels);
+
+/**
+ *This function will create a new snapshot list entry and
+ * return to the caller. This entry will also be added to
+ * the global snapshot list.
+ *
+ * @param[in]   priv	shadow_copy2 specific data structure
+ * @return	Newly   created snapshot entry or NULL on failure
+ */
+static struct shadow_copy2_snapentry *shadow_copy2_create_snapentry(
+					struct shadow_copy2_private *priv)
+{
+	struct shadow_copy2_snapentry *tmpentry = NULL;
+
+	tmpentry = talloc_zero(priv->snaps, struct shadow_copy2_snapentry);
+	if (tmpentry == NULL) {
+		DBG_ERR("talloc_zero() failed\n");
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	DLIST_ADD(priv->snaps->snaplist, tmpentry);
+
+	return tmpentry;
+}
+
+/**
+ *This function will delete the entire snaplist and reset
+ * priv->snaps->snaplist to NULL.
+ *
+ * @param[in] priv shadow_copye specific data structure
+ */
+static void shadow_copy2_delete_snaplist(struct shadow_copy2_private *priv)
+{
+	struct shadow_copy2_snapentry *tmp = NULL;
+
+	while ((tmp = priv->snaps->snaplist) != NULL) {
+		DLIST_REMOVE(priv->snaps->snaplist, tmp);
+		talloc_free(tmp);
+	}
+}
+
+/**
+ * Given a timestamp this function searches the global snapshot list
+ * and returns the complete snapshot directory name saved in the entry.
+ *
+ * @param[in]   priv		shadow_copy2 specific structure
+ * @param[in]   timestamp	timestamp corresponding to one of the snapshot
+ * @param[out]  snap_str	buffer to copy the actual snapshot name
+ * @param[in]   len		length of snap_str buffer
+ *
+ * @return 	Length of actual snapshot name, and -1 on failure
+ */
+static ssize_t shadow_copy2_saved_snapname(struct shadow_copy2_private *priv,
+					  struct tm *timestamp,
+					  char *snap_str, size_t len)
+{
+	ssize_t snaptime_len = -1;
+	struct shadow_copy2_snapentry *entry = NULL;
+
+	snaptime_len = strftime(snap_str, len, GMT_FORMAT, timestamp);
+	if (snaptime_len == 0) {
+		DBG_ERR("strftime failed\n");
+		return -1;
+	}
+
+	snaptime_len = -1;
+
+	for (entry = priv->snaps->snaplist; entry; entry = entry->next) {
+		if (strcmp(entry->time_fmt, snap_str) == 0) {
+			snaptime_len = snprintf(snap_str, len, "%s",
+						entry->snapname);
+			return snaptime_len;
+		}
+	}
+
+	snap_str[0] = 0;
+	return snaptime_len;
+}
+
+
+/**
+ * This function will check if snaplist is updated or not. If snaplist
+ * is empty then it will create a new list. Each time snaplist is updated
+ * the time is recorded. If the snapshot time is greater than the snaplist
+ * update time then chances are we are working on an older list. Then discard
+ * the old list and fetch a new snaplist.
+ *
+ * @param[in]   handle		VFS handle struct
+ * @param[in]   snap_time	time of snapshot
+ *
+ * @return 	true if the list is updated else false
+ */
+static bool shadow_copy2_update_snaplist(struct vfs_handle_struct *handle,
+		time_t snap_time)
+{
+	int ret = -1;
+	bool snaplist_updated = false;
+	struct files_struct fsp = {0};
+	struct smb_filename smb_fname = {0};
+	double seconds = 0.0;
+	struct shadow_copy2_private *priv = NULL;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return false);
+
+	seconds = difftime(snap_time, priv->snaps->fetch_time);
+
+	/*
+	 * Fetch the snapshot list if either the snaplist is empty or the
+	 * required snapshot time is greater than the last fetched snaplist
+	 * time.
+	 */
+	if (seconds > 0 || (priv->snaps->snaplist == NULL)) {
+		smb_fname.base_name = ".";
+		fsp.fsp_name = &smb_fname;
+
+		ret = shadow_copy2_get_shadow_copy_data(handle, &fsp,
+							NULL, false);
+		if (ret == 0) {
+			snaplist_updated = true;
+		} else {
+			DBG_ERR("Failed to get shadow copy data\n");
+		}
+
+	}
+
+	return snaplist_updated;
+}
+
 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
 				      size_t **poffsets,
 				      unsigned *pnum_offsets)
@@ -133,6 +284,28 @@ static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
 				return -1;
 			}
 		}
+
+		if (priv->snaps->regex != NULL) {
+			snaptime_len = shadow_copy2_saved_snapname(priv,
+						&snap_tm, snaptime_string, len);
+			if (snaptime_len >= 0)
+				return snaptime_len;
+
+			/*
+			 * If we fail to find the snapshot name, chances are
+			 * that we have not updated our snaplist. Make sure the
+			 * snaplist is updated.
+			 */
+			if (!shadow_copy2_update_snaplist(handle, snapshot)) {
+				DBG_DEBUG("shadow_copy2_update_snaplist "
+					  "failed\n");
+				return -1;
+			}
+
+			return shadow_copy2_saved_snapname(priv,
+						&snap_tm, snaptime_string, len);
+		}
+
 		snaptime_len = strftime(snaptime_string,
 					len,
 					config->gmt_format,
@@ -1354,6 +1527,10 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
 	const char *fmt;
 	struct shadow_copy2_config *config;
 	struct shadow_copy2_private *priv;
+	char *tmpstr = NULL;
+	char *tmp = NULL;
+	bool converted = false;
+	int ret = -1;
 
 	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
 				return NULL);
@@ -1362,13 +1539,38 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
 
 	fmt = config->gmt_format;
 
+	/*
+	 * If regex is provided, then we will have to parse the
+	 * filename which will contain both the prefix and the time format.
+	 * e.g. <prefix><delimiter><time_format>
+	 */
+	if (priv->snaps->regex != NULL) {
+		tmpstr = talloc_strdup(talloc_tos(), name);
+		/* point "name" to the time format */
+		name = strstr(name, priv->config->delimiter);
+		if (name == NULL) {
+			goto done;
+		}
+		/* Extract the prefix */
+		tmp = strstr(tmpstr, priv->config->delimiter);
+		*tmp = '\0';
+
+		/* Parse regex */
+		ret = regexec(priv->snaps->regex, tmpstr, 0, NULL, 0);
+		if (ret) {
+			DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
+				  "no regex match for %s\n", tmpstr);
+			goto done;
+		}
+	}
+
 	ZERO_STRUCT(timestamp);
 	if (config->use_sscanf) {
 		if (sscanf(name, fmt, &timestamp_long) != 1) {
 			DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
 				   "no sscanf match %s: %s\n",
 				   fmt, name));
-			return false;
+			goto done;
 		}
 		timestamp_t = timestamp_long;
 		gmtime_r(&timestamp_t, &timestamp);
@@ -1377,7 +1579,7 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
 			DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
 				   "no match %s: %s\n",
 				   fmt, name));
-			return false;
+			goto done;
 		}
 		DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
 			   fmt, name));
@@ -1390,7 +1592,11 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
 	}
 
 	strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
-	return true;
+	converted = true;
+
+done:
+	TALLOC_FREE(tmpstr);
+	return converted;
 }
 
 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
@@ -1448,6 +1654,9 @@ static int shadow_copy2_get_shadow_copy_data(
 	struct smb_filename *snapdir_smb_fname = NULL;
 	struct dirent *d;
 	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+	struct shadow_copy2_private *priv = NULL;
+	struct shadow_copy2_snapentry *tmpentry = NULL;
+	bool get_snaplist = false;
 	bool ret;
 
 	snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
@@ -1487,8 +1696,32 @@ static int shadow_copy2_get_shadow_copy_data(
 		return -1;
 	}
 
-	shadow_copy2_data->num_volumes = 0;
-	shadow_copy2_data->labels      = NULL;
+	if (shadow_copy2_data != NULL) {
+		shadow_copy2_data->num_volumes = 0;
+		shadow_copy2_data->labels      = NULL;
+	}
+
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return -1);
+
+	/*
+	 * Normally this function is called twice once with labels = false and
+	 * then with labels = true. When labels is false it will return the
+	 * number of volumes so that the caller can allocate memory for that
+	 * many labels. Therefore to eliminate snaplist both the times it is
+	 * good to check if labels is set or not.
+	 *
+	 * shadow_copy2_data is NULL when we only want to update the list and
+	 * don't want any labels.
+	 */
+	if ((priv->snaps->regex != NULL) && (labels || shadow_copy2_data == NULL)) {
+		get_snaplist = true;
+		/* Reset the global snaplist */
+		shadow_copy2_delete_snaplist(priv);
+
+		/* Set the current time as snaplist update time */
+		time(&(priv->snaps->fetch_time));
+	}
 
 	while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
 		char snapshot[GMT_NAME_LEN+1];
@@ -1509,6 +1742,25 @@ static int shadow_copy2_get_shadow_copy_data(
 		DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
 			 d->d_name, snapshot));
 
+		if (get_snaplist) {
+			/*
+			 * Create a snap entry for each successful
+			 * pattern match.
+			 */
+			tmpentry = shadow_copy2_create_snapentry(priv);
+			if (tmpentry == NULL) {
+				DBG_ERR("talloc_zero() failed\n");
+				talloc_free(tmp_ctx);
+				return -1;
+			}
+			tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
+			tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
+		}
+
+		if (shadow_copy2_data == NULL) {
+			continue;
+		}
+
 		if (!labels) {
 			/* the caller doesn't want the labels */
 			shadow_copy2_data->num_volumes++;
@@ -2061,6 +2313,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 	struct shadow_copy2_private *priv;
 	int ret;
 	const char *snapdir;
+	const char *snapprefix = NULL;
+	const char *delimiter;
 	const char *gmt_format;
 	const char *sort_order;
 	const char *basedir = NULL;
@@ -2078,7 +2332,14 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 
 	priv = talloc_zero(handle->conn, struct shadow_copy2_private);
 	if (priv == NULL) {
-		DEBUG(0, ("talloc_zero() failed\n"));
+		DBG_ERR("talloc_zero() failed\n");
+		errno = ENOMEM;
+		return -1;
+	}
+
+	priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info);
+	if (priv->snaps == NULL) {
+		DBG_ERR("talloc_zero() failed\n");
 		errno = ENOMEM;
 		return -1;
 	}
@@ -2119,6 +2380,37 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		return -1;
 	}
 
+	snapprefix = lp_parm_const_string(SNUM(handle->conn),
+				       "shadow", "snapprefix",
+				       NULL);
+	if (snapprefix != NULL) {
+		priv->snaps->regex = talloc_zero(priv->snaps, regex_t);
+		if (priv->snaps->regex == NULL) {
+			DBG_ERR("talloc_zero() failed\n");
+			errno = ENOMEM;
+			return -1;
+		}
+
+		/* pre-compute regex rule for matching pattern later */
+		ret = regcomp(priv->snaps->regex, snapprefix, 0);
+		if (ret) {
+			DBG_ERR("Failed to create regex object\n");
+			return -1;
+		}
+	}
+
+	delimiter = lp_parm_const_string(SNUM(handle->conn),
+				       "shadow", "delimiter",
+				       "_GMT");
+	if (delimiter != NULL) {
+		priv->config->delimiter = talloc_strdup(priv->config, delimiter);
+		if (priv->config->delimiter == NULL) {
+			DBG_ERR("talloc_strdup() failed\n");
+			errno = ENOMEM;
+			return -1;
+		}
+	}
+
 	config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
 						  "shadow",
 						  "snapdirseverywhere",
@@ -2298,6 +2590,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		   "  mountpoint: '%s'\n"
 		   "  rel share root: '%s'\n"
 		   "  snapdir: '%s'\n"
+		   "  snapprefix: '%s'\n"
+		   "  delimiter: '%s'\n"
 		   "  snapshot base path: '%s'\n"
 		   "  format: '%s'\n"
 		   "  use sscanf: %s\n"
@@ -2310,6 +2604,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 		   config->mount_point,
 		   config->rel_connectpath,
 		   config->snapdir,
+		   snapprefix,
+		   config->delimiter,
 		   config->snapshot_basepath,
 		   config->gmt_format,
 		   config->use_sscanf ? "yes" : "no",
-- 
2.5.5


From 990c12c4a4414f9701bb59639face81f5a70db8e Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Wed, 13 Jul 2016 16:15:27 +0000
Subject: [PATCH 5/7] shadow_copy2: Add test case for snapprefix and delimiter

Add test case for the newly addded option shadow:snapprefix
and shadow:delimiter

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 selftest/target/Samba3.pm                | 25 +++++++++++++++++++++++++
 source3/script/tests/test_shadow_copy.sh |  8 +++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 5c3f8e1..e8f35e3 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1738,6 +1738,31 @@ sub provision($$$$$$$$)
 	shadow:snapdir = $shadow_basedir/.snapshots
 	shadow:format = \@GMT-%Y.%m.%d-%H_%M_%S-snap
 
+[shadow_fmt4]
+	comment = Testing shadow:snapprefix regex
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:snapprefix = \^s[a-z]*p\$
+	shadow:format = _GMT-%Y.%m.%d-%H.%M.%S
+
+[shadow_fmt5]
+	comment = Testing shadow:snapprefix with delim regex
+	vfs object = shadow_copy2
+	path = $shadow_shrdir
+	read only = no
+	guest ok = yes
+	shadow:mountpoint = $shadow_mntdir
+	shadow:basedir = $shadow_basedir
+	shadow:snapdir = $shadow_basedir/.snapshots
+	shadow:delimiter = \@GMT
+	shadow:snapprefix = [a-z]*
+	shadow:format = \@GMT-%Y.%m.%d-%H.%M.%S
+
 [shadow_wl]
 	path = $shadow_shrdir
 	comment = previous versions with wide links allowed
diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
index ef1f4e4..45d9cf1 100755
--- a/source3/script/tests/test_shadow_copy.sh
+++ b/source3/script/tests/test_shadow_copy.sh
@@ -40,6 +40,10 @@ SNAPSHOTS[12]='snap at GMT-2012.11.11-11.40.30'
 SNAPSHOTS[13]='@GMT-2013.11.11-11_40_33-snap'
 SNAPSHOTS[14]='@GMT-2014.11.11-11.40.30'
 SNAPSHOTS[15]='daily at GMT-2015.11.11-11.40.30'
+SNAPSHOTS[16]='snap_GMT-2016.11.11-11.40.30'
+SNAPSHOTS[17]='sysp_GMT-2017.11.11-11.40.30'
+SNAPSHOTS[18]='monthly at GMT-2018.11.11-11.40.30'
+SNAPSHOTS[19]='straps_GMT-2019.11.11-11.40.33'
 
 # build a hierarchy of files, symlinks, and directories
 build_files()
@@ -283,7 +287,7 @@ test_shadow_copy_format()
 
     #delete snapshots from previous tests
     find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
-    build_snapshots $WORKDIR/$where "$prefix" 10 15
+    build_snapshots $WORKDIR/$where "$prefix" 10 19
 
     testit "$msg - regular file" \
         test_count_versions $share foo $ncopies_allowed || \
@@ -322,5 +326,7 @@ test_shadow_copy_format shadow_fmt0 mount/base share 3 "basic shadow:format test
 test_shadow_copy_format shadow_fmt1 mount/base share 2 "shadow:format with only date"
 test_shadow_copy_format shadow_fmt2 mount/base share 2 "shadow:format with some prefix"
 test_shadow_copy_format shadow_fmt3 mount/base share 2 "shadow:format with modified format"
+test_shadow_copy_format shadow_fmt4 mount/base share 3 "shadow:format with snapprefix"
+test_shadow_copy_format shadow_fmt5 mount/base share 6 "shadow:format with delimiter"
 
 exit $failed
-- 
2.5.5


From b69ad4a2a86eb30d9e52e5f145d5bafdc81ef635 Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Tue, 12 Jul 2016 11:01:32 +0000
Subject: [PATCH 6/7] shadow_copy2: update man pages for the newly introduced
 options

shadow:snapprefix and shadow:delimiter are the two newly added options
in shadow copy. Update man pages explaining the two options.

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 docs-xml/manpages/vfs_shadow_copy2.8.xml | 36 +++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/docs-xml/manpages/vfs_shadow_copy2.8.xml b/docs-xml/manpages/vfs_shadow_copy2.8.xml
index fbc0651..6097511 100644
--- a/docs-xml/manpages/vfs_shadow_copy2.8.xml
+++ b/docs-xml/manpages/vfs_shadow_copy2.8.xml
@@ -406,7 +406,41 @@
                 </listitem>
                 </varlistentry>
 
-		</variablelist>
+		<varlistentry>
+		<term>shadow:snapprefix
+		</term>
+		<listitem>
+		<para>
+		With growing number of snapshots file-systems need some mechanism
+		to differentiate one set of snapshots from other, e.g. monthly, weekly,
+		manual, special events, etc. Therefore these file-systems provide different
+		ways to tag snapshots, e.g. provide a configurable way to name snapshots,
+		which is not just based on time.  With only <command>shadow:format</command>
+		it is very difficult to filter these snapshots. With this optional parameter,
+		one can specify a variable prefix component for names of the snapshot
+		directories in the file-system. If this parameter is set, together with the
+		<command>shadow:format</command> and <command>shadow:delimiter</command>
+		parameters it determines the possible names of snapshot
+		directories in the file-system. The option only supports Basic
+		Regular Expression (BRE).
+		</para>
+		</listitem>
+		</varlistentry>
+
+		<varlistentry>
+		<term>shadow:delimiter
+		</term>
+		<listitem>
+		<para>
+		This optional parameter is used as a delimiter between
+		<command>shadow:snapprefix</command> and <command>shadow:format</command>.
+		This parameter is used only when <command>shadow:snapprefix</command>
+		is set.
+		</para>
+		<para>Default: shadow:delimiter = "_GMT"</para>
+		</listitem>
+		</varlistentry>
+	</variablelist>
 </refsect1>
 
 <refsect1>
-- 
2.5.5


From 797657db6e4ea2730d402649a29379425f43d3de Mon Sep 17 00:00:00 2001
From: Rajesh Joseph <rjoseph at redhat.com>
Date: Thu, 21 Jul 2016 09:58:43 +0000
Subject: [PATCH 7/7] shadow_copy2: Fix error handling in
 shadow_copy2_get_shadow_copy_data

Memory was freed in most of the failure cases. It is always better
to free the memory at the end of the function so that all exit path
of the function will free the memory. Otherwise chances are that
you might miss some cleanup.

Signed-off-by: Rajesh Joseph <rjoseph at redhat.com>
Reviewed-by: Uri Simchoni <uri at samba.org>
Reviewed-by: Michael Adam <obnox at samba.org>
---
 source3/modules/vfs_shadow_copy2.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 123901c..bda934e 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -1657,22 +1657,22 @@ static int shadow_copy2_get_shadow_copy_data(
 	struct shadow_copy2_private *priv = NULL;
 	struct shadow_copy2_snapentry *tmpentry = NULL;
 	bool get_snaplist = false;
-	bool ret;
+	bool access_granted = false;
+	int ret = -1;
 
 	snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
 	if (snapdir == NULL) {
 		DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
 			 handle->conn->connectpath));
 		errno = EINVAL;
-		talloc_free(tmp_ctx);
-		return -1;
+		goto done;
 	}
-	ret = check_access_snapdir(handle, snapdir);
-	if (!ret) {
+
+	access_granted = check_access_snapdir(handle, snapdir);
+	if (!access_granted) {
 		DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
 		errno = EACCES;
-		talloc_free(tmp_ctx);
-		return -1;
+		goto done;
 	}
 
 	snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
@@ -1682,8 +1682,7 @@ static int shadow_copy2_get_shadow_copy_data(
 					fsp->fsp_name->flags);
 	if (snapdir_smb_fname == NULL) {
 		errno = ENOMEM;
-		talloc_free(tmp_ctx);
-		return -1;
+		goto done;
 	}
 
 	p = SMB_VFS_NEXT_OPENDIR(handle, snapdir_smb_fname, NULL, 0);
@@ -1691,9 +1690,8 @@ static int shadow_copy2_get_shadow_copy_data(
 	if (!p) {
 		DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
 			 " - %s\n", snapdir, strerror(errno)));
-		talloc_free(tmp_ctx);
 		errno = ENOSYS;
-		return -1;
+		goto done;
 	}
 
 	if (shadow_copy2_data != NULL) {
@@ -1702,7 +1700,7 @@ static int shadow_copy2_get_shadow_copy_data(
 	}
 
 	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
-				return -1);
+				goto done);
 
 	/*
 	 * Normally this function is called twice once with labels = false and
@@ -1750,8 +1748,7 @@ static int shadow_copy2_get_shadow_copy_data(
 			tmpentry = shadow_copy2_create_snapentry(priv);
 			if (tmpentry == NULL) {
 				DBG_ERR("talloc_zero() failed\n");
-				talloc_free(tmp_ctx);
-				return -1;
+				goto done;
 			}
 			tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
 			tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
@@ -1774,8 +1771,7 @@ static int shadow_copy2_get_shadow_copy_data(
 		if (tlabels == NULL) {
 			DEBUG(0,("shadow_copy2: out of memory\n"));
 			SMB_VFS_NEXT_CLOSEDIR(handle, p);
-			talloc_free(tmp_ctx);
-			return -1;
+			goto done;
 		}
 
 		strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
@@ -1788,9 +1784,11 @@ static int shadow_copy2_get_shadow_copy_data(
 	SMB_VFS_NEXT_CLOSEDIR(handle,p);
 
 	shadow_copy2_sort_data(handle, shadow_copy2_data);
+	ret = 0;
 
-	talloc_free(tmp_ctx);
-	return 0;
+done:
+	TALLOC_FREE(tmp_ctx);
+	return ret;
 }
 
 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
-- 
2.5.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20160727/15e520bc/signature.sig>


More information about the samba-technical mailing list