1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-11 16:58:40 +03:00

vfs_shadow_copy2: ensure we call convert_sbuf() in shadow_copy2_*stat() on already converted paths with absolute path

shadow_copy2_strip_snapshot() will happily return without modifying the passed
timestamp=0 if the path is already converted and refers to an object in a
snapshot, eg (first debug line from extra debugging patch [1]):

[10 2021/07/02 08:19:28.811424 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:1303 shadow_copy2_fstat]
  shadow_copy2_fstat: fsp [test.txt {@GMT-2000.01.02-03.04.05}]
[10 2021/07/02 08:19:28.811449 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:607 _shadow_copy2_strip_snapshot_internal]
  _shadow_copy2_strip_snapshot_internal: [from shadow_copy2_fstat()] Path 'test.txt {@GMT-2000.01.02-03.04.05}'
[10 2021/07/02 08:19:28.811474 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:619 _shadow_copy2_strip_snapshot_internal]
  _shadow_copy2_strip_snapshot_internal: abs path '/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05/test.txt'
[10 2021/07/02 08:19:28.811496 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:1924 shadow_copy2_snapshot_to_gmt]
  shadow_copy2_snapshot_to_gmt: match @GMT-%Y.%m.%d-%H.%M.%S: @GMT-2000.01.02-03.04.05
[10 2021/07/02 08:19:28.811536 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:566 check_for_converted_path]
  check_for_converted_path: path |/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05/test.txt| is already converted. connect path = |/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05|

As check_for_converted_path() detects an "already converted path",
_shadow_copy2_strip_snapshot_internal() just returns without modifying the value
of the timestamp.

By using shadow_copy2_strip_snapshot_converted() instead of
shadow_copy2_strip_snapshot() we can check if the path is in fact referring to a
VSS object by checking the "converted" bool.

An alternative way would have been directly checking fsp->fsp_name->twrp != 0,
but that would be a new semantic in the module, I'll leave this excersize for
the future when we clean up the usage of shadow_copy2_strip_snapshot() in the
whole module.

This change also switches to using the absolute paths in both place where
convert_sbuf() is called.

[1]
@@ -1309,8 +1348,16 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
                saved_errno = errno;
        }

+       DBG_DEBUG("fsp [%s]\n", fsp_str_dbg(fsp));

RN: vfs_shadow_copy2 fixinodes not correctly updating inode numbers
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit c7d6745858f2efdd24ed6fd353ec5ece898033fa)

Autobuild-User(v4-14-test): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(v4-14-test): Tue Aug 17 10:07:42 UTC 2021 on sn-devel-184
This commit is contained in:
Ralph Boehme 2021-07-03 15:46:11 +02:00 committed by Karolin Seeger
parent 8222ff1110
commit 3228383d8a
2 changed files with 138 additions and 43 deletions

View File

@ -1 +0,0 @@
^samba3.blackbox.shadow_copy_torture.fix inodes with hardlink\(fileserver\)

View File

@ -1168,19 +1168,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_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)) {
&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 +1220,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_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)) {
&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 +1297,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,
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);
&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;
@ -1301,20 +1390,27 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
}
ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
if (ret != 0) {
goto out;
}
abspath = make_path_absolute(talloc_tos(),
priv,
fsp->fsp_name->base_name);
if (abspath == NULL) {
ret = -1;
goto out;
}
convert_sbuf(handle, abspath, sbuf);
TALLOC_FREE(abspath);
out:
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) {
convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
}
if (saved_errno != 0) {
errno = saved_errno;
}
return ret;
}