mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
s3:smbd: let mkdir_internal() try VFS_RENAME_HOW_NO_REPLACE first
With renameat2(RENAME_NOREPLACE) being available it's even better, as we don't even have the short window where the incomplete directory is visible to others. The flow will be this: tmp_name = ".::TMPNAME:D:$PID:client_name" mkdirat(tmp_name, mode=client_mode); prepare_acls(tmp_name); renameat2(tmp_name, client_name, NOREPLACE); if (EEXIST) { unlinkat(tmp_name); return EEXIST; } if (EINVAL) { /* fallback if NOREPLACE is not supported */ mkdirat(client_name, mode=0); if (EEXIST) { unlinkat(tmp_name); return EEXIST; } renameat(tmp_name, client_name); } BUG: https://bugzilla.samba.org/show_bug.cgi?id=15693 Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
parent
fe8b4617dd
commit
1bacaae526
@ -4681,7 +4681,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
|
||||
struct server_id_buf idbuf;
|
||||
char *idstr = server_id_str_buf_unique_ex(id, '%', &idbuf);
|
||||
struct vfs_open_how how = { .flags = O_RDONLY|O_DIRECTORY, };
|
||||
struct vfs_rename_how rhow = { .flags = 0, };
|
||||
struct vfs_rename_how rhow = { .flags = VFS_RENAME_HOW_NO_REPLACE, };
|
||||
int ret;
|
||||
|
||||
if (!CAN_WRITE(conn) || (access_mask & ~(conn->share_access))) {
|
||||
@ -4896,7 +4896,27 @@ mkdir_first:
|
||||
*/
|
||||
tmp_atname->st = smb_dname->st;
|
||||
|
||||
{
|
||||
/*
|
||||
* We first try VFS_RENAME_HOW_NO_REPLACE,
|
||||
* if it's implemented in the kernel,
|
||||
* we'll always get EEXIST if the target
|
||||
* exist, as it's handled at the linux vfs
|
||||
* layer. But if it doesn't exist we
|
||||
* can still get EINVAL if the actual
|
||||
* filesystem doesn't support RENAME_NOREPLACE.
|
||||
*
|
||||
* If the kernel doesn't support rename2()
|
||||
* we get EINVAL instead of ENOSYS (this
|
||||
* is mapped in the libreplace replacement
|
||||
* (as well as the glibc replacement).
|
||||
*/
|
||||
ret = SMB_VFS_RENAMEAT(conn,
|
||||
parent_dir_fname->fsp,
|
||||
tmp_atname,
|
||||
parent_dir_fname->fsp,
|
||||
smb_fname_atname,
|
||||
&rhow);
|
||||
if (ret == -1 && errno == EINVAL) {
|
||||
/*
|
||||
* This is the strategie we use without having
|
||||
* renameat2(RENAME_NOREPLACE):
|
||||
@ -4916,6 +4936,8 @@ mkdir_first:
|
||||
* the incomplete directory, which has a mode of 0.
|
||||
*/
|
||||
|
||||
rhow.flags &= ~VFS_RENAME_HOW_NO_REPLACE;
|
||||
|
||||
DBG_DEBUG("MKDIRAT/RENAMEAT '%s' -> '%s'\n",
|
||||
tmp_dname, orig_dname);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user