The branch, master has been updated
       via  0e1deb7 s3: VFS: Don't allow symlink, link or rename on already 
converted paths.
       via  cda6764 s3: VFS: shadow_copy2: Fix usage of saved_errno to only set 
errno on error.
       via  4d339a8 s3: VFS: shadow_copy2: Fix a memory leak in the connectpath 
function.
       via  128d5f2 s3: VFS: shadow_copy2: Fix module to work with variable 
current working directory.
       via  b94dc85 s3: VFS: Add utility function check_for_converted_path().
       via  cd4f940 s3: VFS: Ensure shadow:format cannot contain a / path 
separator.
       via  42bd1ac s3: VFS: Allow shadow_copy2_connectpath() to return the 
cached path derived from $cwd.
       via  27340df s3: VFS: shadow_copy2: Fix chdir to store off the needed 
private variables.
       via  9d65107 s3: VFS: shadow_copy2: Add two currently unused functions 
to make pathnames absolute or relative to $cwd.
       via  2887465 s3: VFS: shadow_copy2: Change a parameter name.
       via  5aa1ea9 s3: VFS: shadow_copy2: Add a wrapper function to call the 
original shadow_copy2_strip_snapshot().
       via  72fe2b6 s3: VFS: shadow_copy2: Add two new variables to the private 
data. Not yet used.
       via  37ef8d3 s3: VFS: shadow_copy2: Fix length comparison to ensure we 
don't overstep a length.
       via  979e392 s3: VFS: shadow_copy2: Ensure pathnames for parameters are 
correctly relative and terminated.
       via  0a190f4 s3: VFS: shadow_copy2: Correctly initialize timestamp and 
stripped variables.
       via  d650d65 s3: smbd: Make set_conn_connectpath() call 
canonicalize_absolute_path().
       via  a513633 s3: smbtorture: Add new local test LOCAL-CANONICALIZE-PATH
       via  82979af s3: lib: Fix two old, old bugs in set_conn_connectpath(), 
now in canonicalize_absolute_path().
       via  02599c3 s3: lib: Add canonicalize_absolute_path().
       via  39678ed s3: smbd: Correctly canonicalize any incoming shadow copy 
path.
      from  26ffc20 build: vfs_posix_eadb is only built with the AD DC enabled

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 0e1deb77f2b310ad7e5dd784174207adacf1c981
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 26 17:19:24 2017 -0800

    s3: VFS: Don't allow symlink, link or rename on already converted paths.
    
    Snapshot paths are a read-only filesystem.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>
    
    Autobuild-User(master): Jeremy Allison <j...@samba.org>
    Autobuild-Date(master): Mon Jan 30 22:26:29 CET 2017 on sn-devel-144

commit cda6764f1a8db96182bfd1855440bc6a1ba1abee
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Jan 23 10:20:13 2017 -0800

    s3: VFS: shadow_copy2: Fix usage of saved_errno to only set errno on error.
    
    Rationale:
    
    VFS calls must act like their POSIX equivalents, and the POSIX versions
    *only* set errno on a failure. There is actually code in the upper smbd
    layers that depends on errno being correct on a fail return from a VFS call.
    
    For a compound VFS module like this, a common pattern is :
    
    SMB_VFS_CALL_X()
    {
          int ret;
    
          syscall1();
          ret = syscall2();
          syscall3();
    
          return ret;
    }
    
    Where if *any* of the contained syscallX()'s fail, they'll set errno.
    However, the actual errno we should return is *only* the one returned
    if syscall2() fails (the others are lstat's checking for existence etc.).
    
    So what we should do to correctly return only the errno from syscall2() is:
    
    SMB_VFS_CALL_X()
    {
          int ret;
          int saved_errno = 0;
    
          syscall1()
    
          ret = syscall2();
          if (ret == -1) {
                saved_errno = errno;
          }
          syscall3()
    
          if (saved_errno != 0) {
               errno = saved_errno;
          }
          return ret;
    }
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 4d339a88851f601fae195ac8ff0691cbd3504f41
Author: Jeremy Allison <j...@samba.org>
Date:   Mon Jan 23 10:06:44 2017 -0800

    s3: VFS: shadow_copy2: Fix a memory leak in the connectpath function.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 128d5f27cd42b0c7efcbe3d28fe3eee881e0734b
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 26 10:49:51 2017 -0800

    s3: VFS: shadow_copy2: Fix module to work with variable current working 
directory.
    
    Completely cleans up the horrible shadow_copy2_strip_snapshot()
    and adds an explaination of what it's actually trying to do.
    
    * This function does two things.
    *
    * 1). Checks if an incoming filename is already a
    * snapshot converted pathname.
    *     If so, it returns the pathname truncated
    *     at the snapshot point which will be used
    *     as the connectpath, and then does an early return.
    *
    * 2). Checks if an incoming filename contains an
    * SMB-layer @GMT- style timestamp.
    *     If so, it strips the timestamp, and returns
    *     both the timestamp and the stripped path
    *     (making it cwd-relative).
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit b94dc85d339c9a10496edd07b85bdd7808d2e332
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 26 10:35:50 2017 -0800

    s3: VFS: Add utility function check_for_converted_path().
    
    Detects an already converted path. Not yet used.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit cd4f940162b17e4f7345d392326a31ae478230fa
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 26 10:24:52 2017 -0800

    s3: VFS: Ensure shadow:format cannot contain a / path separator.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 42bd1acad75a6b5ea81fe4b30c067dd82623c042
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 12:09:08 2017 -0800

    s3: VFS: Allow shadow_copy2_connectpath() to return the cached path derived 
from $cwd.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 27340df4b52e4341f134667c59d71656a7a1fdae
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 12:06:55 2017 -0800

    s3: VFS: shadow_copy2: Fix chdir to store off the needed private variables.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    This is not yet used, the users of this will be added later.
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 9d65107b8f2864dba8d41b3316c483b3f36d0697
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 12:00:08 2017 -0800

    s3: VFS: shadow_copy2: Add two currently unused functions to make pathnames 
absolute or relative to $cwd.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 2887465108aef5e2e7c64417437ecb86c7460e16
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:56:21 2017 -0800

    s3: VFS: shadow_copy2: Change a parameter name.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Allows easy substitution later.
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 5aa1ea95157475dfd2d056f0158b14b2b90895a9
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:54:56 2017 -0800

    s3: VFS: shadow_copy2: Add a wrapper function to call the original 
shadow_copy2_strip_snapshot().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Allows an extra (currently unused) parameter to be added.
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 72fe2b62e3ee7462e5be855b01943f28b26c36c1
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:50:49 2017 -0800

    s3: VFS: shadow_copy2: Add two new variables to the private data. Not yet 
used.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 37ef8d3f65bd1215717eb51b2e1cdb84a7bed348
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:48:40 2017 -0800

    s3: VFS: shadow_copy2: Fix length comparison to ensure we don't overstep a 
length.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 979e39252bcc88e8aacb543b8bf322dd6f17fe7f
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:45:54 2017 -0800

    s3: VFS: shadow_copy2: Ensure pathnames for parameters are correctly 
relative and terminated.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 0a190f4dd950c947d47c42163d11ea4bd6e6e508
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Jan 20 11:42:39 2017 -0800

    s3: VFS: shadow_copy2: Correctly initialize timestamp and stripped 
variables.
    
    Allow the called functions to be fixed to not touch them on error.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit d650d65488761b30fa34d42cb1ab400618a78c33
Author: Jeremy Allison <j...@samba.org>
Date:   Tue Jan 17 11:35:52 2017 -0800

    s3: smbd: Make set_conn_connectpath() call canonicalize_absolute_path().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit a51363309a4330b65e34ae941ec99d180bdbab56
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 26 16:08:42 2017 -0800

    s3: smbtorture: Add new local test LOCAL-CANONICALIZE-PATH
    
    Tests new canonicalize_absolute_path() function.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 82979afc46cc5e466bdd999a94080e7a5df95518
Author: Jeremy Allison <j...@samba.org>
Date:   Thu Jan 19 15:18:41 2017 -0800

    s3: lib: Fix two old, old bugs 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.
    
    Canonicalizing /foo/.. would end up as '\0'.
    
    Test to follow.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 02599c39337c3049762a6b0bd6290577817ee5a5
Author: Jeremy Allison <j...@samba.org>
Date:   Tue Jan 17 11:33:18 2017 -0800

    s3: lib: Add canonicalize_absolute_path().
    
    Resolves any invalid path components (.) (..)
    in an absolute POSIX path.
    
    We will be re-using this in several places.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

commit 39678ed6af708fb6f2760bfb51051add11e3c498
Author: Jeremy Allison <j...@samba.org>
Date:   Wed Jan 11 16:30:38 2017 -0800

    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.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12531
    
    Signed-off-by: Jeremy Allison <j...@samba.org>
    Reviewed-by: Uri Simchoni <u...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/lib/util_path.c            | 139 ++++++
 source3/lib/util_path.h            |   1 +
 source3/modules/vfs_shadow_copy2.c | 909 ++++++++++++++++++++++++++-----------
 source3/selftest/tests.py          |   1 +
 source3/smbd/filename.c            | 150 ++++++
 source3/smbd/service.c             | 103 +----
 source3/torture/torture.c          |  44 ++
 7 files changed, 994 insertions(+), 353 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/lib/util_path.c b/source3/lib/util_path.c
index 509ba5f..6f58a03 100644
--- a/source3/lib/util_path.c
+++ b/source3/lib/util_path.c
@@ -93,3 +93,142 @@ char *cache_path(const char *name)
 {
        return xx_path(name, lp_cache_directory());
 }
+
+/**
+ * @brief Removes any invalid path components in an absolute POSIX path.
+ *
+ * @param ctx Talloc context to return string.
+ *
+ * @param abs_path Absolute path string to process.
+ *
+ * @retval Pointer to a talloc'ed string containing the absolute full path.
+ **/
+
+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 .. leaving us on the / or '\0' */
+                               s += 2;
+
+                               /* 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;
+                                       }
+                               }
+
+                               /*
+                                * Are we at the start ?
+                                * Can't go back further if so.
+                                */
+                               if (d <= destname) {
+                                       *d++ = '/'; /* Can't delete root */
+                                       continue;
+                               }
+
+                               /*
+                                * 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 118a4be..16e2792 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
diff --git a/source3/modules/vfs_shadow_copy2.c 
b/source3/modules/vfs_shadow_copy2.c
index 6a25c87..402eb70 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,11 @@ struct shadow_copy2_snaplist_info {
 struct shadow_copy2_private {
        struct shadow_copy2_config *config;
        struct shadow_copy2_snaplist_info *snaps;
+       char *shadow_cwd; /* Absolute $cwd path. */
+       /* Absolute connectpath - can vary depending on $cwd. */
+       char *shadow_connectpath;
+       /* malloc'ed realpath return. */
+       char *shadow_realpath;
 };
 
 static int shadow_copy2_get_shadow_copy_data(
@@ -404,79 +410,254 @@ 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;
+}
+
+static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
+                                       const char *name,
+                                       char *gmt, size_t gmt_len);
+
+/*
+ * Check if an incoming filename is already a snapshot converted pathname.
+ *
+ * If so, it returns the pathname truncated at the snapshot point which
+ * will be used as the connectpath.
+ */
+
+static int check_for_converted_path(TALLOC_CTX *mem_ctx,
+                               struct vfs_handle_struct *handle,
+                               struct shadow_copy2_private *priv,
+                               char *abs_path,
+                               bool *ppath_already_converted,
+                               char **pconnectpath)
+{
+       size_t snapdirlen = 0;
+       char *p = strstr_m(abs_path, priv->config->snapdir);
+       char *q = NULL;
+       char *connect_path = NULL;
+       char snapshot[GMT_NAME_LEN+1];
+
+       *ppath_already_converted = false;
+
+       if (p == NULL) {
+               /* Must at least contain shadow:snapdir. */
+               return 0;
+       }
+
+       if (priv->config->snapdir[0] == '/' &&
+                       p != abs_path) {
+               /* Absolute shadow:snapdir must be at the start. */
+               return 0;
+       }
+
+       snapdirlen = strlen(priv->config->snapdir);
+       if (p[snapdirlen] != '/') {
+               /* shadow:snapdir must end as a separate component. */
+               return 0;
+       }
+
+       if (p > abs_path && p[-1] != '/') {
+               /* shadow:snapdir must start as a separate component. */
+               return 0;
+       }
+
+       p += snapdirlen;
+       p++; /* Move past the / */
+
+       /*
+        * Need to return up to the next path
+        * component after the time.
+        * This will be used as the connectpath.
+        */
+       q = strchr(p, '/');
+       if (q == NULL) {
+               /*
+                * No next path component.
+                * Use entire string.
+                */
+               connect_path = talloc_strdup(mem_ctx,
+                                       abs_path);
+       } else {
+               connect_path = talloc_strndup(mem_ctx,
+                                       abs_path,
+                                       q - abs_path);
+       }
+       if (connect_path == NULL) {
+               return ENOMEM;
+       }
+
+       /*
+        * Point p at the same offset in connect_path as
+        * it is in abs_path.
+        */
+
+       p = &connect_path[p - abs_path];
+
+       /*
+        * Now ensure there is a time string at p.
+        * The SMB-format @GMT-token string is returned
+        * in snapshot.
+        */
+
+       if (!shadow_copy2_snapshot_to_gmt(handle,
+                               p,
+                               snapshot,
+                               sizeof(snapshot))) {
+               TALLOC_FREE(connect_path);
+               return 0;
+       }
+
+       if (pconnectpath != NULL) {
+               *pconnectpath = connect_path;
+       }
+
+       *ppath_already_converted = true;
+
+       DBG_DEBUG("path |%s| is already converted. "
+               "connect path = |%s|\n",
+               abs_path,
+               connect_path);
+
+       return 0;
+}
+
 /**
- * Strip a snapshot component from a filename as
- * handed in via the smb layer.
- * Returns the parsed timestamp and the stripped filename.
+ * This function does two things.
+ *
+ * 1). Checks if an incoming filename is already a
+ * snapshot converted pathname.
+ *     If so, it returns the pathname truncated
+ *     at the snapshot point which will be used
+ *     as the connectpath, and then does an early return.
+ *
+ * 2). Checks if an incoming filename contains an
+ * SMB-layer @GMT- style timestamp.
+ *     If so, it strips the timestamp, and returns
+ *     both the timestamp and the stripped path
+ *     (making it cwd-relative).
  */
-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;
+       const char *name = orig_name;
+       char *abs_path = NULL;
+       bool ret = true;
+       bool already_converted = false;
+       int err = 0;
 
        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));
+
+       err = check_for_converted_path(mem_ctx,
+                                       handle,
+                                       priv,
+                                       abs_path,
+                                       &already_converted,
+                                       psnappath);
+       if (err != 0) {
+               /* error in conversion. */
+               ret = false;
+               goto out;
+       }
+
+       if (already_converted) {
+               goto out;
+       }
+
+       /*
+        * From here we're only looking to strip an
+        * SMB-layer @GMT- token.
+        */
+
        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;
        }
 
-       /*
-        * Figure out whether we got an already converted string. One
-        * case where this happens is in a smb2 create call with the
-        * mxac create blob set. We do the get_acl call on
-        * fsp->fsp_name, which is already converted. We are converted
-        * if we got a file name of the form ".snapshots/@GMT-",
-        * i.e. ".snapshots/" precedes "p".
-        */
-
-       snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
-                                      ".snapshots");
-       snapdirlen = strlen(snapdir);
        len_before_gmt = p - name;
 
-       if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
-               const char *parent_snapdir = p - (snapdirlen+1);
-
-               DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
-
-               if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
-                       DEBUG(10, ("name=%s is already converted\n", name));
-                       goto no_snapshot;
-               }
-       }
        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 +677,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] != '/') {
                /*


-- 
Samba Shared Repository

Reply via email to