smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_shadow_copy2.c
index 9f004aff6b613605e4c967cfa87e12ea2c64e1d9..9d3f5843f43f1ee7210028db25d92646b27ffe47 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * This is a second implemetation of a shadow copy module for exposing
+ * This is a second implementation of a shadow copy module for exposing
  * file system snapshots to windows clients as shadow copies.
  *
  * See the manual page for documentation.
@@ -69,7 +69,6 @@ struct shadow_copy2_snaplist_info {
        time_t fetch_time; /* snaplist update time */
 };
 
-
 /*
  * shadow_copy2 private structure. This structure will be
  * used to keep module specific information
@@ -90,7 +89,7 @@ static int shadow_copy2_get_shadow_copy_data(
        bool labels);
 
 /**
- *This function will create a new snapshot list entry and
+ * 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.
  *
@@ -115,7 +114,7 @@ static struct shadow_copy2_snapentry *shadow_copy2_create_snapentry(
 }
 
 /**
- *This function will delete the entire snaplist and reset
+ * This function will delete the entire snaplist and reset
  * priv->snaps->snaplist to NULL.
  *
  * @param[in] priv shadow_copye specific data structure
@@ -369,7 +368,7 @@ static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
                                         config->snapdir, snaptime_string);
        }
        if (result == NULL) {
-               DEBUG(1, (__location__ " talloc_asprintf failed\n"));
+               DBG_WARNING("talloc_asprintf failed\n");
        }
 
        return result;
@@ -406,7 +405,7 @@ static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
        result = talloc_asprintf(mem_ctx, "%s/%s",
                                 priv->config->snapshot_basepath, snaptime_string);
        if (result == NULL) {
-               DEBUG(1, (__location__ " talloc_asprintf failed\n"));
+               DBG_WARNING("talloc_asprintf failed\n");
        }
 
        return result;
@@ -572,13 +571,13 @@ static int check_for_converted_path(TALLOC_CTX *mem_ctx,
  * This function does two things.
  *
  * 1). Checks if an incoming filename is already a
- * snapshot converted pathname.
+ *     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.
+ *     SMB-layer @GMT- style timestamp.
  *     If so, it strips the timestamp, and returns
  *     both the timestamp and the stripped path
  *     (making it cwd-relative).
@@ -813,8 +812,9 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
                        goto fail;
                }
 
-               ZERO_STRUCT(converted_fname);
-               converted_fname.base_name = converted;
+               converted_fname = (struct smb_filename) {
+                       .base_name = converted,
+               };
 
                ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
                DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
@@ -864,7 +864,7 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
        insertlen = talloc_get_size(insert)-1;
 
        /*
-        * Note: We deliberatly don't expensively initialize the
+        * Note: We deliberately don't expensively initialize the
         * array with talloc_zero here: Putting zero into
         * converted[pathlen+insertlen] below is sufficient, because
         * in the following for loop, the insert string is inserted
@@ -901,8 +901,9 @@ static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
        memcpy(converted, path, pathlen+1);
        converted[pathlen+insertlen] = '\0';
 
-       ZERO_STRUCT(converted_fname);
-       converted_fname.base_name = converted;
+       converted_fname = (struct smb_filename) {
+               .base_name = converted,
+       };
 
        for (i = num_slashes-1; i>=0; i--) {
                int ret;
@@ -1168,19 +1169,45 @@ static int shadow_copy2_linkat(vfs_handle_struct *handle,
 static int shadow_copy2_stat(vfs_handle_struct *handle,
                             struct smb_filename *smb_fname)
 {
+       struct shadow_copy2_private *priv = NULL;
        time_t timestamp = 0;
        char *stripped = NULL;
+       bool converted = false;
+       char *abspath = NULL;
        char *tmp;
-       int saved_errno = 0;
-       int ret;
+       int ret = 0;
 
-       if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
-                                        smb_fname,
-                                        &timestamp, &stripped)) {
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return -1);
+
+       if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+                                                  handle,
+                                                  smb_fname,
+                                                  &timestamp,
+                                                  &stripped,
+                                                  &converted)) {
                return -1;
        }
        if (timestamp == 0) {
-               return SMB_VFS_NEXT_STAT(handle, smb_fname);
+               TALLOC_FREE(stripped);
+               ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+               if (ret != 0) {
+                       return ret;
+               }
+               if (!converted) {
+                       return 0;
+               }
+
+               abspath = make_path_absolute(talloc_tos(),
+                                            priv,
+                                            smb_fname->base_name);
+               if (abspath == NULL) {
+                       return -1;
+               }
+
+               convert_sbuf(handle, abspath, &smb_fname->st);
+               TALLOC_FREE(abspath);
+               return 0;
        }
 
        tmp = smb_fname->base_name;
@@ -1194,38 +1221,70 @@ static int shadow_copy2_stat(vfs_handle_struct *handle,
        }
 
        ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-       if (ret == -1) {
-               saved_errno = errno;
+       if (ret != 0) {
+               goto out;
+       }
+
+       abspath = make_path_absolute(talloc_tos(),
+                                    priv,
+                                    smb_fname->base_name);
+       if (abspath == NULL) {
+               ret = -1;
+               goto out;
        }
 
+       convert_sbuf(handle, abspath, &smb_fname->st);
+       TALLOC_FREE(abspath);
+
+out:
        TALLOC_FREE(smb_fname->base_name);
        smb_fname->base_name = tmp;
 
-       if (ret == 0) {
-               convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
-       }
-       if (saved_errno != 0) {
-               errno = saved_errno;
-       }
        return ret;
 }
 
 static int shadow_copy2_lstat(vfs_handle_struct *handle,
                              struct smb_filename *smb_fname)
 {
+       struct shadow_copy2_private *priv = NULL;
        time_t timestamp = 0;
        char *stripped = NULL;
+       bool converted = false;
+       char *abspath = NULL;
        char *tmp;
-       int saved_errno = 0;
-       int ret;
+       int ret = 0;
 
-       if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
-                                        smb_fname,
-                                        &timestamp, &stripped)) {
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return -1);
+
+       if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+                                                  handle,
+                                                  smb_fname,
+                                                  &timestamp,
+                                                  &stripped,
+                                                  &converted)) {
                return -1;
        }
        if (timestamp == 0) {
-               return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+               TALLOC_FREE(stripped);
+               ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+               if (ret != 0) {
+                       return ret;
+               }
+               if (!converted) {
+                       return 0;
+               }
+
+               abspath = make_path_absolute(talloc_tos(),
+                                            priv,
+                                            smb_fname->base_name);
+               if (abspath == NULL) {
+                       return -1;
+               }
+
+               convert_sbuf(handle, abspath, &smb_fname->st);
+               TALLOC_FREE(abspath);
+               return 0;
        }
 
        tmp = smb_fname->base_name;
@@ -1239,45 +1298,76 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle,
        }
 
        ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-       if (ret == -1) {
-               saved_errno = errno;
+       if (ret != 0) {
+               goto out;
+       }
+
+       abspath = make_path_absolute(talloc_tos(),
+                                    priv,
+                                    smb_fname->base_name);
+       if (abspath == NULL) {
+               ret = -1;
+               goto out;
        }
 
+       convert_sbuf(handle, abspath, &smb_fname->st);
+       TALLOC_FREE(abspath);
+
+out:
        TALLOC_FREE(smb_fname->base_name);
        smb_fname->base_name = tmp;
 
-       if (ret == 0) {
-               convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
-       }
-       if (saved_errno != 0) {
-               errno = saved_errno;
-       }
        return ret;
 }
 
 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
                              SMB_STRUCT_STAT *sbuf)
 {
+       struct shadow_copy2_private *priv = NULL;
        time_t timestamp = 0;
        struct smb_filename *orig_smb_fname = NULL;
        struct smb_filename vss_smb_fname;
        struct smb_filename *orig_base_smb_fname = NULL;
        struct smb_filename vss_base_smb_fname;
        char *stripped = NULL;
-       int saved_errno = 0;
+       char *abspath = NULL;
+       bool converted = false;
        bool ok;
        int ret;
 
-       ok = shadow_copy2_strip_snapshot(talloc_tos(), handle,
-                                        fsp->fsp_name,
-                                        &timestamp, &stripped);
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return -1);
+
+       ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
+                                                  handle,
+                                                  fsp->fsp_name,
+                                                  &timestamp,
+                                                  &stripped,
+                                                  &converted);
        if (!ok) {
                return -1;
        }
 
        if (timestamp == 0) {
                TALLOC_FREE(stripped);
-               return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+               ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+               if (ret != 0) {
+                       return ret;
+               }
+               if (!converted) {
+                       return 0;
+               }
+
+               abspath = make_path_absolute(talloc_tos(),
+                                            priv,
+                                            fsp->fsp_name->base_name);
+               if (abspath == NULL) {
+                       return -1;
+               }
+
+               convert_sbuf(handle, abspath, sbuf);
+               TALLOC_FREE(abspath);
+               return 0;
        }
 
        vss_smb_fname = *fsp->fsp_name;
@@ -1293,7 +1383,7 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
        orig_smb_fname = fsp->fsp_name;
        fsp->fsp_name = &vss_smb_fname;
 
-       if (fsp->base_fsp != NULL) {
+       if (fsp_is_alternate_stream(fsp)) {
                vss_base_smb_fname = *fsp->base_fsp->fsp_name;
                vss_base_smb_fname.base_name = vss_smb_fname.base_name;
                orig_base_smb_fname = fsp->base_fsp->fsp_name;
@@ -1301,38 +1391,49 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
        }
 
        ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
-       fsp->fsp_name = orig_smb_fname;
-       if (fsp->base_fsp != NULL) {
-               fsp->base_fsp->fsp_name = orig_base_smb_fname;
-       }
-       if (ret == -1) {
-               saved_errno = errno;
+       if (ret != 0) {
+               goto out;
        }
 
-       if (ret == 0) {
-               convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
+       abspath = make_path_absolute(talloc_tos(),
+                                    priv,
+                                    fsp->fsp_name->base_name);
+       if (abspath == NULL) {
+               ret = -1;
+               goto out;
        }
-       if (saved_errno != 0) {
-               errno = saved_errno;
+
+       convert_sbuf(handle, abspath, sbuf);
+       TALLOC_FREE(abspath);
+
+out:
+       fsp->fsp_name = orig_smb_fname;
+       if (fsp_is_alternate_stream(fsp)) {
+               fsp->base_fsp->fsp_name = orig_base_smb_fname;
        }
+
        return ret;
 }
 
-static int shadow_copy2_openat(vfs_handle_struct *handle,
-                              const struct files_struct *dirfsp,
-                              const struct smb_filename *smb_fname_in,
-                              struct files_struct *fsp,
-                              int flags,
-                              mode_t mode)
+static int shadow_copy2_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname_in,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
 {
+       struct shadow_copy2_private *priv = NULL;
        struct smb_filename *smb_fname = NULL;
        time_t timestamp = 0;
        char *stripped = NULL;
-       bool is_converted = false;
-       int saved_errno = 0;
+       char *abspath = NULL;
+       bool converted = false;
        int ret;
        bool ok;
 
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return -1);
+
        smb_fname = full_path_from_dirfsp_atname(talloc_tos(),
                                                 dirfsp,
                                                 smb_fname_in);
@@ -1346,54 +1447,168 @@ static int shadow_copy2_openat(vfs_handle_struct *handle,
                                                   smb_fname,
                                                   &timestamp,
                                                   &stripped,
-                                                  &is_converted);
+                                                  &converted);
        if (!ok) {
                return -1;
        }
        if (timestamp == 0) {
-               if (is_converted) {
+               TALLOC_FREE(stripped);
+               ret = SMB_VFS_NEXT_FSTATAT(
+                       handle, dirfsp, smb_fname_in, sbuf, flags);
+               if (ret != 0) {
+                       return ret;
+               }
+               if (!converted) {
+                       return 0;
+               }
+
+               abspath = make_path_absolute(
+                       talloc_tos(), priv, smb_fname->base_name);
+               if (abspath == NULL) {
+                       errno = ENOMEM;
+                       return -1;
+               }
+
+               convert_sbuf(handle, abspath, sbuf);
+               TALLOC_FREE(abspath);
+               return 0;
+       }
+
+       smb_fname->base_name = shadow_copy2_convert(
+               smb_fname, handle, stripped, timestamp);
+       TALLOC_FREE(stripped);
+       if (smb_fname->base_name == NULL) {
+               TALLOC_FREE(smb_fname);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_FSTATAT(handle,
+                                  dirfsp,
+                                  smb_fname,
+                                  sbuf,
+                                  flags);
+       if (ret != 0) {
+               int saved_errno = errno;
+               TALLOC_FREE(smb_fname);
+               errno = saved_errno;
+               return -1;
+       }
+
+       abspath = make_path_absolute(
+               talloc_tos(), priv, smb_fname->base_name);
+       if (abspath == NULL) {
+               TALLOC_FREE(smb_fname);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       convert_sbuf(handle, abspath, sbuf);
+       TALLOC_FREE(abspath);
+
+       TALLOC_FREE(smb_fname);
+
+       return 0;
+}
+
+static struct smb_filename *shadow_copy2_openat_name(
+       TALLOC_CTX *mem_ctx,
+       const struct files_struct *dirfsp,
+       const struct files_struct *fsp,
+       const struct smb_filename *smb_fname_in)
+{
+       struct smb_filename *result = NULL;
+
+       if (fsp->base_fsp != NULL) {
+               struct smb_filename *base_fname = fsp->base_fsp->fsp_name;
+
+               if (smb_fname_in->base_name[0] == '/') {
                        /*
-                        * Just pave over the user requested mode and use
-                        * O_RDONLY. Later attempts by the client to write on
-                        * the handle will fail in the pwrite() syscall with
-                        * EINVAL which we carefully map to EROFS. In sum, this
-                        * matches Windows behaviour.
+                        * Special-case stream names from streams_depot
                         */
-                       flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
+                       result = cp_smb_filename(mem_ctx, smb_fname_in);
+               } else {
+
+                       SMB_ASSERT(is_named_stream(smb_fname_in));
+
+                       result = synthetic_smb_fname(mem_ctx,
+                                                    base_fname->base_name,
+                                                    smb_fname_in->stream_name,
+                                                    &smb_fname_in->st,
+                                                    smb_fname_in->twrp,
+                                                    smb_fname_in->flags);
                }
+       } else {
+               result = full_path_from_dirfsp_atname(
+                       mem_ctx, dirfsp, smb_fname_in);
+       }
+
+       return result;
+}
+
+static int shadow_copy2_openat(vfs_handle_struct *handle,
+                              const struct files_struct *dirfsp,
+                              const struct smb_filename *smb_fname_in,
+                              struct files_struct *fsp,
+                              const struct vfs_open_how *_how)
+{
+       struct vfs_open_how how = *_how;
+       struct smb_filename *smb_fname = NULL;
+       time_t timestamp = 0;
+       char *stripped = NULL;
+       int saved_errno = 0;
+       int ret;
+       bool ok;
+
+       if (how.resolve != 0) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       smb_fname = shadow_copy2_openat_name(
+               talloc_tos(), dirfsp, fsp, smb_fname_in);
+       if (smb_fname == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ok = shadow_copy2_strip_snapshot(talloc_tos(),
+                                        handle,
+                                        smb_fname,
+                                        &timestamp,
+                                        &stripped);
+       if (!ok) {
+               TALLOC_FREE(smb_fname);
+               return -1;
+       }
+       if (timestamp == 0) {
+               TALLOC_FREE(stripped);
+               TALLOC_FREE(smb_fname);
                return SMB_VFS_NEXT_OPENAT(handle,
                                           dirfsp,
                                           smb_fname_in,
                                           fsp,
-                                          flags,
-                                          mode);
+                                          &how);
        }
 
        smb_fname->base_name = shadow_copy2_convert(smb_fname,
                                               handle,
                                               stripped,
                                               timestamp);
-       TALLOC_FREE(stripped);
        if (smb_fname->base_name == NULL) {
+               int err = errno;
+               TALLOC_FREE(stripped);
                TALLOC_FREE(smb_fname);
-               errno = ENOMEM;
+               errno = err;
                return -1;
        }
-
-       /*
-        * Just pave over the user requested mode and use O_RDONLY. Later
-        * attempts by the client to write on the handle will fail in the
-        * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum,
-        * this matches Windows behaviour.
-        */
-       flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
+       TALLOC_FREE(stripped);
 
        ret = SMB_VFS_NEXT_OPENAT(handle,
                                  dirfsp,
                                  smb_fname,
                                  fsp,
-                                 flags,
-                                 mode);
+                                 &how);
        if (ret == -1) {
                saved_errno = errno;
        }
@@ -1714,6 +1929,7 @@ done:
  * otherwise return NULL.
  */
 static char *have_snapdir(struct vfs_handle_struct *handle,
+                         TALLOC_CTX *mem_ctx,
                          const char *path)
 {
        struct smb_filename smb_fname;
@@ -1723,9 +1939,10 @@ static char *have_snapdir(struct vfs_handle_struct *handle,
        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, priv->config->snapdir);
+       smb_fname = (struct smb_filename) {
+               .base_name = talloc_asprintf(
+                       mem_ctx, "%s/%s", path, priv->config->snapdir),
+       };
        if (smb_fname.base_name == NULL) {
                return NULL;
        }
@@ -1757,7 +1974,7 @@ static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
        config = priv->config;
 
        /*
-        * If the non-snapdisrseverywhere mode, we should not search!
+        * If the non-snapdirseverywhere mode, we should not search!
         */
        if (!config->snapdirseverywhere) {
                return config->snapshot_basepath;
@@ -1770,7 +1987,7 @@ static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
-       snapdir = have_snapdir(handle, path);
+       snapdir = have_snapdir(handle, talloc_tos(), path);
        if (snapdir != NULL) {
                TALLOC_FREE(path);
                return snapdir;
@@ -1780,7 +1997,7 @@ static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
 
                p[0] = '\0';
 
-               snapdir = have_snapdir(handle, path);
+               snapdir = have_snapdir(handle, talloc_tos(), path);
                if (snapdir != NULL) {
                        TALLOC_FREE(path);
                        return snapdir;
@@ -1794,7 +2011,7 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
                                         const char *name,
                                         char *gmt, size_t gmt_len)
 {
-       struct tm timestamp;
+       struct tm timestamp = { .tm_sec = 0, };
        time_t timestamp_t;
        unsigned long int timestamp_long;
        const char *fmt;
@@ -1840,7 +2057,6 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
                }
        }
 
-       ZERO_STRUCT(timestamp);
        if (config->use_sscanf) {
                if (sscanf(name, fmt, &timestamp_long) != 1) {
                        DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
@@ -1859,7 +2075,7 @@ static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
                }
                DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
                           fmt, name));
-               
+
                if (config->use_localtime) {
                        timestamp.tm_isdst = -1;
                        timestamp_t = mktime(&timestamp);
@@ -1935,7 +2151,9 @@ static int shadow_copy2_get_shadow_copy_data(
        struct shadow_copy2_private *priv = NULL;
        struct shadow_copy2_snapentry *tmpentry = NULL;
        bool get_snaplist = false;
-       int open_flags = O_RDONLY;
+       struct vfs_open_how how = {
+               .flags = O_RDONLY, .mode = 0,
+       };
        int fd;
        int ret = -1;
        NTSTATUS status;
@@ -1977,15 +2195,14 @@ static int shadow_copy2_get_shadow_copy_data(
        }
 
 #ifdef O_DIRECTORY
-       open_flags |= O_DIRECTORY;
+       how.flags |= O_DIRECTORY;
 #endif
 
        fd = SMB_VFS_NEXT_OPENAT(handle,
                                 fspcwd,
                                 snapdir_smb_fname,
                                 dirfsp,
-                                open_flags,
-                                0);
+                                &how);
        if (fd == -1) {
                DBG_WARNING("SMB_VFS_NEXT_OPEN failed for '%s'"
                            " - %s\n", snapdir, strerror(errno));
@@ -2042,7 +2259,7 @@ static int shadow_copy2_get_shadow_copy_data(
                time(&(priv->snaps->fetch_time));
        }
 
-       while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p, NULL))) {
+       while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p))) {
                char snapshot[GMT_NAME_LEN+1];
                SHADOW_COPY_LABEL *tlabels;
 
@@ -2131,60 +2348,6 @@ done:
        return ret;
 }
 
-static NTSTATUS shadow_copy2_get_nt_acl_at(vfs_handle_struct *handle,
-                                       struct files_struct *dirfsp,
-                                       const struct smb_filename *smb_fname,
-                                       uint32_t security_info,
-                                       TALLOC_CTX *mem_ctx,
-                                       struct security_descriptor **ppdesc)
-{
-       time_t timestamp = 0;
-       char *stripped = NULL;
-       NTSTATUS status;
-       char *conv;
-       struct smb_filename *conv_smb_fname = NULL;
-
-       if (!shadow_copy2_strip_snapshot(talloc_tos(),
-                                       handle,
-                                       smb_fname,
-                                       &timestamp,
-                                       &stripped)) {
-               return map_nt_error_from_unix(errno);
-       }
-       if (timestamp == 0) {
-               return SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
-                                       dirfsp,
-                                       smb_fname,
-                                       security_info,
-                                       mem_ctx,
-                                       ppdesc);
-       }
-       conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
-       TALLOC_FREE(stripped);
-       if (conv == NULL) {
-               return map_nt_error_from_unix(errno);
-       }
-       conv_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       conv,
-                                       NULL,
-                                       NULL,
-                                       0,
-                                       smb_fname->flags);
-       if (conv_smb_fname == NULL) {
-               TALLOC_FREE(conv);
-               return NT_STATUS_NO_MEMORY;
-       }
-       status = SMB_VFS_NEXT_GET_NT_ACL_AT(handle,
-                                       dirfsp,
-                                       conv_smb_fname,
-                                       security_info,
-                                       mem_ctx,
-                                       ppdesc);
-       TALLOC_FREE(conv);
-       TALLOC_FREE(conv_smb_fname);
-       return status;
-}
-
 static int shadow_copy2_mkdirat(vfs_handle_struct *handle,
                                struct files_struct *dirfsp,
                                const struct smb_filename *smb_fname,
@@ -2206,6 +2369,7 @@ static int shadow_copy2_mkdirat(vfs_handle_struct *handle,
                                        full_fname,
                                        &timestamp,
                                        NULL)) {
+               TALLOC_FREE(full_fname);
                return -1;
        }
        TALLOC_FREE(full_fname);
@@ -2219,15 +2383,15 @@ static int shadow_copy2_mkdirat(vfs_handle_struct *handle,
                        mode);
 }
 
-static int shadow_copy2_chflags(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
+static int shadow_copy2_fchflags(vfs_handle_struct *handle,
+                               struct files_struct *fsp,
                                unsigned int flags)
 {
        time_t timestamp = 0;
 
        if (!shadow_copy2_strip_snapshot(talloc_tos(),
                                        handle,
-                                       smb_fname,
+                                       fsp->fsp_name,
                                        &timestamp,
                                        NULL)) {
                return -1;
@@ -2236,60 +2400,7 @@ static int shadow_copy2_chflags(vfs_handle_struct *handle,
                errno = EROFS;
                return -1;
        }
-       return SMB_VFS_NEXT_CHFLAGS(handle, smb_fname, flags);
-}
-
-static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *aname,
-                               void *value,
-                               size_t size)
-{
-       time_t timestamp = 0;
-       char *stripped = NULL;
-       ssize_t ret;
-       int saved_errno = 0;
-       char *conv;
-       struct smb_filename *conv_smb_fname = NULL;
-
-       if (!shadow_copy2_strip_snapshot(talloc_tos(),
-                               handle,
-                               smb_fname,
-                               &timestamp,
-                               &stripped)) {
-               return -1;
-       }
-       if (timestamp == 0) {
-               return SMB_VFS_NEXT_GETXATTR(handle, smb_fname, aname, value,
-                                            size);
-       }
-       conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
-       TALLOC_FREE(stripped);
-       if (conv == NULL) {
-               return -1;
-       }
-
-       conv_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                       conv,
-                                       NULL,
-                                       NULL,
-                                       0,
-                                       smb_fname->flags);
-       if (conv_smb_fname == NULL) {
-               TALLOC_FREE(conv);
-               return -1;
-       }
-
-       ret = SMB_VFS_NEXT_GETXATTR(handle, conv_smb_fname, aname, value, size);
-       if (ret == -1) {
-               saved_errno = errno;
-       }
-       TALLOC_FREE(conv_smb_fname);
-       TALLOC_FREE(conv);
-       if (saved_errno != 0) {
-               errno = saved_errno;
-       }
-       return ret;
+       return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
 }
 
 static int shadow_copy2_fsetxattr(struct vfs_handle_struct *handle,
@@ -2350,17 +2461,28 @@ static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
 {
        time_t timestamp = 0;
        char *stripped = NULL;
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *conv = NULL;
        NTSTATUS status;
 
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        if (!shadow_copy2_strip_snapshot(mem_ctx,
                                        handle,
-                                       smb_fname,
+                                       full_fname,
                                        &timestamp,
                                        &stripped)) {
+               TALLOC_FREE(full_fname);
                return NT_STATUS_NO_MEMORY;
        }
        if (timestamp == 0) {
+               TALLOC_FREE(full_fname);
+               TALLOC_FREE(stripped);
                return SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
                                        mem_ctx,
                                        dirfsp,
@@ -2369,11 +2491,13 @@ static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
                                        preferral_count);
        }
 
-       conv = cp_smb_filename(mem_ctx, smb_fname);
+       conv = cp_smb_filename(mem_ctx, full_fname);
        if (conv == NULL) {
+               TALLOC_FREE(full_fname);
                TALLOC_FREE(stripped);
                return NT_STATUS_NO_MEMORY;
        }
+       TALLOC_FREE(full_fname);
        conv->base_name = shadow_copy2_convert(conv,
                                        handle,
                                        stripped,
@@ -2386,7 +2510,7 @@ static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
 
        status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
                                mem_ctx,
-                               dirfsp,
+                               handle->conn->cwd_fsp,
                                conv,
                                ppreflist,
                                preferral_count);
@@ -2400,116 +2524,16 @@ static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
        return status;
 }
 
-static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
-                                         const struct smb_filename *fname,
-                                         const char *name,
-                                         TALLOC_CTX *mem_ctx,
-                                         char **found_name)
-{
-       struct shadow_copy2_private *priv = NULL;
-       struct shadow_copy2_config *config = NULL;
-       time_t timestamp = 0;
-       char *stripped = NULL;
-       ssize_t ret;
-       int saved_errno = 0;
-       char *conv;
-       struct smb_filename conv_fname;
-
-       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
-                               return -1);
-       config = priv->config;
-
-       DBG_DEBUG("Path=[%s] name=[%s]\n", smb_fname_str_dbg(fname), name);
-
-       if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
-                                        &timestamp, &stripped)) {
-               DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
-               return -1;
-       }
-       if (timestamp == 0) {
-               DEBUG(10, ("timestamp == 0\n"));
-               return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, fname, name,
-                                                     mem_ctx, found_name);
-       }
-
-       /*
-        * Note that stripped may be an empty string "" if path was ".". As
-        * shadow_copy2_convert() combines "" with the shadow-copy tree connect
-        * root fullpath and get_real_filename_full_scan() has an explicit check
-        * for "" this works.
-        */
-       DBG_DEBUG("stripped [%s]\n", stripped);
-
-       conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
-       if (conv == NULL) {
-               if (!config->snapdirseverywhere) {
-                       DBG_DEBUG("shadow_copy2_convert [%s] failed\n", stripped);
-                       return -1;
-               }
-
-               /*
-                * We're called in the path traversal loop in unix_convert()
-                * walking down the directory hierarchy. shadow_copy2_convert()
-                * will fail if the snapshot directory is futher down in the
-                * hierachy. Set conv to the original stripped path and try to
-                * look it up in the filesystem with
-                * SMB_VFS_NEXT_GET_REAL_FILENAME() or
-                * get_real_filename_full_scan().
-                */
-               DBG_DEBUG("Use stripped [%s] as conv\n", stripped);
-               conv = talloc_strdup(talloc_tos(), stripped);
-               if (conv == NULL) {
-                       TALLOC_FREE(stripped);
-                       return -1;
-               }
-       }
-
-       conv_fname = (struct smb_filename) {
-               .base_name = conv,
-       };
-
-       DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
-                  "name=[%s]\n", conv, name));
-       ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, &conv_fname, name,
-                                            mem_ctx, found_name);
-       DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
-       if (ret == 0) {
-               return 0;
-       }
-       if (errno != EOPNOTSUPP) {
-               TALLOC_FREE(conv);
-               errno = EOPNOTSUPP;
-               return -1;
-       }
-
-       ret = get_real_filename_full_scan(handle->conn,
-                                         conv,
-                                         name,
-                                         false,
-                                         mem_ctx,
-                                         found_name);
-       if (ret != 0) {
-               saved_errno = errno;
-               DBG_DEBUG("Scan [%s] for [%s] failed\n",
-                         conv, name);
-               errno = saved_errno;
-               return -1;
-       }
-
-       DBG_DEBUG("Scan [%s] for [%s] returned [%s]\n",
-                 conv, name, *found_name);
-
-       TALLOC_FREE(conv);
-       return 0;
-}
-
-static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
-                                       const struct smb_filename *smb_fname_in)
+static const char *shadow_copy2_connectpath(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname_in)
 {
        time_t timestamp = 0;
        char *stripped = NULL;
        char *tmp = NULL;
        const char *fname = smb_fname_in->base_name;
+       const struct smb_filename *full = NULL;
        struct smb_filename smb_fname = {0};
        struct smb_filename *result_fname = NULL;
        char *result = NULL;
@@ -2529,12 +2553,18 @@ static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
                return priv->shadow_connectpath;
        }
 
-       if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname_in,
+       full = full_path_from_dirfsp_atname(
+               talloc_tos(), dirfsp, smb_fname_in);
+       if (full == NULL) {
+               return NULL;
+       }
+
+       if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, full,
                                         &timestamp, &stripped)) {
                goto done;
        }
        if (timestamp == 0) {
-               return SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname_in);
+               return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname_in);
        }
 
        tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
@@ -2916,9 +2946,9 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
        const char *snapsharepath = NULL;
        const char *mount_point;
 
-       DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
-                  (unsigned)handle->conn->cnum,
-                  handle->conn->connectpath));
+       DBG_DEBUG("cnum[%" PRIu32 "], connectpath[%s]\n",
+                 handle->conn->cnum,
+                 handle->conn->connectpath);
 
        ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
        if (ret < 0) {
@@ -3046,10 +3076,10 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
                                           "shadow", "mountpoint", NULL);
        if (mount_point != NULL) {
                if (mount_point[0] != '/') {
-                       DEBUG(1, (__location__ " Warning: 'mountpoint' is "
-                                 "relative ('%s'), but it has to be an "
-                                 "absolute path. Ignoring provided value.\n",
-                                 mount_point));
+                       DBG_WARNING("Warning: 'mountpoint' is relative "
+                                   "('%s'), but it has to be an absolute "
+                                   "path. Ignoring provided value.\n",
+                                   mount_point);
                        mount_point = NULL;
                } else {
                        char *p;
@@ -3069,7 +3099,7 @@ 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) {
-                       DEBUG(0, (__location__ " talloc_strdup() failed\n"));
+                       DBG_ERR("talloc_strdup() failed\n");
                        return -1;
                }
        } else {
@@ -3088,10 +3118,10 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 
        if (basedir != NULL) {
                if (basedir[0] != '/') {
-                       DEBUG(1, (__location__ " Warning: 'basedir' is "
-                                 "relative ('%s'), but it has to be an "
-                                 "absolute path. Disabling basedir.\n",
-                                 basedir));
+                       DBG_WARNING("Warning: 'basedir' is "
+                                   "relative ('%s'), but it has to be an "
+                                   "absolute path. Disabling basedir.\n",
+                                   basedir);
                        basedir = NULL;
                } else {
                        char *p;
@@ -3108,8 +3138,8 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
        }
 
        if (config->snapdirseverywhere && basedir != NULL) {
-               DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
-                         "with 'snapdirseverywhere'. Disabling basedir.\n"));
+               DBG_WARNING("Warning: 'basedir' is incompatible "
+                           "with 'snapdirseverywhere'. Disabling basedir.\n");
                basedir = NULL;
        }
 
@@ -3164,17 +3194,18 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
        if (config->snapdir[0] == '/') {
                config->snapdir_absolute = true;
 
-               if (config->snapdirseverywhere == true) {
-                       DEBUG(1, (__location__ " Warning: An absolute snapdir "
-                                 "is incompatible with 'snapdirseverywhere', "
-                                 "setting 'snapdirseverywhere' to false.\n"));
+               if (config->snapdirseverywhere) {
+                       DBG_WARNING("Warning: An absolute snapdir is "
+                                   "incompatible with 'snapdirseverywhere', "
+                                   "setting 'snapdirseverywhere' to "
+                                   "false.\n");
                        config->snapdirseverywhere = false;
                }
 
-               if (config->crossmountpoints == true) {
-                       DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
-                                 "is not supported with an absolute snapdir. "
-                                 "Disabling it.\n"));
+               if (config->crossmountpoints) {
+                       DBG_WARNING("Warning: 'crossmountpoints' is not "
+                                   "supported with an absolute snapdir. "
+                                   "Disabling it.\n");
                        config->crossmountpoints = false;
                }
 
@@ -3244,6 +3275,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
        .stat_fn = shadow_copy2_stat,
        .lstat_fn = shadow_copy2_lstat,
        .fstat_fn = shadow_copy2_fstat,
+       .fstatat_fn = shadow_copy2_fstatat,
        .openat_fn = shadow_copy2_openat,
        .unlinkat_fn = shadow_copy2_unlinkat,
        .fchmod_fn = shadow_copy2_fchmod,
@@ -3252,15 +3284,10 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
        .readlinkat_fn = shadow_copy2_readlinkat,
        .mknodat_fn = shadow_copy2_mknodat,
        .realpath_fn = shadow_copy2_realpath,
-       .get_nt_acl_at_fn = shadow_copy2_get_nt_acl_at,
        .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
        .mkdirat_fn = shadow_copy2_mkdirat,
-       .getxattr_fn = shadow_copy2_getxattr,
-       .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
-       .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
        .fsetxattr_fn = shadow_copy2_fsetxattr,
-       .chflags_fn = shadow_copy2_chflags,
-       .get_real_filename_fn = shadow_copy2_get_real_filename,
+       .fchflags_fn = shadow_copy2_fchflags,
        .pwrite_fn = shadow_copy2_pwrite,
        .pwrite_send_fn = shadow_copy2_pwrite_send,
        .pwrite_recv_fn = shadow_copy2_pwrite_recv,