From: Jeremy Allison Date: Fri, 13 Sep 2019 17:12:38 +0000 (-0700) Subject: s3: VFS: vfs_xattr_tdb. Implement unlinkat(). X-Git-Tag: talloc-2.3.1~648 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95197108becd184dbff61dc9929606f62460e98d;p=thirdparty%2Fsamba.git s3: VFS: vfs_xattr_tdb. Implement unlinkat(). Note this isn't identical to unlink() as this must cope with (flags & AT_REMOVEDIR), which is identical to rmdir(). It calls either unlink or rmdir depending on the flags parameter. Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme --- diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c index 58adac5b9b5..588a2740d68 100644 --- a/source3/modules/vfs_xattr_tdb.c +++ b/source3/modules/vfs_xattr_tdb.c @@ -649,6 +649,75 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle, return ret; } +/* + * On unlink we need to delete the tdb record + */ +static int xattr_tdb_unlinkat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + int flags) +{ + struct smb_filename *smb_fname_tmp = NULL; + struct file_id id; + struct db_context *db; + int ret = -1; + bool remove_record = false; + TALLOC_CTX *frame = talloc_stackframe(); + + SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, + if (!xattr_tdb_init(-1, frame, &db)) + { + TALLOC_FREE(frame); return -1; + }); + + smb_fname_tmp = cp_smb_filename(frame, smb_fname); + if (smb_fname_tmp == NULL) { + TALLOC_FREE(frame); + errno = ENOMEM; + return -1; + } + + if (smb_fname_tmp->flags & SMB_FILENAME_POSIX_PATH) { + ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp); + } else { + ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp); + } + if (ret == -1) { + goto out; + } + + if (flags & AT_REMOVEDIR) { + /* Always remove record when removing a directory succeeds. */ + remove_record = true; + } else { + if (smb_fname_tmp->st.st_ex_nlink == 1) { + /* Only remove record on last link to file. */ + remove_record = true; + } + } + + ret = SMB_VFS_NEXT_UNLINKAT(handle, + dirfsp, + smb_fname_tmp, + flags); + + if (ret == -1) { + goto out; + } + + if (!remove_record) { + goto out; + } + + id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, &smb_fname_tmp->st); + + xattr_tdb_remove_all_attrs(db, &id); + + out: + TALLOC_FREE(frame); + return ret; +} + /* * On rmdir we need to delete the tdb record */ @@ -747,6 +816,7 @@ static struct vfs_fn_pointers vfs_xattr_tdb_fns = { .open_fn = xattr_tdb_open, .mkdirat_fn = xattr_tdb_mkdirat, .unlink_fn = xattr_tdb_unlink, + .unlinkat_fn = xattr_tdb_unlinkat, .rmdir_fn = xattr_tdb_rmdir, .connect_fn = xattr_tdb_connect, };