s3: VFS: shadow_copy2: Fix module to work with variable current working directory.
authorJeremy Allison <jra@samba.org>
Thu, 26 Jan 2017 18:49:51 +0000 (10:49 -0800)
committerJeremy Allison <jra@samba.org>
Mon, 30 Jan 2017 17:39:19 +0000 (18:39 +0100)
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 <jra@samba.org>
Reviewed-by: Uri Simchoni <uri@samba.org>
source3/modules/vfs_shadow_copy2.c

index d6100ac5bb2b39f45d7e7a718ec5da9f0b89034b..f116c553ac4d9834c8d0b5e77349c1d7afc820c1 100644 (file)
@@ -561,10 +561,21 @@ static int check_for_converted_path(TALLOC_CTX *mem_ctx,
 }
 
 /**
- * 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_internal(TALLOC_CTX *mem_ctx,
                                        struct vfs_handle_struct *handle,
                                        const char *orig_name,
@@ -579,62 +590,72 @@ static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
        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') {
                /*
@@ -654,12 +675,24 @@ static bool shadow_copy2_strip_snapshot_internal(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] != '/') {
                /*
@@ -667,75 +700,18 @@ static bool shadow_copy2_strip_snapshot_internal(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;
 
        rest_len = strlen(q);
        dst_len = len_before_gmt + rest_len;
 
-       if (priv->config->snapdirseverywhere) {
-               char *insert;
-               bool have_insert;
-               insert = shadow_copy2_insert_string(talloc_tos(), handle,
-                                                   timestamp);
-               if (insert == NULL) {
-                       errno = ENOMEM;
-                       return false;
-               }
-
-               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) {
-                       DEBUG(10, (__location__ ": insert string '%s' found in "
-                                  "path '%s' found in snapdirseverywhere mode "
-                                  "==> already converted\n", insert, name));
-                       TALLOC_FREE(insert);
-                       goto no_snapshot;
-               }
-               TALLOC_FREE(insert);
-       } else {
-               char *snapshot_path;
-               char *s;
-
-               snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
-                                                          handle,
-                                                          timestamp);
-               if (snapshot_path == NULL) {
-                       errno = ENOMEM;
-                       return false;
-               }
-
-               DEBUG(10, (__location__ " path: '%s'.\n"
-                          "snapshot path: '%s'\n", name, snapshot_path));
-
-               s = strstr(name, snapshot_path);
-               if (s == name) {
-                       /*
-                        * this starts with "snapshot_basepath/GMT-Token"
-                        * so it is already a converted absolute
-                        * path. Don't process further.
-                        */
-                       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;
-               }
-               talloc_free(snapshot_path);
-       }
-
        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);
@@ -744,13 +720,25 @@ static bool shadow_copy2_strip_snapshot_internal(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,