diff mbox

[V9fs-developer,08/13] 9p: add a fd argument to xattr helpers

Message ID 146702052303.5764.4062835425206070448.stgit@bahia.lan (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Greg Kurz June 27, 2016, 9:42 a.m. UTC
This patch adds the plumbing to be able to use fgetxattr(), fsetxattr(),
flistxattr() and fremovexattr().

It does not change any functionality.

Signed-off-by: Greg Kurz <groug@kaod.org>
---
 hw/9pfs/9p-local.c      |   44 +++++++++++++++++---------
 hw/9pfs/9p-posix-acl.c  |   80 ++++++++++++++++++++++++++++++++---------------
 hw/9pfs/9p-xattr-user.c |   41 ++++++++++++++++--------
 hw/9pfs/9p-xattr.c      |   35 +++++++++++++--------
 hw/9pfs/9p-xattr.h      |   67 ++++++++++++++++++++++++---------------
 5 files changed, 172 insertions(+), 95 deletions(-)



------------------------------------------------------------------------------
Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San
Francisco, CA to explore cutting-edge tech and listen to tech luminaries
present their vision of the future. This family event has something for
everyone, including kids. Get more information and register today.
http://sdm.link/attshape
diff mbox

Patch

diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 46ac7aab7c47..873bd4b9d997 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -269,34 +269,48 @@  err_out:
     return ret;
 }
 
-static int local_set_xattr(const char *path, FsCred *credp)
+static int local_do_setxattr(int fd, const char *path,
+                             const char *name, void *value, size_t size)
+{
+    if (path) {
+        return setxattr(path, name, value, size, 0);
+    } else {
+        return fsetxattr(fd, name, value, size, 0);
+    }
+}
+
+static int local_set_xattr(int fd, const char *path, FsCred *credp)
 {
     int err;
 
     if (credp->fc_uid != -1) {
         uint32_t tmp_uid = cpu_to_le32(credp->fc_uid);
-        err = setxattr(path, "user.virtfs.uid", &tmp_uid, sizeof(uid_t), 0);
+        err = local_do_setxattr(fd, path, "user.virtfs.uid", &tmp_uid,
+                                sizeof(uid_t));
         if (err) {
             return err;
         }
     }
     if (credp->fc_gid != -1) {
         uint32_t tmp_gid = cpu_to_le32(credp->fc_gid);
-        err = setxattr(path, "user.virtfs.gid", &tmp_gid, sizeof(gid_t), 0);
+        err = local_do_setxattr(fd, path, "user.virtfs.gid", &tmp_gid,
+                                sizeof(gid_t));
         if (err) {
             return err;
         }
     }
     if (credp->fc_mode != -1) {
         uint32_t tmp_mode = cpu_to_le32(credp->fc_mode);
-        err = setxattr(path, "user.virtfs.mode", &tmp_mode, sizeof(mode_t), 0);
+        err = local_do_setxattr(fd, path, "user.virtfs.mode", &tmp_mode,
+                                sizeof(mode_t));
         if (err) {
             return err;
         }
     }
     if (credp->fc_rdev != -1) {
         uint64_t tmp_rdev = cpu_to_le64(credp->fc_rdev);
-        err = setxattr(path, "user.virtfs.rdev", &tmp_rdev, sizeof(dev_t), 0);
+        err = local_do_setxattr(fd, path, "user.virtfs.rdev", &tmp_rdev,
+                                sizeof(dev_t));
         if (err) {
             return err;
         }
@@ -489,7 +503,7 @@  static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
 
     if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         buffer = rpath(fs_ctx, path);
-        ret = local_set_xattr(buffer, credp);
+        ret = local_set_xattr(-1, buffer, credp);
         g_free(buffer);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         return local_set_mapped_file_attr(fs_ctx, path, credp);
@@ -522,7 +536,7 @@  static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
         if (err == -1) {
             goto out;
         }
-        err = local_set_xattr(buffer, credp);
+        err = local_set_xattr(-1, buffer, credp);
         if (err == -1) {
             serrno = errno;
             goto err_end;
@@ -584,7 +598,7 @@  static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
             goto out;
         }
         credp->fc_mode = credp->fc_mode|S_IFDIR;
-        err = local_set_xattr(buffer, credp);
+        err = local_set_xattr(-1, buffer, credp);
         if (err == -1) {
             serrno = errno;
             goto err_end;
@@ -674,7 +688,7 @@  static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
         }
         credp->fc_mode = credp->fc_mode|S_IFREG;
         /* Set cleint credentials in xattr */
-        err = local_set_xattr(buffer, credp);
+        err = local_set_xattr(-1, buffer, credp);
         if (err == -1) {
             serrno = errno;
             goto err_end;
@@ -760,7 +774,7 @@  static int local_symlink(FsContext *fs_ctx, const char *oldpath,
         close(fd);
         /* Set cleint credentials in symlink's xattr */
         credp->fc_mode = credp->fc_mode|S_IFLNK;
-        err = local_set_xattr(buffer, credp);
+        err = local_set_xattr(-1, buffer, credp);
         if (err == -1) {
             serrno = errno;
             goto err_end;
@@ -932,7 +946,7 @@  static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
         g_free(buffer);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
         buffer = rpath(fs_ctx, path);
-        ret = local_set_xattr(buffer, credp);
+        ret = local_set_xattr(-1, buffer, credp);
         g_free(buffer);
     } else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
         return local_set_mapped_file_attr(fs_ctx, path, credp);
@@ -1046,7 +1060,7 @@  static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
 {
     char *path = fs_path->data;
 
-    return v9fs_get_xattr(ctx, path, name, value, size);
+    return v9fs_get_xattr(ctx, -1, path, name, value, size);
 }
 
 static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
@@ -1054,7 +1068,7 @@  static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path,
 {
     char *path = fs_path->data;
 
-    return v9fs_list_xattr(ctx, path, value, size);
+    return v9fs_list_xattr(ctx, -1, path, value, size);
 }
 
 static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
@@ -1062,7 +1076,7 @@  static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
 {
     char *path = fs_path->data;
 
-    return v9fs_set_xattr(ctx, path, name, value, size, flags);
+    return v9fs_set_xattr(ctx, -1, path, name, value, size, flags);
 }
 
 static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
@@ -1070,7 +1084,7 @@  static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
 {
     char *path = fs_path->data;
 
-    return v9fs_remove_xattr(ctx, path, name);
+    return v9fs_remove_xattr(ctx, -1, path, name);
 }
 
 static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
diff --git a/hw/9pfs/9p-posix-acl.c b/hw/9pfs/9p-posix-acl.c
index ec003181cd33..287e8cf68396 100644
--- a/hw/9pfs/9p-posix-acl.c
+++ b/hw/9pfs/9p-posix-acl.c
@@ -22,19 +22,23 @@ 
 #define ACL_ACCESS "system.posix_acl_access"
 #define ACL_DEFAULT "system.posix_acl_default"
 
-static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
+static ssize_t mp_pacl_getxattr(FsContext *ctx, int fd, const char *path,
                                 const char *name, void *value, size_t size)
 {
     char *buffer;
     ssize_t ret;
 
-    buffer = rpath(ctx, path);
-    ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
+        g_free(buffer);
+    } else {
+        ret = fgetxattr(fd, MAP_ACL_ACCESS, value, size);
+    }
     return ret;
 }
 
-static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+static ssize_t mp_pacl_listxattr(FsContext *ctx, int fd, const char *path,
                                  char *name, void *value, size_t osize)
 {
     ssize_t len = sizeof(ACL_ACCESS);
@@ -53,26 +57,36 @@  static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
     return 0;
 }
 
-static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
+static int mp_pacl_setxattr(FsContext *ctx, int fd, const char *path,
+                            const char *name, void *value, size_t size,
+                            int flags)
 {
     char *buffer;
     int ret;
 
-    buffer = rpath(ctx, path);
-    ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
+        g_free(buffer);
+    } else {
+        ret = fsetxattr(fd, MAP_ACL_ACCESS, value, size, flags);
+    }
     return ret;
 }
 
-static int mp_pacl_removexattr(FsContext *ctx,
+static int mp_pacl_removexattr(FsContext *ctx, int fd,
                                const char *path, const char *name)
 {
     int ret;
     char *buffer;
 
-    buffer = rpath(ctx, path);
-    ret  = lremovexattr(buffer, MAP_ACL_ACCESS);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret  = lremovexattr(buffer, MAP_ACL_ACCESS);
+    } else {
+        buffer = NULL;
+        ret  = fremovexattr(fd, MAP_ACL_ACCESS);
+    }
     if (ret == -1 && errno == ENODATA) {
         /*
          * We don't get ENODATA error when trying to remove a
@@ -86,19 +100,23 @@  static int mp_pacl_removexattr(FsContext *ctx,
     return ret;
 }
 
-static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
+static ssize_t mp_dacl_getxattr(FsContext *ctx, int fd, const char *path,
                                 const char *name, void *value, size_t size)
 {
     char *buffer;
     ssize_t ret;
 
-    buffer = rpath(ctx, path);
-    ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
+        g_free(buffer);
+    } else {
+        ret = fgetxattr(fd, MAP_ACL_DEFAULT, value, size);
+    }
     return ret;
 }
 
-static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+static ssize_t mp_dacl_listxattr(FsContext *ctx, int fd, const char *path,
                                  char *name, void *value, size_t osize)
 {
     ssize_t len = sizeof(ACL_DEFAULT);
@@ -117,26 +135,36 @@  static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
     return 0;
 }
 
-static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
+static int mp_dacl_setxattr(FsContext *ctx, int fd, const char *path,
+                            const char *name, void *value, size_t size,
+                            int flags)
 {
     char *buffer;
     int ret;
 
-    buffer = rpath(ctx, path);
-    ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
+        g_free(buffer);
+    } else {
+        ret = fsetxattr(fd, MAP_ACL_DEFAULT, value, size, flags);
+    }
     return ret;
 }
 
-static int mp_dacl_removexattr(FsContext *ctx,
+static int mp_dacl_removexattr(FsContext *ctx, int fd,
                                const char *path, const char *name)
 {
     int ret;
     char *buffer;
 
-    buffer = rpath(ctx, path);
-    ret  = lremovexattr(buffer, MAP_ACL_DEFAULT);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
+    } else {
+        buffer = NULL;
+        ret = fremovexattr(fd, MAP_ACL_DEFAULT);
+    }
     if (ret == -1 && errno == ENODATA) {
         /*
          * We don't get ENODATA error when trying to remove a
diff --git a/hw/9pfs/9p-xattr-user.c b/hw/9pfs/9p-xattr-user.c
index f87530c8b526..aa93ab926da9 100644
--- a/hw/9pfs/9p-xattr-user.c
+++ b/hw/9pfs/9p-xattr-user.c
@@ -17,7 +17,7 @@ 
 #include "9p-xattr.h"
 
 
-static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+static ssize_t mp_user_getxattr(FsContext *ctx, int fd, const char *path,
                                 const char *name, void *value, size_t size)
 {
     char *buffer;
@@ -31,13 +31,17 @@  static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
         errno = ENOATTR;
         return -1;
     }
-    buffer = rpath(ctx, path);
-    ret = lgetxattr(buffer, name, value, size);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lgetxattr(buffer, name, value, size);
+        g_free(buffer);
+    } else {
+        ret = fgetxattr(fd, name, value, size);
+    }
     return ret;
 }
 
-static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+static ssize_t mp_user_listxattr(FsContext *ctx, int fd, const char *path,
                                  char *name, void *value, size_t size)
 {
     int name_size = strlen(name) + 1;
@@ -70,8 +74,9 @@  static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
     return name_size;
 }
 
-static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
-                            void *value, size_t size, int flags)
+static int mp_user_setxattr(FsContext *ctx, int fd, const char *path,
+                            const char *name, void *value, size_t size,
+                            int flags)
 {
     char *buffer;
     int ret;
@@ -84,13 +89,17 @@  static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
         errno = EACCES;
         return -1;
     }
-    buffer = rpath(ctx, path);
-    ret = lsetxattr(buffer, name, value, size, flags);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lsetxattr(buffer, name, value, size, flags);
+        g_free(buffer);
+    } else {
+        ret = fsetxattr(fd, name, value, size, flags);
+    }
     return ret;
 }
 
-static int mp_user_removexattr(FsContext *ctx,
+static int mp_user_removexattr(FsContext *ctx, int fd,
                                const char *path, const char *name)
 {
     char *buffer;
@@ -104,9 +113,13 @@  static int mp_user_removexattr(FsContext *ctx,
         errno = EACCES;
         return -1;
     }
-    buffer = rpath(ctx, path);
-    ret = lremovexattr(buffer, name);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lremovexattr(buffer, name);
+        g_free(buffer);
+    } else {
+        ret = fremovexattr(fd, name);
+    }
     return ret;
 }
 
diff --git a/hw/9pfs/9p-xattr.c b/hw/9pfs/9p-xattr.c
index 5d8595ed932a..cd8c634b6364 100644
--- a/hw/9pfs/9p-xattr.c
+++ b/hw/9pfs/9p-xattr.c
@@ -29,18 +29,18 @@  static XattrOperations *get_xattr_operations(XattrOperations **h,
     return NULL;
 }
 
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+ssize_t v9fs_get_xattr(FsContext *ctx, int fd, const char *path,
                        const char *name, void *value, size_t size)
 {
     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
     if (xops) {
-        return xops->getxattr(ctx, path, name, value, size);
+        return xops->getxattr(ctx, fd, path, name, value, size);
     }
     errno = EOPNOTSUPP;
     return -1;
 }
 
-ssize_t pt_listxattr(FsContext *ctx, const char *path,
+ssize_t pt_listxattr(FsContext *ctx, int fd, const char *path,
                      char *name, void *value, size_t size)
 {
     int name_size = strlen(name) + 1;
@@ -63,7 +63,7 @@  ssize_t pt_listxattr(FsContext *ctx, const char *path,
  * Get the list and pass to each layer to find out whether
  * to send the data or not
  */
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+ssize_t v9fs_list_xattr(FsContext *ctx, int fd, const char *path,
                         void *value, size_t vsize)
 {
     ssize_t size = 0;
@@ -74,8 +74,13 @@  ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
     ssize_t xattr_len, parsed_len = 0, attr_len;
 
     /* Get the actual len */
-    buffer = rpath(ctx, path);
-    xattr_len = llistxattr(buffer, value, 0);
+    if (path) {
+        buffer = rpath(ctx, path);
+        xattr_len = llistxattr(buffer, value, 0);
+    } else {
+        buffer = NULL;
+        xattr_len = flistxattr(fd, value, 0);
+    }
     if (xattr_len <= 0) {
         g_free(buffer);
         return xattr_len;
@@ -83,7 +88,11 @@  ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
 
     /* Now fetch the xattr and find the actual size */
     orig_value = g_malloc(xattr_len);
-    xattr_len = llistxattr(buffer, orig_value, xattr_len);
+    if (path) {
+        xattr_len = llistxattr(buffer, orig_value, xattr_len);
+    } else {
+        xattr_len = flistxattr(fd, orig_value, xattr_len);
+    }
     g_free(buffer);
 
     /* store the orig pointer */
@@ -95,9 +104,9 @@  ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
         }
 
         if (!value) {
-            size += xops->listxattr(ctx, path, orig_value, value, vsize);
+            size += xops->listxattr(ctx, fd, path, orig_value, value, vsize);
         } else {
-            size = xops->listxattr(ctx, path, orig_value, value, vsize);
+            size = xops->listxattr(ctx, fd, path, orig_value, value, vsize);
             if (size < 0) {
                 goto err_out;
             }
@@ -119,24 +128,24 @@  err_out:
     return size;
 }
 
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+int v9fs_set_xattr(FsContext *ctx, int fd, const char *path, const char *name,
                    void *value, size_t size, int flags)
 {
     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
     if (xops) {
-        return xops->setxattr(ctx, path, name, value, size, flags);
+        return xops->setxattr(ctx, fd, path, name, value, size, flags);
     }
     errno = EOPNOTSUPP;
     return -1;
 
 }
 
-int v9fs_remove_xattr(FsContext *ctx,
+int v9fs_remove_xattr(FsContext *ctx, int fd,
                       const char *path, const char *name)
 {
     XattrOperations *xops = get_xattr_operations(ctx->xops, name);
     if (xops) {
-        return xops->removexattr(ctx, path, name);
+        return xops->removexattr(ctx, fd, path, name);
     }
     errno = EOPNOTSUPP;
     return -1;
diff --git a/hw/9pfs/9p-xattr.h b/hw/9pfs/9p-xattr.h
index 4d39a20262ad..dacb423c0968 100644
--- a/hw/9pfs/9p-xattr.h
+++ b/hw/9pfs/9p-xattr.h
@@ -18,13 +18,13 @@ 
 typedef struct xattr_operations
 {
     const char *name;
-    ssize_t (*getxattr)(FsContext *ctx, const char *path,
+    ssize_t (*getxattr)(FsContext *ctx, int fd, const char *path,
                         const char *name, void *value, size_t size);
-    ssize_t (*listxattr)(FsContext *ctx, const char *path,
+    ssize_t (*listxattr)(FsContext *ctx, int fd, const char *path,
                          char *name, void *value, size_t size);
-    int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+    int (*setxattr)(FsContext *ctx, int fd, const char *path, const char *name,
                     void *value, size_t size, int flags);
-    int (*removexattr)(FsContext *ctx,
+    int (*removexattr)(FsContext *ctx, int fd,
                        const char *path, const char *name);
 } XattrOperations;
 
@@ -41,54 +41,67 @@  extern XattrOperations *mapped_xattr_ops[];
 extern XattrOperations *passthrough_xattr_ops[];
 extern XattrOperations *none_xattr_ops[];
 
-ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name,
-                       void *value, size_t size);
-ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
+ssize_t v9fs_get_xattr(FsContext *ctx, int fd, const char *path,
+                       const char *name, void *value, size_t size);
+ssize_t v9fs_list_xattr(FsContext *ctx, int fd, const char *path, void *value,
                         size_t vsize);
-int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+int v9fs_set_xattr(FsContext *ctx, int fd, const char *path, const char *name,
                           void *value, size_t size, int flags);
-int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
-ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
-                     size_t size);
+int v9fs_remove_xattr(FsContext *ctx, int fd, const char *path,
+                      const char *name);
+ssize_t pt_listxattr(FsContext *ctx, int fd, const char *path, char *name,
+                     void *value, size_t size);
 
-static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
+static inline ssize_t pt_getxattr(FsContext *ctx, int fd, const char *path,
                                   const char *name, void *value, size_t size)
 {
     char *buffer;
     ssize_t ret;
 
-    buffer = rpath(ctx, path);
-    ret = lgetxattr(buffer, name, value, size);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lgetxattr(buffer, name, value, size);
+        g_free(buffer);
+    } else {
+        ret = fgetxattr(fd, name, value, size);
+    }
     return ret;
 }
 
-static inline int pt_setxattr(FsContext *ctx, const char *path,
+static inline int pt_setxattr(FsContext *ctx, int fd, const char *path,
                               const char *name, void *value,
                               size_t size, int flags)
 {
     char *buffer;
     int ret;
 
-    buffer = rpath(ctx, path);
-    ret = lsetxattr(buffer, name, value, size, flags);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lsetxattr(buffer, name, value, size, flags);
+        g_free(buffer);
+    } else {
+        ret = fsetxattr(fd, name, value, size, flags);
+    }
     return ret;
 }
 
-static inline int pt_removexattr(FsContext *ctx,
+static inline int pt_removexattr(FsContext *ctx, int fd,
                                  const char *path, const char *name)
 {
     char *buffer;
     int ret;
 
-    buffer = rpath(ctx, path);
-    ret = lremovexattr(path, name);
-    g_free(buffer);
+    if (path) {
+        buffer = rpath(ctx, path);
+        ret = lremovexattr(path, name);
+        g_free(buffer);
+    } else {
+        ret = fremovexattr(fd, name);
+    }
     return ret;
 }
 
-static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+static inline ssize_t notsup_getxattr(FsContext *ctx, int fd, const char *path,
                                       const char *name, void *value,
                                       size_t size)
 {
@@ -96,7 +109,7 @@  static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
     return -1;
 }
 
-static inline int notsup_setxattr(FsContext *ctx, const char *path,
+static inline int notsup_setxattr(FsContext *ctx, int fd, const char *path,
                                   const char *name, void *value,
                                   size_t size, int flags)
 {
@@ -104,13 +117,13 @@  static inline int notsup_setxattr(FsContext *ctx, const char *path,
     return -1;
 }
 
-static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+static inline ssize_t notsup_listxattr(FsContext *ctx, int fd, const char *path,
                                        char *name, void *value, size_t size)
 {
     return 0;
 }
 
-static inline int notsup_removexattr(FsContext *ctx,
+static inline int notsup_removexattr(FsContext *ctx, int fd,
                                      const char *path, const char *name)
 {
     errno = ENOTSUP;