From 857ed9ea2c380246c3327c7ab4fa77045e6c44b8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 11 Jan 2017 16:30:38 -0800 Subject: [PATCH 1/6] s3: smbd: Correctly canonicalize any incoming shadow copy path. Converts to: @GMT-token/path/last_component from all incoming path types. Allows shadow_copy modules to work when current directory is changed after removing last component. Ultimately when the VFS ABI is changed to add a timestamp to struct smb_filename, this is where the parsing will be done. Signed-off-by: Jeremy Allison --- source3/smbd/filename.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index a8cfb55b0f0..efe52a04328 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -220,6 +220,148 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx, return NT_STATUS_OK; } +/* + * Re-order a known good @GMT-token path. + */ + +static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname, + char *startp, + char *endp) +{ + size_t endlen = 0; + size_t gmt_len = endp - startp; + char gmt_store[gmt_len + 1]; + char *parent = NULL; + const char *last_component = NULL; + char *newstr; + bool ret; + + DBG_DEBUG("|%s| -> ", smb_fname->base_name); + + /* Save off the @GMT-token. */ + memcpy(gmt_store, startp, gmt_len); + gmt_store[gmt_len] = '\0'; + + if (*endp == '/') { + /* Remove any trailing '/' */ + endp++; + } + + if (*endp == '\0') { + /* + * @GMT-token was at end of path. + * Remove any preceeding '/' + */ + if (startp > smb_fname->base_name && startp[-1] == '/') { + startp--; + } + } + + /* Remove @GMT-token from the path. */ + endlen = strlen(endp); + memmove(startp, endp, endlen + 1); + + /* Split the remaining path into components. */ + ret = parent_dirname(smb_fname, + smb_fname->base_name, + &parent, + &last_component); + if (ret == false) { + /* Must terminate debug with \n */ + DBG_DEBUG("NT_STATUS_NO_MEMORY\n"); + return NT_STATUS_NO_MEMORY; + } + + if (ISDOT(parent)) { + if (last_component[0] == '\0') { + newstr = talloc_strdup(smb_fname, + gmt_store); + } else { + newstr = talloc_asprintf(smb_fname, + "%s/%s", + gmt_store, + last_component); + } + } else { + newstr = talloc_asprintf(smb_fname, + "%s/%s/%s", + gmt_store, + parent, + last_component); + } + + TALLOC_FREE(parent); + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = newstr; + + DBG_DEBUG("|%s|\n", newstr); + + return NT_STATUS_OK; +} + +/* + * Canonicalize any incoming pathname potentially containining + * a @GMT-token into a path that looks like: + * + * @GMT-YYYY-MM-DD-HH-MM-SS/path/name/components/last_component + * + * Leaves single path @GMT-token -component alone: + * + * @GMT-YYYY-MM-DD-HH-MM-SS -> @GMT-YYYY-MM-DD-HH-MM-SS + * + * Eventually when struct smb_filename is updated and the VFS + * ABI is changed this will remove the @GMT-YYYY-MM-DD-HH-MM-SS + * and store in the struct smb_filename as a struct timeval field + * instead. + */ + +static NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname) +{ + char *startp = strchr_m(smb_fname->base_name, '@'); + char *endp = NULL; + struct tm tm; + + if (startp == NULL) { + /* No @ */ + return NT_STATUS_OK; + } + + startp = strstr_m(startp, "@GMT-"); + if (startp == NULL) { + /* No @ */ + return NT_STATUS_OK; + } + + if ((startp > smb_fname->base_name) && (startp[-1] != '/')) { + /* the GMT-token does not start a path-component */ + return NT_STATUS_OK; + } + + endp = strptime(startp, GMT_FORMAT, &tm); + if (endp == NULL) { + /* Not a valid timestring. */ + return NT_STATUS_OK; + } + + if ( endp[0] == '\0') { + return rearrange_snapshot_path(smb_fname, + startp, + endp); + } + + if (endp[0] != '/') { + /* + * It is not a complete path component, i.e. the path + * component continues after the gmt-token. + */ + return NT_STATUS_OK; + } + + return rearrange_snapshot_path(smb_fname, + startp, + endp); +} + /**************************************************************************** This routine is called to convert names from the dos namespace to unix namespace. It needs to handle any case conversions, mangling, format changes, @@ -356,6 +498,14 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, goto err; } + /* Canonicalize any @GMT- paths. */ + if (posix_pathnames == false) { + status = canonicalize_snapshot_path(smb_fname); + if (!NT_STATUS_IS_OK(status)) { + goto err; + } + } + /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of -- 2.11.0.483.g087da7b7c-goog From c158b091a596834c4adb8c25c6b291a6761565e0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 17 Jan 2017 11:33:18 -0800 Subject: [PATCH 2/6] s3: lib: Add canonicalize_absolute_path(). We will be re-using this in several places. Signed-off-by: Jeremy Allison --- source3/lib/util_path.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ source3/lib/util_path.h | 1 + 2 files changed, 124 insertions(+) diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c index 509ba5ff727..888937d4fb4 100644 --- a/source3/lib/util_path.c +++ b/source3/lib/util_path.c @@ -93,3 +93,126 @@ char *cache_path(const char *name) { return xx_path(name, lp_cache_directory()); } + +char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path) +{ + char *destname; + char *d; + const char *s = abs_path; + bool start_of_name_component = true; + + /* Allocate for strlen + '\0' + possible leading '/' */ + destname = (char *)talloc_size(ctx, strlen(abs_path) + 2); + if (destname == NULL) { + return NULL; + } + d = destname; + + *d++ = '/'; /* Always start with root. */ + + while (*s) { + if (*s == '/') { + /* Eat multiple '/' */ + while (*s == '/') { + s++; + } + if ((d > destname + 1) && (*s != '\0')) { + *d++ = '/'; + } + start_of_name_component = true; + continue; + } + + if (start_of_name_component) { + if ((s[0] == '.') && (s[1] == '.') && + (s[2] == '/' || s[2] == '\0')) { + /* Uh oh - "/../" or "/..\0" ! */ + + /* Go past the ../ or .. */ + if (s[2] == '/') { + s += 3; + } else { + s += 2; /* Go past the .. */ + } + + /* If we just added a '/' - delete it */ + if ((d > destname) && (*(d-1) == '/')) { + *(d-1) = '\0'; + d--; + } + + /* + * Are we at the start ? + * Can't go back further if so. + */ + if (d <= destname) { + *d++ = '/'; /* Can't delete root */ + continue; + } + /* Go back one level... */ + /* + * Decrement d first as d points to + * the *next* char to write into. + */ + for (d--; d > destname; d--) { + if (*d == '/') { + break; + } + } + /* + * We're still at the start of a name + * component, just the previous one. + */ + continue; + } else if ((s[0] == '.') && + ((s[1] == '\0') || s[1] == '/')) { + /* + * Component of pathname can't be "." only. + * Skip the '.' . + */ + if (s[1] == '/') { + s += 2; + } else { + s++; + } + continue; + } + } + + if (!(*s & 0x80)) { + *d++ = *s++; + } else { + size_t siz; + /* Get the size of the next MB character. */ + next_codepoint(s,&siz); + switch(siz) { + case 5: + *d++ = *s++; + /*fall through*/ + case 4: + *d++ = *s++; + /*fall through*/ + case 3: + *d++ = *s++; + /*fall through*/ + case 2: + *d++ = *s++; + /*fall through*/ + case 1: + *d++ = *s++; + break; + default: + break; + } + } + start_of_name_component = false; + } + *d = '\0'; + + /* And must not end in '/' */ + if (d > destname + 1 && (*(d-1) == '/')) { + *(d-1) = '\0'; + } + + return destname; +} diff --git a/source3/lib/util_path.h b/source3/lib/util_path.h index 118a4bed524..16e27926084 100644 --- a/source3/lib/util_path.h +++ b/source3/lib/util_path.h @@ -27,5 +27,6 @@ char *lock_path(const char *name); char *state_path(const char *name); char *cache_path(const char *name); +char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path); #endif -- 2.11.0.483.g087da7b7c-goog From 77a3c4098a9b054eb1a73eb72a409615e278e2df Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 19 Jan 2017 15:18:41 -0800 Subject: [PATCH 3/6] s3: lib: Fix old, old bug in set_conn_connectpath(), now in canonicalize_absolute_path(). Canonicalizing a path of /foo/bar/../baz would return /foo/barbaz as moving forward 3 characters would delete the / character. Signed-off-by: Jeremy Allison --- source3/lib/util_path.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c index 888937d4fb4..0437ca11ac9 100644 --- a/source3/lib/util_path.c +++ b/source3/lib/util_path.c @@ -128,12 +128,8 @@ char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path) (s[2] == '/' || s[2] == '\0')) { /* Uh oh - "/../" or "/..\0" ! */ - /* Go past the ../ or .. */ - if (s[2] == '/') { - s += 3; - } else { - s += 2; /* Go past the .. */ - } + /* Go past the .. leaving us on the / or '\0' */ + s += 2; /* If we just added a '/' - delete it */ if ((d > destname) && (*(d-1) == '/')) { -- 2.11.0.483.g087da7b7c-goog From 9573b7cc812cfb3094fbd5c3b4be80a97b0dc3f2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 17 Jan 2017 11:35:52 -0800 Subject: [PATCH 4/6] s3: smbd: Make set_conn_connectpath() call canonicalize_absolute_path(). Signed-off-by: Jeremy Allison --- source3/smbd/service.c | 103 ++----------------------------------------------- 1 file changed, 3 insertions(+), 100 deletions(-) diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 3308e9dce97..a0ac9dfa2af 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -31,6 +31,7 @@ #include "lib/param/loadparm.h" #include "messages.h" #include "lib/afs/afs_funcs.h" +#include "lib/util_path.h" static bool canonicalize_connect_path(connection_struct *conn) { @@ -47,118 +48,20 @@ static bool canonicalize_connect_path(connection_struct *conn) /**************************************************************************** Ensure when setting connectpath it is a canonicalized (no ./ // or ../) absolute path stating in / and not ending in /. - Observent people will notice a similarity between this and check_path_syntax :-). ****************************************************************************/ bool set_conn_connectpath(connection_struct *conn, const char *connectpath) { char *destname; - char *d; - const char *s = connectpath; - bool start_of_name_component = true; if (connectpath == NULL || connectpath[0] == '\0') { return false; } - /* Allocate for strlen + '\0' + possible leading '/' */ - destname = (char *)talloc_size(conn, strlen(connectpath) + 2); - if (!destname) { + destname = canonicalize_absolute_path(conn, connectpath); + if (destname == NULL) { return false; } - d = destname; - - *d++ = '/'; /* Always start with root. */ - - while (*s) { - if (*s == '/') { - /* Eat multiple '/' */ - while (*s == '/') { - s++; - } - if ((d > destname + 1) && (*s != '\0')) { - *d++ = '/'; - } - start_of_name_component = True; - continue; - } - - if (start_of_name_component) { - if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) { - /* Uh oh - "/../" or "/..\0" ! */ - - /* Go past the ../ or .. */ - if (s[2] == '/') { - s += 3; - } else { - s += 2; /* Go past the .. */ - } - - /* If we just added a '/' - delete it */ - if ((d > destname) && (*(d-1) == '/')) { - *(d-1) = '\0'; - d--; - } - - /* Are we at the start ? Can't go back further if so. */ - if (d <= destname) { - *d++ = '/'; /* Can't delete root */ - continue; - } - /* Go back one level... */ - /* Decrement d first as d points to the *next* char to write into. */ - for (d--; d > destname; d--) { - if (*d == '/') { - break; - } - } - /* We're still at the start of a name component, just the previous one. */ - continue; - } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) { - /* Component of pathname can't be "." only - skip the '.' . */ - if (s[1] == '/') { - s += 2; - } else { - s++; - } - continue; - } - } - - if (!(*s & 0x80)) { - *d++ = *s++; - } else { - size_t siz; - /* Get the size of the next MB character. */ - next_codepoint(s,&siz); - switch(siz) { - case 5: - *d++ = *s++; - /*fall through*/ - case 4: - *d++ = *s++; - /*fall through*/ - case 3: - *d++ = *s++; - /*fall through*/ - case 2: - *d++ = *s++; - /*fall through*/ - case 1: - *d++ = *s++; - break; - default: - break; - } - } - start_of_name_component = false; - } - *d = '\0'; - - /* And must not end in '/' */ - if (d > destname + 1 && (*(d-1) == '/')) { - *(d-1) = '\0'; - } DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n", lp_servicename(talloc_tos(), SNUM(conn)), destname )); -- 2.11.0.483.g087da7b7c-goog From 06185f167a798fff937dbf590cca91466072e2c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 17 Jan 2017 11:48:03 -0800 Subject: [PATCH 5/6] s3: modules: vfs_shadow_copy2 - Fix module when chdir() is used. Signed-off-by: Jeremy Allison --- source3/modules/vfs_shadow_copy2.c | 401 ++++++++++++++++++++++++++++--------- 1 file changed, 305 insertions(+), 96 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 6a25c87b7f7..6aa741b5f46 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -35,6 +35,7 @@ #include "system/filesys.h" #include "include/ntioctl.h" #include "util_tdb.h" +#include "lib/util_path.h" struct shadow_copy2_config { char *gmt_format; @@ -74,6 +75,8 @@ struct shadow_copy2_snaplist_info { struct shadow_copy2_private { struct shadow_copy2_config *config; struct shadow_copy2_snaplist_info *snaps; + char *shadow_cwd; + char *shadow_connectpath; }; static int shadow_copy2_get_shadow_copy_data( @@ -404,43 +407,101 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx, return result; } +static char *make_path_absolute(TALLOC_CTX *mem_ctx, + struct shadow_copy2_private *priv, + const char *name) +{ + char *newpath = NULL; + char *abs_path = NULL; + + if (name[0] != '/') { + newpath = talloc_asprintf(mem_ctx, + "%s/%s", + priv->shadow_cwd, + name); + if (newpath == NULL) { + return NULL; + } + name = newpath; + } + abs_path = canonicalize_absolute_path(mem_ctx, name); + TALLOC_FREE(newpath); + return abs_path; +} + +/* Return a $cwd-relative path. */ +static bool make_relative_path(const char *cwd, char *abs_path) +{ + size_t cwd_len = strlen(cwd); + size_t abs_len = strlen(abs_path); + + if (abs_len < cwd_len) { + return false; + } + if (memcmp(abs_path, cwd, cwd_len) != 0) { + return false; + } + if (abs_path[cwd_len] != '/' && abs_path[cwd_len] != '\0') { + return false; + } + if (abs_path[cwd_len] == '/') { + cwd_len++; + } + memmove(abs_path, &abs_path[cwd_len], abs_len + 1 - cwd_len); + return true; +} + /** * Strip a snapshot component from a filename as * handed in via the smb layer. - * Returns the parsed timestamp and the stripped filename. + * Always returns the parsed timestamp, if present + * and the $cwd relative stripped filename, if not already converted. */ -static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, +static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx, struct vfs_handle_struct *handle, - const char *name, + const char *orig_name, time_t *ptimestamp, - char **pstripped) + char **pstripped, + char **psnappath) { struct tm tm; - time_t timestamp; + time_t timestamp = 0; const char *p; char *q; - char *stripped; + char *stripped = NULL; size_t rest_len, dst_len; struct shadow_copy2_private *priv; const char *snapdir; ssize_t snapdirlen; ptrdiff_t len_before_gmt; + char *abs_path = NULL; + const char *name = orig_name; + int ret = true; SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, return false); DEBUG(10, (__location__ ": enter path '%s'\n", name)); + abs_path = make_path_absolute(mem_ctx, priv, name); + if (abs_path == NULL) { + ret = false; + goto out; + } + name = abs_path; + + DEBUG(10, (__location__ ": abs path '%s'\n", name)); + p = strstr_m(name, "@GMT-"); if (p == NULL) { DEBUG(11, ("@GMT not found\n")); - goto no_snapshot; + goto out; } if ((p > name) && (p[-1] != '/')) { /* the GMT-token does not start a path-component */ DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n", p, name, (int)p[-1])); - goto no_snapshot; + goto out; } /* @@ -464,19 +525,42 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) { DEBUG(10, ("name=%s is already converted\n", name)); - goto no_snapshot; + if (psnappath) { + /* + * Need to return up to the next path + * component after the @GMT-. + */ + q = strchr(p, '/'); + if (q == NULL) { + /* + * No next path component. + * Just return entire string. + */ + *psnappath = talloc_strdup(mem_ctx, + name); + } else { + *psnappath = talloc_strndup(mem_ctx, + name, + q - name); + } + if (*psnappath == NULL) { + ret = false; + goto out; + } + } + goto out; } } q = strptime(p, GMT_FORMAT, &tm); if (q == NULL) { DEBUG(10, ("strptime failed\n")); - goto no_snapshot; + goto out; } tm.tm_isdst = -1; timestamp = timegm(&tm); if (timestamp == (time_t)-1) { DEBUG(10, ("timestamp==-1\n")); - goto no_snapshot; + goto out; } if (q[0] == '\0') { /* @@ -496,12 +580,24 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, stripped = talloc_strndup(mem_ctx, name, len_before_gmt); if (stripped == NULL) { - return false; + ret = false; + goto out; + } + if (orig_name[0] != '/') { + if (make_relative_path(priv->shadow_cwd, + stripped) == false) { + DEBUG(10, (__location__ ": path '%s' " + "doesn't start with cwd '%s\n", + stripped, priv->shadow_cwd)); + ret = false; + errno = ENOENT; + goto out; + } } *pstripped = stripped; } *ptimestamp = timestamp; - return true; + goto out; } if (q[0] != '/') { /* @@ -509,7 +605,7 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, * component continues after the gmt-token. */ DEBUG(10, ("q[0] = %d\n", (int)q[0])); - goto no_snapshot; + goto out; } q += 1; @@ -518,27 +614,37 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, if (priv->config->snapdirseverywhere) { char *insert; - bool have_insert; + char *have_insert; insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp); if (insert == NULL) { - errno = ENOMEM; - return false; + ret = false; + goto out; } DEBUG(10, (__location__ ": snapdirseverywhere mode.\n" "path '%s'.\n" "insert string '%s'\n", name, insert)); - have_insert = (strstr(name, insert+1) != NULL); - DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n", - (int)have_insert, name, insert+1)); - if (have_insert) { + have_insert = strstr(name, insert+1); + DEBUG(10, ("have_insert=%s, name=%s, insert+1=%s\n", + have_insert ? have_insert : "", name, insert+1)); + if (have_insert != NULL) { DEBUG(10, (__location__ ": insert string '%s' found in " "path '%s' found in snapdirseverywhere mode " "==> already converted\n", insert, name)); + if (psnappath) { + size_t insertlen = strlen(insert); + *psnappath = talloc_strndup(mem_ctx, + name, + have_insert - name + insertlen); + if (*psnappath == NULL) { + ret = false; + goto out; + } + } TALLOC_FREE(insert); - goto no_snapshot; + goto out; } TALLOC_FREE(insert); } else { @@ -549,8 +655,8 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, handle, timestamp); if (snapshot_path == NULL) { - errno = ENOMEM; - return false; + ret = false; + goto out; } DEBUG(10, (__location__ " path: '%s'.\n" @@ -563,12 +669,22 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, * so it is already a converted absolute * path. Don't process further. */ + if (psnappath) { + size_t slen = strlen(snapshot_path); + *psnappath = talloc_strndup(mem_ctx, + name, + slen); + if (*psnappath == NULL) { + ret = false; + goto out; + } + } DEBUG(10, (__location__ ": path '%s' starts with " "snapshot path '%s' (not in " "snapdirseverywhere mode) ==> " "already converted\n", name, snapshot_path)); talloc_free(snapshot_path); - goto no_snapshot; + goto out; } talloc_free(snapshot_path); } @@ -576,8 +692,8 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, if (pstripped != NULL) { stripped = talloc_array(mem_ctx, char, dst_len+1); if (stripped == NULL) { - errno = ENOMEM; - return false; + ret = false; + goto out; } if (p > name) { memcpy(stripped, name, len_before_gmt); @@ -586,13 +702,40 @@ static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, memcpy(stripped + len_before_gmt, q, rest_len); } stripped[dst_len] = '\0'; + if (orig_name[0] != '/') { + if (make_relative_path(priv->shadow_cwd, + stripped) == false) { + DEBUG(10, (__location__ ": path '%s' " + "doesn't start with cwd '%s\n", + stripped, priv->shadow_cwd)); + ret = false; + errno = ENOENT; + goto out; + } + } *pstripped = stripped; } + *ptimestamp = timestamp; - return true; -no_snapshot: - *ptimestamp = 0; - return true; + ret = true; + +out: + TALLOC_FREE(abs_path); + return ret; +} + +static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx, + struct vfs_handle_struct *handle, + const char *orig_name, + time_t *ptimestamp, + char **pstripped) +{ + return shadow_copy2_strip_snapshot_internal(mem_ctx, + handle, + orig_name, + ptimestamp, + pstripped, + NULL); } static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx, @@ -893,8 +1036,8 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, const char *mask, uint32_t attr) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; DIR *ret; int saved_errno; char *conv; @@ -1002,8 +1145,8 @@ static int shadow_copy2_link(vfs_handle_struct *handle, static int shadow_copy2_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname) { - time_t timestamp; - char *stripped, *tmp; + time_t timestamp = 0; + char *stripped = NULL, *tmp; int ret, saved_errno; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, @@ -1041,8 +1184,8 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, static int shadow_copy2_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname) { - time_t timestamp; - char *stripped, *tmp; + time_t timestamp = 0; + char *stripped = NULL, *tmp; int ret, saved_errno; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, @@ -1080,7 +1223,7 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) { - time_t timestamp; + time_t timestamp = 0; int ret; ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); @@ -1102,8 +1245,8 @@ static int shadow_copy2_open(vfs_handle_struct *handle, struct smb_filename *smb_fname, files_struct *fsp, int flags, mode_t mode) { - time_t timestamp; - char *stripped, *tmp; + time_t timestamp = 0; + char *stripped = NULL, *tmp; int ret, saved_errno; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, @@ -1138,8 +1281,8 @@ static int shadow_copy2_open(vfs_handle_struct *handle, static int shadow_copy2_unlink(vfs_handle_struct *handle, const struct smb_filename *smb_fname) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; struct smb_filename *conv; @@ -1173,7 +1316,7 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, const struct smb_filename *smb_fname, mode_t mode) { - time_t timestamp; + time_t timestamp = 0; char *stripped = NULL; int ret, saved_errno; char *conv = NULL; @@ -1187,7 +1330,6 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, return -1; } if (timestamp == 0) { - TALLOC_FREE(stripped); return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode); } conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); @@ -1219,8 +1361,8 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, uid_t uid, gid_t gid) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv = NULL; struct smb_filename *conv_smb_fname = NULL; @@ -1258,30 +1400,83 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, return ret; } +static void store_cwd_data(vfs_handle_struct *handle, + char *connectpath) +{ + struct shadow_copy2_private *priv = NULL; + char *cwd = NULL; + + SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, + return); + + TALLOC_FREE(priv->shadow_cwd); + cwd = SMB_VFS_NEXT_GETWD(handle); + if (cwd == NULL) { + smb_panic("getwd failed\n"); + } + DBG_DEBUG("shadow cwd = %s\n", cwd); + priv->shadow_cwd = talloc_strdup(priv, cwd); + SAFE_FREE(cwd); + if (priv->shadow_cwd == NULL) { + smb_panic("talloc failed\n"); + } + TALLOC_FREE(priv->shadow_connectpath); + if (connectpath) { + DBG_DEBUG("shadow conectpath = %s\n", connectpath); + priv->shadow_connectpath = talloc_strdup(priv, connectpath); + if (priv->shadow_connectpath == NULL) { + smb_panic("talloc failed\n"); + } + } +} + static int shadow_copy2_chdir(vfs_handle_struct *handle, const char *fname) { - time_t timestamp; - char *stripped; - int ret, saved_errno; - char *conv; + time_t timestamp = 0; + char *stripped = NULL; + char *snappath = NULL; + int ret = -1, saved_errno = 0; + char *conv = NULL; + size_t rootpath_len = 0; - if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, - ×tamp, &stripped)) { + if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, fname, + ×tamp, &stripped, &snappath)) { return -1; } - if (timestamp == 0) { - return SMB_VFS_NEXT_CHDIR(handle, fname); + if (stripped != NULL) { + conv = shadow_copy2_do_convert(talloc_tos(), + handle, + stripped, + timestamp, + &rootpath_len); + TALLOC_FREE(stripped); + if (conv == NULL) { + return -1; + } + fname = conv; } - conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp); - TALLOC_FREE(stripped); - if (conv == NULL) { - return -1; + ret = SMB_VFS_NEXT_CHDIR(handle, fname); + if (ret == -1) { + saved_errno = errno; } - ret = SMB_VFS_NEXT_CHDIR(handle, conv); - saved_errno = errno; + + if (ret == 0) { + if (conv != NULL && rootpath_len != 0) { + conv[rootpath_len] = '\0'; + } else if (snappath != 0) { + TALLOC_FREE(conv); + conv = snappath; + } + store_cwd_data(handle, conv); + } + + TALLOC_FREE(stripped); TALLOC_FREE(conv); - errno = saved_errno; + + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1289,8 +1484,8 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, const struct smb_filename *smb_fname, struct smb_file_time *ft) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; struct smb_filename *conv; @@ -1323,8 +1518,8 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, static int shadow_copy2_readlink(vfs_handle_struct *handle, const char *fname, char *buf, size_t bufsiz) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; @@ -1350,8 +1545,8 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, static int shadow_copy2_mknod(vfs_handle_struct *handle, const char *fname, mode_t mode, SMB_DEV_T dev) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; @@ -1377,7 +1572,7 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, static char *shadow_copy2_realpath(vfs_handle_struct *handle, const char *fname) { - time_t timestamp; + time_t timestamp = 0; char *stripped = NULL; char *tmp = NULL; char *result = NULL; @@ -1805,8 +2000,8 @@ static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; NTSTATUS status; char *conv; struct smb_filename *smb_fname = NULL; @@ -1849,8 +2044,8 @@ static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct security_descriptor **ppdesc) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; NTSTATUS status; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -1891,8 +2086,8 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, const struct smb_filename *smb_fname, mode_t mode) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -1932,8 +2127,8 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, static int shadow_copy2_rmdir(vfs_handle_struct *handle, const struct smb_filename *smb_fname) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -1973,8 +2168,8 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, unsigned int flags) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; @@ -2001,8 +2196,8 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, const char *fname, const char *aname, void *value, size_t size) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv; @@ -2031,8 +2226,8 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname, char *list, size_t size) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv; @@ -2059,8 +2254,8 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, static int shadow_copy2_removexattr(vfs_handle_struct *handle, const char *fname, const char *aname) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret, saved_errno; char *conv; @@ -2088,8 +2283,8 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *aname, const void *value, size_t size, int flags) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv; @@ -2118,8 +2313,8 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, const struct smb_filename *smb_fname, mode_t mode) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv = NULL; @@ -2164,8 +2359,8 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, char **found_name) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv; @@ -2203,16 +2398,25 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, const char *fname) { - time_t timestamp; + time_t timestamp = 0; char *stripped = NULL; char *tmp = NULL; char *result = NULL; char *parent_dir = NULL; int saved_errno; size_t rootpath_len = 0; + struct shadow_copy2_private *priv = NULL; + + SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, + return NULL); DBG_DEBUG("Calc connect path for [%s]\n", fname); + if (priv->shadow_connectpath != NULL) { + DBG_DEBUG("cached connect path is [%s]\n", priv->shadow_connectpath); + return priv->shadow_connectpath; + } + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, ×tamp, &stripped)) { goto done; @@ -2278,8 +2482,8 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; ssize_t ret; int saved_errno; char *conv; @@ -2312,8 +2516,8 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dq) { - time_t timestamp; - char *stripped; + time_t timestamp = 0; + char *stripped = NULL; int ret; int saved_errno; char *conv; @@ -2582,7 +2786,7 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, } if (config->rel_connectpath == NULL && - strlen(basedir) != strlen(handle->conn->connectpath)) { + strlen(basedir) < strlen(handle->conn->connectpath)) { config->rel_connectpath = talloc_strdup(config, handle->conn->connectpath + strlen(basedir)); if (config->rel_connectpath == NULL) { @@ -2620,6 +2824,11 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle, } } + trim_string(config->mount_point, NULL, "/"); + trim_string(config->rel_connectpath, "/", "/"); + trim_string(config->snapdir, NULL, "/"); + trim_string(config->snapshot_basepath, NULL, "/"); + DEBUG(10, ("shadow_copy2_connect: configuration:\n" " share root: '%s'\n" " mountpoint: '%s'\n" -- 2.11.0.483.g087da7b7c-goog From 1ef1fffde2ce4c52802b0af230dd8744b8d3a44d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 19 Jan 2017 17:18:58 -0800 Subject: [PATCH 6/6] s3: vfs_shadow_copy2: Fix usage of saved_errno to only set errno on error. Signed-off-by: Jeremy Allison --- source3/modules/vfs_shadow_copy2.c | 232 ++++++++++++++++++++++++++----------- 1 file changed, 162 insertions(+), 70 deletions(-) diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 6aa741b5f46..6e727c95b1b 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -789,7 +789,7 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx, char *insert = NULL; char *converted = NULL; size_t insertlen, connectlen = 0; - int i, saved_errno; + int i, saved_errno = 0; size_t min_offset; struct shadow_copy2_config *config; struct shadow_copy2_private *priv; @@ -1039,7 +1039,7 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; DIR *ret; - int saved_errno; + int saved_errno = 0; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -1068,10 +1068,14 @@ static DIR *shadow_copy2_opendir(vfs_handle_struct *handle, return NULL; } ret = SMB_VFS_NEXT_OPENDIR(handle, conv_smb_fname, mask, attr); - saved_errno = errno; + if (ret == NULL) { + saved_errno = errno; + } TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1147,7 +1151,7 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL, *tmp; - int ret, saved_errno; + int ret, saved_errno = 0; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname->base_name, @@ -1169,7 +1173,9 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, } ret = SMB_VFS_NEXT_STAT(handle, smb_fname); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; @@ -1177,7 +1183,9 @@ static int shadow_copy2_stat(vfs_handle_struct *handle, if (ret == 0) { convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); } - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1186,7 +1194,7 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL, *tmp; - int ret, saved_errno; + int ret, saved_errno = 0; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname->base_name, @@ -1208,7 +1216,9 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, } ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; @@ -1216,7 +1226,9 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle, if (ret == 0) { convert_sbuf(handle, smb_fname->base_name, &smb_fname->st); } - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1247,7 +1259,7 @@ static int shadow_copy2_open(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL, *tmp; - int ret, saved_errno; + int ret, saved_errno = 0; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname->base_name, @@ -1269,12 +1281,16 @@ static int shadow_copy2_open(vfs_handle_struct *handle, } ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1283,7 +1299,7 @@ static int shadow_copy2_unlink(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; struct smb_filename *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, @@ -1306,9 +1322,13 @@ static int shadow_copy2_unlink(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_UNLINK(handle, conv); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1318,7 +1338,7 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv = NULL; struct smb_filename *conv_smb_fname; @@ -1349,10 +1369,14 @@ static int shadow_copy2_chmod(vfs_handle_struct *handle, } ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1363,7 +1387,7 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv = NULL; struct smb_filename *conv_smb_fname = NULL; @@ -1393,10 +1417,14 @@ static int shadow_copy2_chown(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1486,7 +1514,7 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; struct smb_filename *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, @@ -1509,9 +1537,13 @@ static int shadow_copy2_ntimes(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1520,7 +1552,7 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -1536,9 +1568,13 @@ static int shadow_copy2_readlink(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1547,7 +1583,7 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -1563,9 +1599,13 @@ static int shadow_copy2_mknod(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -1576,7 +1616,7 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, char *stripped = NULL; char *tmp = NULL; char *result = NULL; - int saved_errno; + int saved_errno = 0; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, ×tamp, &stripped)) { @@ -1594,10 +1634,14 @@ static char *shadow_copy2_realpath(vfs_handle_struct *handle, result = SMB_VFS_NEXT_REALPATH(handle, tmp); done: - saved_errno = errno; + if (result == NULL) { + saved_errno = errno; + } TALLOC_FREE(tmp); TALLOC_FREE(stripped); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return result; } @@ -2088,7 +2132,7 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -2117,10 +2161,14 @@ static int shadow_copy2_mkdir(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2129,7 +2177,7 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; struct smb_filename *conv_smb_fname = NULL; @@ -2158,10 +2206,14 @@ static int shadow_copy2_rmdir(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv_smb_fname); TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2170,7 +2222,7 @@ static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -2186,9 +2238,13 @@ static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, return -1; } ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2199,7 +2255,7 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -2216,9 +2272,13 @@ static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2229,7 +2289,7 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -2245,9 +2305,13 @@ static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2256,7 +2320,7 @@ static int shadow_copy2_removexattr(vfs_handle_struct *handle, { time_t timestamp = 0; char *stripped = NULL; - int ret, saved_errno; + int ret, saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -2272,9 +2336,13 @@ static int shadow_copy2_removexattr(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2286,7 +2354,7 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname, @@ -2303,9 +2371,13 @@ static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2316,7 +2388,7 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv = NULL; struct smb_filename *conv_smb_fname = NULL; @@ -2346,10 +2418,14 @@ static int shadow_copy2_chmod_acl(vfs_handle_struct *handle, return -1; } ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv_smb_fname, mode); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); TALLOC_FREE(conv_smb_fname); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2362,7 +2438,7 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv; DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], " @@ -2389,9 +2465,13 @@ static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle, ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name, mem_ctx, found_name); DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret)); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2403,7 +2483,7 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, char *tmp = NULL; char *result = NULL; char *parent_dir = NULL; - int saved_errno; + int saved_errno = 0; size_t rootpath_len = 0; struct shadow_copy2_private *priv = NULL; @@ -2470,11 +2550,15 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, DBG_DEBUG("connect path is [%s]\n", result); done: - saved_errno = errno; + if (result == NULL) { + saved_errno = errno; + } TALLOC_FREE(tmp); TALLOC_FREE(stripped); TALLOC_FREE(parent_dir); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return result; } @@ -2485,7 +2569,7 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, time_t timestamp = 0; char *stripped = NULL; ssize_t ret; - int saved_errno; + int saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, @@ -2505,9 +2589,13 @@ static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle, ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } @@ -2519,7 +2607,7 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, time_t timestamp = 0; char *stripped = NULL; int ret; - int saved_errno; + int saved_errno = 0; char *conv; if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, ×tamp, @@ -2538,9 +2626,13 @@ static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path, ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq); - saved_errno = errno; + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } -- 2.11.0.483.g087da7b7c-goog