[PATCH] shadow_copy2: Allow configurable prefix for snapshots

Jeremy Allison jra at samba.org
Sun May 8 18:42:21 UTC 2016


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