]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_shadow_copy2: implement readdir()
authorRalph Boehme <slow@samba.org>
Thu, 24 Mar 2022 15:25:22 +0000 (16:25 +0100)
committerJeremy Allison <jra@samba.org>
Thu, 31 Mar 2022 18:47:42 +0000 (18:47 +0000)
RN: shadow_copy2 fails listing snapshotted dirs with shadow:fixinodes
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15035

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Mar 31 18:47:42 UTC 2022 on sn-devel-184

selftest/knownfail.d/samba3.blackbox.shadow_copy_torture [deleted file]
source3/modules/vfs_shadow_copy2.c

diff --git a/selftest/knownfail.d/samba3.blackbox.shadow_copy_torture b/selftest/knownfail.d/samba3.blackbox.shadow_copy_torture
deleted file mode 100644 (file)
index 36f2acb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-^samba3.blackbox.shadow_copy_torture.fix inodes when listing directory\(fileserver\)
index 8e92cc71e1828b23e88986c98375610f9a0a058e..dfdc6735dfb7813a0eaae2ab0a02051361855b7b 100644 (file)
@@ -3331,6 +3331,96 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
        return 0;
 }
 
+static struct dirent *shadow_copy2_readdir(vfs_handle_struct *handle,
+                                          struct files_struct *dirfsp,
+                                          DIR *dirp,
+                                          SMB_STRUCT_STAT *sbuf)
+{
+       struct shadow_copy2_private *priv = NULL;
+       struct dirent *ent = NULL;
+       struct smb_filename atname;
+       struct smb_filename *full_fname = NULL;
+       time_t timestamp = 0;
+       char *stripped = NULL;
+       char *conv = NULL;
+       char *abspath = NULL;
+       bool converted = false;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return NULL);
+
+       ent = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp, sbuf);
+       if (ent == NULL) {
+               return NULL;
+       }
+       if (sbuf == NULL) {
+               return ent;
+       }
+       if (ISDOT(dirfsp->fsp_name->base_name) && ISDOTDOT(ent->d_name)) {
+               return ent;
+       }
+
+       atname = (struct smb_filename) {
+               .base_name = ent->d_name,
+               .twrp = dirfsp->fsp_name->twrp,
+               .flags = dirfsp->fsp_name->flags,
+       };
+
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 &atname);
+       if (full_fname == NULL) {
+               return NULL;
+       }
+
+       if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+                                                  handle,
+                                                  full_fname,
+                                                  &timestamp,
+                                                  &stripped,
+                                                  &converted)) {
+               TALLOC_FREE(full_fname);
+               return NULL;
+       }
+
+       if (timestamp == 0 && !converted) {
+               /* Not a snapshot path, no need for convert_sbuf() */
+               TALLOC_FREE(stripped);
+               TALLOC_FREE(full_fname);
+               return ent;
+       }
+
+       if (timestamp == 0) {
+               abspath = make_path_absolute(talloc_tos(),
+                                            priv,
+                                            full_fname->base_name);
+               TALLOC_FREE(full_fname);
+               if (abspath == NULL) {
+                       return NULL;
+               }
+       } else {
+               conv = shadow_copy2_convert(talloc_tos(),
+                                           handle,
+                                           stripped,
+                                           timestamp);
+               TALLOC_FREE(stripped);
+               if (conv == NULL) {
+                       return NULL;
+               }
+
+               abspath = make_path_absolute(talloc_tos(), priv, conv);
+               TALLOC_FREE(conv);
+               if (abspath == NULL) {
+                       return NULL;
+               }
+       }
+
+       convert_sbuf(handle, abspath, sbuf);
+
+       TALLOC_FREE(abspath);
+       return ent;
+}
+
 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
        .connect_fn = shadow_copy2_connect,
        .disk_free_fn = shadow_copy2_disk_free,
@@ -3362,6 +3452,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
        .pwrite_recv_fn = shadow_copy2_pwrite_recv,
        .connectpath_fn = shadow_copy2_connectpath,
        .parent_pathname_fn = shadow_copy2_parent_pathname,
+       .readdir_fn = shadow_copy2_readdir,
 };
 
 static_decl_vfs;