]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3: VFS: vfs_xattr_tdb. Implement unlinkat().
authorJeremy Allison <jra@samba.org>
Fri, 13 Sep 2019 17:12:38 +0000 (10:12 -0700)
committerRalph Boehme <slow@samba.org>
Thu, 26 Sep 2019 17:20:45 +0000 (17:20 +0000)
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 <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/modules/vfs_xattr_tdb.c

index 58adac5b9b5a26381fd102873349ac8ca3b0437a..588a2740d685c282df0793df90112568c6b22cdd 100644 (file)
@@ -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,
 };