[PATCH] shadow_copy2: Allow configurable prefix for snapshots

Uri Simchoni uri at samba.org
Sun May 8 20:11:15 UTC 2016


I haven't gone through the patch line-by-line yet but if Jeremy's
commenting, I have comments too:

1. Most of the config->x --> priv->config->x changes can be avoided by
adding a "config" local variable set to priv->config. This both makes
the patch smaller (and easier to review!), and in most if not all of the
cases represents (IMHO) better coding style.

2. The patch seems to require that the client first call
get_shadow_copy_data_fn, because that's where the snapentries get
populated. I think there's no such assumption in the code prior to the
patch. The unit tests go directly to the snapshots without listing them
first. Not sure what to make of this, perhaps we can start that way and
add lazy-population of the list if need arises.

3. About durable handles - I don't think durable handles are an issue,
or at least they should not be. We reconnect to the actual file, denoted
by its file id, and whose path is a result of all the path manipulations
and translations in the original open. Well, at least that's what we
should be doing, because we don't have special handling for durable
handles in each VFS module that fiddles with the path. In essence,
vfs_shadow_copy2 is yet another path-manipulation module.

4. Isn't regcomp expensive? It can be computed once at connect time.

Thanks,
Uri.

On 05/08/2016 09:42 PM, Jeremy Allison wrote:
> OK - I still need changes in the memory hierarchy
> for struct shadow_copy2_snapentry.
> 
> You're still treating the head of the list:
> 
> priv->snaplist
> 
> in a special way, in that it's talloc'ed off
> the containing struct, and then tallocing
> all the list entries off it.
> 
> Don't do that.
> 
> It allows you to free the list by doing
> TALLOC_FREE(priv->snaplist), but loses
> in the added complexity when creating
> the list.
> 
> *Never* manipulate lists with anything
> other than the DLIST_XXXX macros.
> 
> I have a long experience with mistakes
> added to the code by people doing exactly
> this, myself being one of them.
> 
> I know your code as written is safe, but
> the next person to modify it *will* screw
> it up (and the person might be me, as
> likely as not :-).
> 
> If you want to free the list with one
> TALLOC_FREE() then create a new talloc
> context as a member of struct shadow_copy2_private,
> and talloc everything off that.
> 
> But to be honest it's as easy to
> write a proper dellaocate function
> that just walks the list and deallocates
> each entry manually (there's already lots
> of boilerplate code in Samba that does
> this you can copy). It won't be a performance
> bottleneck.
> 
> Secondly, don't use:
> 
> typedef struct shadow_copy2_snapentry
> 
> - just use 'struct shadow_copy2_snapentry'
> instead. This is a style thing (see the
> README.coding).
> 
> Thanks !
> 
> Jeremy.
> 
> On Fri, May 06, 2016 at 07:46:23PM +0530, Rajesh Joseph wrote:
> 
>> From 4863de914ed4ed91fad27176fdcc2afe2710292a Mon Sep 17 00:00:00 2001
>> From: Rajesh Joseph <rjoseph at redhat.com>
>> Date: Mon, 18 Apr 2016 09:47:38 +0530
>> Subject: [PATCH] vfs/shadow_copy2: allow configurable prefix for snapshot name
>>
>> shadow_copy2 module provides configurable format for time via
>> shadow:format option in smb.conf. Currently there is no way
>> to specify a variable name along with time.
>>
>> As part of this change added a new option (shadow:snapprefix) in
>> shadow_copy2 config. This option will accept regular expression as input.
>> 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>
>> ---
>>  source3/modules/vfs_shadow_copy2.c |  380 +++++++++++++++++++++++++++---------
>>  1 files changed, 283 insertions(+), 97 deletions(-)
>>
>> diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
>> index 43bc89d..b387da3 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,8 @@ struct shadow_copy2_config {
>>  	bool use_sscanf;
>>  	bool use_localtime;
>>  	char *snapdir;
>> +	char *snapprefix;
>> +	char *delimiter;
>>  	bool snapdirseverywhere;
>>  	bool crossmountpoints;
>>  	bool fixinodes;
>> @@ -50,6 +53,46 @@ struct shadow_copy2_config {
>>  	char *snapshot_basepath; /* the absolute version of snapdir */
>>  };
>>  
>> +/* Data-structure to hold the list of snap entries */
>> +typedef struct shadow_copy2_snapentry {
>> +	char *snapname;
>> +	char *time_fmt;
>> +	struct shadow_copy2_snapentry *next;
>> +	struct shadow_copy2_snapentry *prev;
>> +} shadow_copy2_snapentry;
>> +
>> +
>> +/* 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_snapentry	*snaplist; /* Global snapshot list */
>> +};
>> +
>> +/* 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 priv	shadow_copy2 specific data structure
>> + * @return	Newly created snapshot entry or NULL on failure
>> + */
>> +static shadow_copy2_snapentry *shadow_copy2_create_snapentry(
>> +					struct shadow_copy2_private *priv)
>> +{
>> +	shadow_copy2_snapentry *tmpentry = NULL;
>> +
>> +	if (priv->snaplist == NULL) {
>> +		tmpentry = talloc_zero(priv, shadow_copy2_snapentry);
>> +		priv->snaplist = tmpentry;
>> +	} else {
>> +		tmpentry = talloc_zero(priv->snaplist,
>> +					shadow_copy2_snapentry);
>> +		DLIST_ADD_END(priv->snaplist, tmpentry);
>> +	}
>> +
>> +	return tmpentry;
>> +}
>> +
>>  static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
>>  				      size_t **poffsets,
>>  				      unsigned *pnum_offsets)
>> @@ -84,6 +127,41 @@ static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
>>  	return true;
>>  }
>>  
>> +/* Given a timestamp this function searches the global snapshot list
>> + * and returns the complete snapshot directory name saved in the entry.
>> + *
>> + * @param priv		shadow_copy2 specific structure
>> + * @param timestamp	timestamp corresponding to one of the snapshot
>> + * @param snap_str	buffer to copy the actual snapshot name
>> + * @param len		length of snap_str buffer
>> + *
>> + * @return 	Length of actual snapshot name, and -1 on failure
>> + */
>> +static size_t shadow_copy2_saved_snapname(struct shadow_copy2_private *priv,
>> +					  struct tm *timestamp,
>> +					  char *snap_str, size_t len)
>> +{
>> +	size_t snaptime_len = -1;
>> +	shadow_copy2_snapentry *entry = NULL;
>> +
>> +	snaptime_len = strftime(snap_str, len, GMT_FORMAT, timestamp);
>> +	if (snaptime_len == 0) {
>> +		DEBUG(10, ("strftime failed\n"));
>> +		return -1;
>> +	}
>> +
>> +	for (entry = priv->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;
>> +}
>> +
>>  /**
>>   * Given a timestamp, build the posix level GMT-tag string
>>   * based on the configurable format.
>> @@ -95,22 +173,22 @@ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
>>  {
>>  	struct tm snap_tm;
>>  	size_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);
>>  
>> -	if (config->use_sscanf) {
>> +	if (priv->config->use_sscanf) {
>>  		snaptime_len = snprintf(snaptime_string,
>>  					len,
>> -					config->gmt_format,
>> +					priv->config->gmt_format,
>>  					(unsigned long)snapshot);
>>  		if (snaptime_len <= 0) {
>>  			DEBUG(10, ("snprintf failed\n"));
>>  			return snaptime_len;
>>  		}
>>  	} else {
>> -		if (config->use_localtime) {
>> +		if (priv->config->use_localtime) {
>>  			if (localtime_r(&snapshot, &snap_tm) == 0) {
>>  				DEBUG(10, ("gmtime_r failed\n"));
>>  				return -1;
>> @@ -121,9 +199,15 @@ static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
>>  				return -1;
>>  			}
>>  		}
>> +
>> +		if (priv->config->snapprefix != NULL) {
>> +			return shadow_copy2_saved_snapname(priv, &snap_tm,
>> +							snaptime_string, len);
>> +		}
>> +
>>  		snaptime_len = strftime(snaptime_string,
>>  					len,
>> -					config->gmt_format,
>> +					priv->config->gmt_format,
>>  					&snap_tm);
>>  		if (snaptime_len == 0) {
>>  			DEBUG(10, ("strftime failed\n"));
>> @@ -152,9 +236,9 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
>>  	fstring snaptime_string;
>>  	size_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,
>> @@ -165,12 +249,12 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
>>  		return NULL;
>>  	}
>>  
>> -	if (config->snapdir_absolute) {
>> +	if (priv->config->snapdir_absolute) {
>>  		result = talloc_asprintf(mem_ctx, "%s/%s",
>> -					 config->snapdir, snaptime_string);
>> +					 priv->config->snapdir, snaptime_string);
>>  	} else {
>>  		result = talloc_asprintf(mem_ctx, "/%s/%s",
>> -					 config->snapdir, snaptime_string);
>> +					 priv->config->snapdir, snaptime_string);
>>  	}
>>  	if (result == NULL) {
>>  		DEBUG(1, (__location__ " talloc_asprintf failed\n"));
>> @@ -194,9 +278,9 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
>>  	fstring snaptime_string;
>>  	size_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 +292,8 @@ 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 +318,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 +405,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,
>> @@ -452,15 +537,14 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
>>  	size_t insertlen, connectlen = 0;
>>  	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);
>> -
>>  	DEBUG(10, ("converting '%s'\n", name));
>>  
>> -	if (!config->snapdirseverywhere) {
>> +	if (!priv->config->snapdirseverywhere) {
>>  		int ret;
>>  		char *snapshot_path;
>>  
>> @@ -471,13 +555,13 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
>>  			goto fail;
>>  		}
>>  
>> -		if (config->rel_connectpath == NULL) {
>> +		if (priv->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,
>> +						    priv->config->rel_connectpath,
>>  						    name);
>>  		}
>>  		if (converted == NULL) {
>> @@ -497,9 +581,9 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
>>  			converted = NULL;
>>  			if (snaproot_len != NULL) {
>>  				*snaproot_len = strlen(snapshot_path);
>> -				if (config->rel_connectpath != NULL) {
>> +				if (priv->config->rel_connectpath != NULL) {
>>  					*snaproot_len +=
>> -					    strlen(config->rel_connectpath) + 1;
>> +					    strlen(priv->config->rel_connectpath) + 1;
>>  				}
>>  			}
>>  			goto fail;
>> @@ -565,8 +649,8 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
>>  
>>  	min_offset = 0;
>>  
>> -	if (!config->crossmountpoints) {
>> -		min_offset = strlen(config->mount_point);
>> +	if (!priv->config->crossmountpoints) {
>> +		min_offset = strlen(priv->config->mount_point);
>>  	}
>>  
>>  	memcpy(converted, path, pathlen+1);
>> @@ -661,12 +745,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 +1302,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;
>>  	}
>> @@ -1284,16 +1368,16 @@ 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);
>>  
>>  	/*
>>  	 * If the non-snapdisrseverywhere mode, we should not search!
>>  	 */
>> -	if (!config->snapdirseverywhere) {
>> -		return config->snapshot_basepath;
>> +	if (!priv->config->snapdirseverywhere) {
>> +		return priv->config->snapshot_basepath;
>>  	}
>>  
>>  	path = talloc_asprintf(mem_ctx, "%s/%s",
>> @@ -1331,19 +1415,58 @@ 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;
>> +	char *tmpstr = NULL;
>> +	char *tmp = NULL;
>> +	int ret = -1;
>> +	struct shadow_copy2_private *priv;
>> +	regex_t regex;
>>  
>> -	SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
>> +	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
>>  				return NULL);
>>  
>> -	fmt = config->gmt_format;
>> +	fmt = priv->config->gmt_format;
>> +
>> +	/* If snapprefix 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->config->snapprefix != NULL) {
>> +		tmpstr = talloc_strdup(NULL, name);
>> +		/* point "name" to the time format */
>> +		name = strstr(name, priv->config->delimiter);
>> +		if (name == NULL) {
>> +			talloc_free(tmpstr);
>> +			return false;
>> +		}
>> +		/* Extract the prefix */
>> +		tmp = strstr(tmpstr, priv->config->delimiter);
>> +		*tmp = '\0';
>> +		/* Create regex rule */
>> +		ret = regcomp(&regex, priv->config->snapprefix, 0);
>> +		if (ret) {
>> +			DEBUG(0, ("shadow_copy2_snapshot_to_gmt: "
>> +				  "Failed to create regex object\n"));
>> +			talloc_free(tmpstr);
>> +			return false;
>> +		}
>> +
>> +		/* Parse regex */
>> +		ret = regexec(&regex, tmpstr, 0, NULL, 0);
>> +		if (ret) {
>> +			DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
>> +				   "no regex match %s: %s\n",
>> +				   priv->config->snapprefix, tmpstr));
>> +			talloc_free(tmpstr);
>> +			return false;
>> +		}
>> +	}
>>  
>>  	ZERO_STRUCT(timestamp);
>> -	if (config->use_sscanf) {
>> +	if (priv->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));
>> +			talloc_free(tmpstr);
>>  			return false;
>>  		}
>>  		timestamp_t = timestamp_long;
>> @@ -1353,12 +1476,13 @@ 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));
>> +			talloc_free(tmpstr);
>>  			return false;
>>  		}
>>  		DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
>>  			   fmt, name));
>> -		
>> -		if (config->use_localtime) {
>> +
>> +		if (priv->config->use_localtime) {
>>  			timestamp.tm_isdst = -1;
>>  			timestamp_t = mktime(&timestamp);
>>  			gmtime_r(&timestamp_t, &timestamp);
>> @@ -1366,6 +1490,8 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
>>  	}
>>  
>>  	strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
>> +
>> +	talloc_free(tmpstr);
>>  	return true;
>>  }
>>  
>> @@ -1387,12 +1513,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;
>>  	}
>> @@ -1423,6 +1549,8 @@ static int shadow_copy2_get_shadow_copy_data(
>>  	const char *snapdir;
>>  	struct smb_filename *snapdir_smb_fname = NULL;
>>  	struct dirent *d;
>> +	struct shadow_copy2_private *priv = NULL;
>> +	shadow_copy2_snapentry *tmpentry = NULL;
>>  	TALLOC_CTX *tmp_ctx = talloc_stackframe();
>>  	bool ret;
>>  
>> @@ -1466,6 +1594,15 @@ static int shadow_copy2_get_shadow_copy_data(
>>  	shadow_copy2_data->num_volumes = 0;
>>  	shadow_copy2_data->labels      = NULL;
>>  
>> +	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
>> +				return -1);
>> +
>> +	if (labels && priv->config->snapprefix != NULL) {
>> +		/* Reset the global snaplist */
>> +		TALLOC_FREE(priv->snaplist);
>> +		priv->snaplist = NULL;
>> +	}
>> +
>>  	while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
>>  		char snapshot[GMT_NAME_LEN+1];
>>  		SHADOW_COPY_LABEL *tlabels;
>> @@ -1491,6 +1628,18 @@ static int shadow_copy2_get_shadow_copy_data(
>>  			continue;
>>  		}
>>  
>> +		if (priv->config->snapprefix != NULL) {
>> +			/* Create a snap entry for each successful
>> +			 * pattern match */
>> +			tmpentry = shadow_copy2_create_snapentry(priv);
>> +			if (tmpentry == NULL) {
>> +				DEBUG(0, ("talloc_zero() failed\n"));
>> +				return -1;
>> +			}
>> +			tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
>> +			tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
>> +		}
>> +
>>  		tlabels = talloc_realloc(shadow_copy2_data,
>>  					 shadow_copy2_data->labels,
>>  					 SHADOW_COPY_LABEL,
>> @@ -2033,9 +2182,11 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
>>  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 *snapprefix;
>> +	const char *delimiter;
>>  	const char *gmt_format;
>>  	const char *sort_order;
>>  	const char *basedir = NULL;
>> @@ -2051,8 +2202,15 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  		return ret;
>>  	}
>>  
>> -	config = talloc_zero(handle->conn, struct shadow_copy2_config);
>> -	if (config == NULL) {
>> +	priv = talloc_zero(handle->conn, struct shadow_copy2_private);
>> +	if (priv == NULL) {
>> +		DEBUG(0, ("talloc_zero() failed\n"));
>> +		errno = ENOMEM;
>> +		return -1;
>> +	}
>> +
>> +	priv->config = talloc_zero(priv, struct shadow_copy2_config);
>> +	if (priv->config == NULL) {
>>  		DEBUG(0, ("talloc_zero() failed\n"));
>>  		errno = ENOMEM;
>>  		return -1;
>> @@ -2061,52 +2219,76 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  	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) {
>> +	priv->config->gmt_format = talloc_strdup(priv->config, gmt_format);
>> +	if (priv->config->gmt_format == NULL) {
>>  		DEBUG(0, ("talloc_strdup() failed\n"));
>>  		errno = ENOMEM;
>>  		return -1;
>>  	}
>>  
>> -	config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
>> +	priv->config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
>>  					  "shadow", "sscanf", false);
>>  
>> -	config->use_localtime = lp_parm_bool(SNUM(handle->conn),
>> +	priv->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) {
>> +	priv->config->snapdir = talloc_strdup(priv->config, snapdir);
>> +	if (priv->config->snapdir == NULL) {
>>  		DEBUG(0, ("talloc_strdup() failed\n"));
>>  		errno = ENOMEM;
>>  		return -1;
>>  	}
>>  
>> -	config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
>> +	snapprefix = lp_parm_const_string(SNUM(handle->conn),
>> +				       "shadow", "snapprefix",
>> +				       NULL);
>> +	if (snapprefix != NULL) {
>> +		priv->config->snapprefix = talloc_strdup(priv->config, snapprefix);
>> +		if (priv->config->snapprefix == NULL) {
>> +			DEBUG(0, ("talloc_strdup() failed\n"));
>> +			errno = ENOMEM;
>> +			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) {
>> +			DEBUG(0, ("talloc_strdup() failed\n"));
>> +			errno = ENOMEM;
>> +			return -1;
>> +		}
>> +	}
>> +
>> +	priv->config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
>>  						  "shadow",
>>  						  "snapdirseverywhere",
>>  						  false);
>>  
>> -	config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
>> +	priv->config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
>>  						"shadow", "crossmountpoints",
>>  						false);
>>  
>> -	if (config->crossmountpoints && !config->snapdirseverywhere) {
>> +	if (priv->config->crossmountpoints && !priv->config->snapdirseverywhere) {
>>  		DBG_WARNING("Warning: 'crossmountpoints' depends on "
>>  			    "'snapdirseverywhere'. Disabling crossmountpoints.\n");
>>  	}
>>  
>> -	config->fixinodes = lp_parm_bool(SNUM(handle->conn),
>> +	priv->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) {
>> +	priv->config->sort_order = talloc_strdup(priv->config, sort_order);
>> +	if (priv->config->sort_order == NULL) {
>>  		DEBUG(0, ("talloc_strdup() failed\n"));
>>  		errno = ENOMEM;
>>  		return -1;
>> @@ -2137,15 +2319,15 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  	}
>>  
>>  	if (mount_point != NULL) {
>> -		config->mount_point = talloc_strdup(config, mount_point);
>> -		if (config->mount_point == NULL) {
>> +		priv->config->mount_point = talloc_strdup(priv->config, mount_point);
>> +		if (priv->config->mount_point == NULL) {
>>  			DEBUG(0, (__location__ " talloc_strdup() failed\n"));
>>  			return -1;
>>  		}
>>  	} else {
>> -		config->mount_point = shadow_copy2_find_mount_point(config,
>> +		priv->config->mount_point = shadow_copy2_find_mount_point(priv->config,
>>  								    handle);
>> -		if (config->mount_point == NULL) {
>> +		if (priv->config->mount_point == NULL) {
>>  			DBG_WARNING("shadow_copy2_find_mount_point "
>>  				    "of the share root '%s' failed: %s\n",
>>  				    handle->conn->connectpath, strerror(errno));
>> @@ -2165,19 +2347,19 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  			basedir = NULL;
>>  		} else {
>>  			char *p;
>> -			p = strstr(basedir, config->mount_point);
>> +			p = strstr(basedir, priv->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));
>> +					  basedir, priv->config->mount_point));
>>  				basedir = NULL;
>>  			}
>>  		}
>>  	}
>>  
>> -	if (config->snapdirseverywhere && basedir != NULL) {
>> +	if (priv->config->snapdirseverywhere && basedir != NULL) {
>>  		DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
>>  			  "with 'snapdirseverywhere'. Disabling basedir.\n"));
>>  		basedir = NULL;
>> @@ -2193,7 +2375,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  				    snapsharepath);
>>  			snapsharepath = NULL;
>>  		}
>> -		if (config->snapdirseverywhere && snapsharepath != NULL) {
>> +		if (priv->config->snapdirseverywhere && snapsharepath != NULL) {
>>  			DBG_WARNING("Warning: 'snapsharepath' is incompatible "
>>  				    "with 'snapdirseverywhere'. Disabling "
>>  				    "snapsharepath.\n");
>> @@ -2208,8 +2390,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  	}
>>  
>>  	if (snapsharepath != NULL) {
>> -		config->rel_connectpath = talloc_strdup(config, snapsharepath);
>> -		if (config->rel_connectpath == NULL) {
>> +		priv->config->rel_connectpath = talloc_strdup(priv->config, snapsharepath);
>> +		if (priv->config->rel_connectpath == NULL) {
>>  			DBG_ERR("talloc_strdup() failed\n");
>>  			errno = ENOMEM;
>>  			return -1;
>> @@ -2217,42 +2399,42 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  	}
>>  
>>  	if (basedir == NULL) {
>> -		basedir = config->mount_point;
>> +		basedir = priv->config->mount_point;
>>  	}
>>  
>> -	if (config->rel_connectpath == NULL &&
>> +	if (priv->config->rel_connectpath == NULL &&
>>  	    strlen(basedir) != strlen(handle->conn->connectpath)) {
>> -		config->rel_connectpath = talloc_strdup(config,
>> +		priv->config->rel_connectpath = talloc_strdup(priv->config,
>>  			handle->conn->connectpath + strlen(basedir));
>> -		if (config->rel_connectpath == NULL) {
>> +		if (priv->config->rel_connectpath == NULL) {
>>  			DEBUG(0, ("talloc_strdup() failed\n"));
>>  			errno = ENOMEM;
>>  			return -1;
>>  		}
>>  	}
>>  
>> -	if (config->snapdir[0] == '/') {
>> -		config->snapdir_absolute = true;
>> +	if (priv->config->snapdir[0] == '/') {
>> +		priv->config->snapdir_absolute = true;
>>  
>> -		if (config->snapdirseverywhere == true) {
>> +		if (priv->config->snapdirseverywhere == true) {
>>  			DEBUG(1, (__location__ " Warning: An absolute snapdir "
>>  				  "is incompatible with 'snapdirseverywhere', "
>>  				  "setting 'snapdirseverywhere' to false.\n"));
>> -			config->snapdirseverywhere = false;
>> +			priv->config->snapdirseverywhere = false;
>>  		}
>>  
>> -		if (config->crossmountpoints == true) {
>> +		if (priv->config->crossmountpoints == true) {
>>  			DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
>>  				  "is not supported with an absolute snapdir. "
>>  				  "Disabling it.\n"));
>> -			config->crossmountpoints = false;
>> +			priv->config->crossmountpoints = false;
>>  		}
>>  
>> -		config->snapshot_basepath = config->snapdir;
>> +		priv->config->snapshot_basepath = priv->config->snapdir;
>>  	} else {
>> -		config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
>> -				config->mount_point, config->snapdir);
>> -		if (config->snapshot_basepath == NULL) {
>> +		priv->config->snapshot_basepath = talloc_asprintf(priv->config, "%s/%s",
>> +				priv->config->mount_point, priv->config->snapdir);
>> +		if (priv->config->snapshot_basepath == NULL) {
>>  			DEBUG(0, ("talloc_asprintf() failed\n"));
>>  			errno = ENOMEM;
>>  			return -1;
>> @@ -2264,6 +2446,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"
>> @@ -2273,21 +2457,23 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
>>  		   "  sort order: %s\n"
>>  		   "",
>>  		   handle->conn->connectpath,
>> -		   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
>> +		   priv->config->mount_point,
>> +		   priv->config->rel_connectpath,
>> +		   priv->config->snapdir,
>> +		   priv->config->snapprefix,
>> +		   priv->config->delimiter,
>> +		   priv->config->snapshot_basepath,
>> +		   priv->config->gmt_format,
>> +		   priv->config->use_sscanf ? "yes" : "no",
>> +		   priv->config->snapdirseverywhere ? "yes" : "no",
>> +		   priv->config->crossmountpoints ? "yes" : "no",
>> +		   priv->config->fixinodes ? "yes" : "no",
>> +		   priv->config->sort_order
>>  		   ));
>>  
>>  
>> -	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;
>> -- 
>> 1.7.1
>>
> 
> 




More information about the samba-technical mailing list