vfs_shadow_copy2: implement readdir()
authorRalph Boehme <slow@samba.org>
Thu, 24 Mar 2022 15:25:22 +0000 (16:25 +0100)
committerJule Anger <janger@samba.org>
Mon, 11 Apr 2022 07:49:13 +0000 (07:49 +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

(cherry picked from commit 9fa67ba8eeb6249d4b91b894e80eb1985c845314)

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 769f8c7da8738bbad86fa421bd8df1f16aab0164..05b12d4924cf4e6e97d792d1217b20c18242fb00 100644 (file)
@@ -3234,6 +3234,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,
@@ -3264,6 +3354,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;