]> arthur.barton.de Git - netatalk.git/commitdiff
afpd: Solaris locking problem, bug #559
authorRalph Boehme <rb@sernet.de>
Fri, 15 Aug 2014 08:46:48 +0000 (10:46 +0200)
committerRalph Boehme <rb@sernet.de>
Wed, 17 Sep 2014 22:21:30 +0000 (00:21 +0200)
Authored-by: Peter Baranski
Reviewed-by: Ralph Boehme <rb@sernet.de>
NEWS
etc/afpd/directory.c
etc/afpd/extattrs.c
include/atalk/ea.h
include/atalk/vfs.h
libatalk/vfs/ea_ad.c
libatalk/vfs/ea_sys.c
libatalk/vfs/extattr.c

diff --git a/NEWS b/NEWS
index 1aca7b8fa0a25d1ac3c29b284ef12d5ce0d82b7a..d0e32b563842692cf08e387dedcc38cc85ff195e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ Changes in 3.1.7
 * FIX: netatalk: fix a crash on Solaris when registering with mDNS
 * FIX: netatalk: SIGHUP would kill the process instead of being resent
        to the other Netatalk processes, bug #579
+* FIX: afpd: Solaris locking problem, bug #559
 
 Changes in 3.1.6
 ================
index e83e5e76ca45cd29e99faf27e3744914251c4412..470cfb0184b95cb8e93ffe31a018ba1e7aef9837 100644 (file)
@@ -1083,7 +1083,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath)
     int         size = 0;
     int         toUTF8 = 0;
 
-    LOG(log_maxdebug, logtype_afpd, "came('%s'): {start}", cfrombstr(dir->d_fullpath));
+    LOG(log_maxdebug, logtype_afpd, "cname('%s'): {start}", cfrombstr(dir->d_fullpath));
 
     data = *cpath;
     afp_errno = AFPERR_NOOBJ;
@@ -1286,7 +1286,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath)
         ret.d_dir = dir;
     }
 
-    LOG(log_debug, logtype_afpd, "came('%s') {end: curdir:'%s', path:'%s'}",
+    LOG(log_debug, logtype_afpd, "cname('%s') {end: curdir:'%s', path:'%s'}",
         cfrombstr(dir->d_fullpath),
         cfrombstr(curdir->d_fullpath),
         ret.u_name);
index f6b1cf66178a585c5475aa9f781c8e21ea939612..18f5c787ffb6b9c1ef987e78dbe1769ce1b507ed 100644 (file)
@@ -73,7 +73,7 @@ static void hexdump(void *m, size_t l) {
 */
 int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    int                 ret, oflag = 0, adflags = 0;
+    int                 ret, oflag = 0, adflags = 0, fd = -1;
     uint16_t            vid, bitmap, uint16;
     uint32_t            did, maxreply, tmpattr;
     struct vol          *vol;
@@ -81,6 +81,7 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
     struct path         *s_path;
     struct stat         *st;
     struct adouble      ad, *adp = NULL;
+    struct ofork       *opened = NULL;
     char                *uname, *FinderInfo;
     char                emptyFinderInfo[32] = { 0 };
 
@@ -147,11 +148,21 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
           via FPGetExtAttr !
         */
 
-        if (S_ISDIR(st->st_mode))
-            adflags = ADFLAGS_DIR;
-
         adp = &ad;
         ad_init(adp, vol);
+
+        if (path_isadir(s_path)) {
+           LOG(log_debug, logtype_afpd, "afp_listextattr(%s): is a dir", uname);
+            adflags = ADFLAGS_DIR;
+       } else {
+           LOG(log_debug, logtype_afpd, "afp_listextattr(%s): is a file", uname);
+           opened = of_findname(vol, s_path);
+           if (opened) {
+               adp = opened->of_ad;
+               fd = ad_meta_fileno(adp);
+           }
+       }
+
         if (ad_metadata(uname, adflags, adp) != 0 ) {
             switch (errno) {
             case ENOENT:
@@ -183,8 +194,8 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
                 attrbuflen += strlen(ea_resourcefork) + 1;
             }
         }
-        
-        ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
+       
+        ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag, fd);
 
         switch (ret) {
         case AFPERR_BADTYPE:
@@ -248,13 +259,15 @@ static char attrmname[256];
 
 int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    int                 ret, oflag = 0;
+    int                 ret, oflag = 0, fd = -1;
     uint16_t            vid, bitmap, attrnamelen;
     uint32_t            did, maxreply;
     char                attruname[256];
     struct vol          *vol;
     struct dir          *dir;
     struct path         *s_path;
+    struct adouble     ad, *adp = NULL;
+    struct ofork       *opened = NULL;
 
 
     *rbuflen = 0;
@@ -315,22 +328,33 @@ int afp_getextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
     rbuf += sizeof(bitmap);
     *rbuflen += sizeof(bitmap);
 
+    if (path_isadir(s_path)) {
+       LOG(log_debug, logtype_afpd, "afp_getextattr(%s): is a dir", s_path->u_name);
+    } else {
+       LOG(log_debug, logtype_afpd, "afp_getextattr(%s): is a file", s_path->u_name);
+       opened = of_findname(vol, s_path);
+       if (opened) {
+           adp = opened->of_ad;
+           fd = ad_meta_fileno(adp);
+       }
+    }
+
     /*
       Switch on maxreply:
       if its 0 we must return the size of the requested attribute,
       if its non 0 we must return the attribute.
     */
     if (maxreply == 0)
-        ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
+        ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, fd);
     else
-        ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
+        ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply, fd);
 
     return ret;
 }
 
 int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    int                 oflag = 0, ret;
+    int                 oflag = 0, ret, fd = -1;
     uint16_t            vid, bitmap, attrnamelen;
     uint32_t            did, attrsize;
     char                attruname[256];
@@ -338,6 +362,8 @@ int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
     struct vol          *vol;
     struct dir          *dir;
     struct path         *s_path;
+    struct adouble     ad, *adp = NULL;
+    struct ofork       *opened = NULL;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -377,6 +403,18 @@ int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
         return AFPERR_NOOBJ;
     }
 
+    if (path_isadir(s_path)) {
+       LOG(log_debug, logtype_afpd, "afp_setextattr(%s): is a dir", s_path->u_name);
+    } else {
+       LOG(log_debug, logtype_afpd, "afp_setextattr(%s): is a file", s_path->u_name);
+       opened = of_findname(vol, s_path);
+       if (opened) {
+           adp = opened->of_ad;
+           fd = ad_meta_fileno(adp);
+       }
+    }
+
+
     if ((unsigned long)ibuf & 1)
         ibuf++;
 
@@ -403,20 +441,22 @@ int afp_setextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
 
     LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, to_stringz(attrmname, attrnamelen), attrsize);
 
-    ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
+    ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag, fd);
 
     return ret;
 }
 
 int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    int                 oflag = 0, ret;
+    int                 oflag = 0, ret, fd = -1;
     uint16_t            vid, bitmap, attrnamelen;
     uint32_t            did;
     char                attruname[256];
     struct vol          *vol;
     struct dir          *dir;
     struct path         *s_path;
+    struct adouble     ad, *adp = NULL;
+    struct ofork       *opened = NULL;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -444,10 +484,21 @@ int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
 
     /* get name */
     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
-        LOG(log_debug, logtype_afpd, "afp_setextattr: cname error: %s", strerror(errno));
+        LOG(log_debug, logtype_afpd, "afp_remextattr: cname error: %s", strerror(errno));
         return AFPERR_NOOBJ;
     }
 
+    if (path_isadir(s_path)) {
+       LOG(log_debug, logtype_afpd, "afp_remextattr(%s): is a dir", s_path->u_name);
+    } else {
+       LOG(log_debug, logtype_afpd, "afp_remextattr(%s): is a file", s_path->u_name);
+       opened = of_findname(vol, s_path);
+       if (opened) {
+           adp = opened->of_ad;
+           fd = ad_meta_fileno(adp);
+       }
+    }
+
     if ((unsigned long)ibuf & 1)
         ibuf++;
 
@@ -464,7 +515,7 @@ int afp_remextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _
 
     LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, to_stringz(ibuf, attrnamelen));
 
-    ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);
+    ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag, fd);
 
     return ret;
 }
index fbbafafabef4169cc746e72dc3afa2aad2905a91..7cd4234a78006fbfc5513f229a8b9471a2ef1421 100644 (file)
@@ -90,10 +90,12 @@ ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t s
 ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
 ssize_t sys_listxattr (const char *path, char *list, size_t size);
 ssize_t sys_llistxattr (const char *path, char *list, size_t size);
-ssize_t sys_flistxattr (int filedes, char *list, size_t size);
+/* ssize_t sys_flistxattr (int filedes, char *list, size_t size); */
+ssize_t sys_flistxattr (int filedes, const char *path, char *list, size_t size);
 int sys_removexattr (const char *path, const char *name);
 int sys_lremovexattr (const char *path, const char *name);
-int sys_fremovexattr (int filedes, const char *name);
+/* int sys_fremovexattr (int filedes, const char *name); */
+int sys_fremovexattr (int filedes, const char *path, const char *name);
 int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
 int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
 int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
index 6021c150987db56b02c701a5bac934ef54c90aa4..580c22b256268dfe9072a7a5fa8174d34817b874 100644 (file)
 #define VFS_FUNC_ARGS_REMOVE_ACL const struct vol *vol, const char *path, int dir
 #define VFS_FUNC_VARS_REMOVE_ACL vol, path, dir
 
-#define VFS_FUNC_ARGS_EA_GETSIZE const struct vol * restrict vol, char * restrict rbuf, size_t * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname
-#define VFS_FUNC_VARS_EA_GETSIZE vol, rbuf, rbuflen, uname, oflag, attruname
+#define VFS_FUNC_ARGS_EA_GETSIZE const struct vol * restrict vol, char * restrict rbuf, size_t * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname, int fd
+#define VFS_FUNC_VARS_EA_GETSIZE vol, rbuf, rbuflen, uname, oflag, attruname, fd
 
-#define VFS_FUNC_ARGS_EA_GETCONTENT const struct vol * restrict vol, char * restrict rbuf, size_t * restrict rbuflen,  const char * restrict uname, int oflag, const char * restrict attruname, int maxreply
-#define VFS_FUNC_VARS_EA_GETCONTENT vol, rbuf, rbuflen, uname, oflag, attruname, maxreply
+#define VFS_FUNC_ARGS_EA_GETCONTENT const struct vol * restrict vol, char * restrict rbuf, size_t * restrict rbuflen,  const char * restrict uname, int oflag, const char * restrict attruname, int maxreply, int fd
+#define VFS_FUNC_VARS_EA_GETCONTENT vol, rbuf, rbuflen, uname, oflag, attruname, maxreply, fd
 
-#define VFS_FUNC_ARGS_EA_LIST const struct vol * restrict vol, char * restrict attrnamebuf, size_t * restrict buflen, const char * restrict uname, int oflag
-#define VFS_FUNC_VARS_EA_LIST vol, attrnamebuf, buflen, uname, oflag
+#define VFS_FUNC_ARGS_EA_LIST const struct vol * restrict vol, char * restrict attrnamebuf, size_t * restrict buflen, const char * restrict uname, int oflag, int fd
+#define VFS_FUNC_VARS_EA_LIST vol, attrnamebuf, buflen, uname, oflag, fd
 
-#define VFS_FUNC_ARGS_EA_SET const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, const char * restrict ibuf, size_t attrsize, int oflag
-#define VFS_FUNC_VARS_EA_SET vol, uname, attruname, ibuf, attrsize, oflag
+#define VFS_FUNC_ARGS_EA_SET const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, const char * restrict ibuf, size_t attrsize, int oflag, int fd
+#define VFS_FUNC_VARS_EA_SET vol, uname, attruname, ibuf, attrsize, oflag, fd
 
-#define VFS_FUNC_ARGS_EA_REMOVE const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, int oflag
-#define VFS_FUNC_VARS_EA_REMOVE vol, uname, attruname, oflag
+#define VFS_FUNC_ARGS_EA_REMOVE const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, int oflag, int fd
+#define VFS_FUNC_VARS_EA_REMOVE vol, uname, attruname, oflag, fd
 
 /*
  * Forward declaration. We need it because of the circular inclusion of
index 19c23e0672c8ac78ba2287b448f19bffe0b6baf9..5b99a5c321b2052866307aa161615188ca61b59d 100644 (file)
@@ -1065,7 +1065,7 @@ int get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
  */
 int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
 {
-    int ret = AFPERR_MISC, fd = -1;
+    int ret = AFPERR_MISC;
     unsigned int count = 0;
     uint32_t uint32;
     size_t toread;
index 0b899903ee433a0a70f50a9ffb0cab0cd96df406..7ed87294825a4f7f2085b739f9d81c98c5d11314 100644 (file)
@@ -68,12 +68,20 @@ int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
 
     LOG(log_debug7, logtype_afpd, "sys_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
 
-    if ((oflag & O_NOFOLLOW) ) {
-        ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
-    }
-    else {
-        ret = sys_getxattr(uname, attruname,  rbuf +4, 0);
+    /* PBaranski fix */
+    if (fd != -1) {
+       LOG(log_debug, logtype_afpd, "sys_get_easize(%s): file is already opened", uname);
+       ret = sys_fgetxattr(fd, attruname, rbuf +4, 0);
+    } else {
+       if ((oflag & O_NOFOLLOW) ) {
+           ret = sys_lgetxattr(uname, attruname, rbuf +4, 0);
+       }
+       else {
+           ret = sys_getxattr(uname, attruname,  rbuf +4, 0);
+       }
     }
+    /* PBaranski fix */
+
     
     if (ret == -1) {
         memset(rbuf, 0, 4);
@@ -125,7 +133,7 @@ int sys_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
  *    oflag        (r) link and create flag
  *    attruname    (r) name of attribute
  *    maxreply     (r) maximum EA size as of current specs/real-life
- *
+ *    fd           (r) file descriptor
  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
  *
  * Effects:
@@ -146,13 +154,20 @@ int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
 
     LOG(log_debug7, logtype_afpd, "sys_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
 
-    if ((oflag & O_NOFOLLOW) ) {
-        ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
-    }
-    else {
-        ret = sys_getxattr(uname, attruname,  rbuf +4, maxreply);
+    /* PBaranski fix */
+    if (fd != -1) {
+       LOG(log_debug, logtype_afpd, "sys_get_eacontent(%s): file is already opened", uname);
+       ret = sys_fgetxattr(fd, attruname, rbuf +4, maxreply);
+    } else {
+       if ((oflag & O_NOFOLLOW) ) {
+           ret = sys_lgetxattr(uname, attruname, rbuf +4, maxreply);
+       }
+       else {
+           ret = sys_getxattr(uname, attruname,  rbuf +4, maxreply);
+       }
     }
-    
+    /* PBaranski fix */
+
     if (ret == -1) {
         memset(rbuf, 0, 4);
         *rbuflen += 4;
@@ -210,17 +225,25 @@ int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
     int     ret, len, nlen;
     char    *buf;
     char    *ptr;
-        
+    struct adouble ad, *adp;
+
     buf = malloc(ATTRNAMEBUFSIZ);
     if (!buf)
         return AFPERR_MISC;
 
-    if ((oflag & O_NOFOLLOW)) {
-        ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
-    }
-    else {
-        ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
+    /* PBaranski fix */
+    if ( fd != -1) {
+       LOG(log_debug, logtype_afpd, "sys_list_eas(%s): file is already opened", uname);
+       ret = sys_flistxattr(fd, uname, buf, ATTRNAMEBUFSIZ);
+    } else {
+       if ((oflag & O_NOFOLLOW)) {
+           ret = sys_llistxattr(uname, buf, ATTRNAMEBUFSIZ);
+       }
+       else {
+           ret = sys_listxattr(uname, buf, ATTRNAMEBUFSIZ);
+       }
     }
+    /* PBaranski fix */
 
     if (ret == -1) switch(errno) {
         case OPEN_NOFOLLOW_ERRNO:
@@ -299,12 +322,19 @@ int sys_set_ea(VFS_FUNC_ARGS_EA_SET)
     else if ((oflag & O_TRUNC) ) 
         attr_flag |= XATTR_REPLACE;
     
-    if ((oflag & O_NOFOLLOW) ) {
-        ret = sys_lsetxattr(uname, attruname,  ibuf, attrsize,attr_flag);
-    }
-    else {
-        ret = sys_setxattr(uname, attruname,  ibuf, attrsize, attr_flag);
+    /* PBaranski fix */
+    if ( fd != -1) {
+       LOG(log_debug, logtype_afpd, "sys_set_ea(%s): file is already opened", uname);
+       ret = sys_fsetxattr(fd, attruname,  ibuf, attrsize, attr_flag);
+    } else {
+       if ((oflag & O_NOFOLLOW) ) {
+           ret = sys_lsetxattr(uname, attruname,  ibuf, attrsize,attr_flag);
+       }
+       else {
+           ret = sys_setxattr(uname, attruname,  ibuf, attrsize, attr_flag);
+       }
     }
+    /* PBaranski fix */
 
     if (ret == -1) {
         switch(errno) {
@@ -347,6 +377,7 @@ int sys_set_ea(VFS_FUNC_ARGS_EA_SET)
  *    uname        (r) filename
  *    attruname    (r) EA name
  *    oflag        (r) link and create flag
+ *    fd           (r) file descriptor
  *
  * Returns: AFP code: AFP_OK on success or appropiate AFP error code
  *
@@ -358,12 +389,19 @@ int sys_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
 {
     int ret;
 
-    if ((oflag & O_NOFOLLOW) ) {
-        ret = sys_lremovexattr(uname, attruname);
-    }
-    else {
-        ret = sys_removexattr(uname, attruname);
+    /* PBaranski fix */
+    if ( fd != -1) {
+       LOG(log_debug, logtype_afpd, "sys_remove_ea(%s): file is already opened", uname);
+       ret = sys_fremovexattr(fd, uname, attruname);
+    } else {
+       if ((oflag & O_NOFOLLOW) ) {
+           ret = sys_lremovexattr(uname, attruname);
+       }
+       else {
+           ret = sys_removexattr(uname, attruname);
+       }
     }
+    /* PBaranski fix */
 
     if (ret == -1) {
         switch(errno) {
index 4a338bae5a3869f2417bc2cdbe6f2f03290bf9bc..9e45bb8bea0b27c71a17d218a48481fd20bba753 100644 (file)
@@ -70,6 +70,7 @@ static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
 static int solaris_unlinkat(int attrdirfd, const char *name);
 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
+static int solaris_attropenat(int filedes, const char *path, const char *attrpath, int oflag, mode_t mode);
 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
 #endif
 
@@ -494,6 +495,41 @@ ssize_t sys_listxattr (const char *path, char *list, size_t size)
 #endif
 }
 
+ssize_t sys_flistxattr (int filedes, const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LISTXATTR)
+       ssize_t ret;
+
+#ifndef XATTR_ADD_OPT
+       ret = listxattr(path, list, size);
+#else
+       int options = 0;
+       ret = listxattr(path, list, size, options);
+#endif
+       return remove_user(ret, list, size);
+
+#elif defined(HAVE_LISTEA)
+       return listea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_FILE)
+       extattr_arg arg;
+       arg.path = path;
+       return bsd_attr_list(0, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+       return irix_attr_list(path, 0, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+       ssize_t ret = -1;
+       int attrdirfd = solaris_attropenat(filedes, path, ".", O_RDONLY, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_list_xattr(attrdirfd, list, size);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
 {
 #if defined(HAVE_LLISTXATTR)
@@ -565,6 +601,41 @@ int sys_removexattr (const char *path, const char *uname)
 #endif
 }
 
+int sys_fremovexattr (int filedes, const char *path, const char *uname)
+{
+       const char *name = prefix(uname);
+#if defined(HAVE_REMOVEXATTR)
+#ifndef XATTR_ADD_OPT
+       return removexattr(path, name);
+#else
+       int options = 0;
+       return removexattr(path, name, options);
+#endif
+#elif defined(HAVE_REMOVEEA)
+       return removeea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_FILE)
+       return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
+#elif defined(HAVE_ATTR_REMOVE)
+       int flags = 0;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+       return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+       int ret = -1;
+       int attrdirfd = solaris_attropenat(filedes, path, ".", O_RDONLY, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_unlinkat(attrdirfd, name);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
 int sys_lremovexattr (const char *path, const char *uname)
 {
        const char *name = prefix(uname);
@@ -907,6 +978,32 @@ EC_CLEANUP:
     return eafd;
 }
 
+static int solaris_attropenat(int filedes, const char *path, const char *attrpath, int oflag, mode_t mode)
+{
+    EC_INIT;
+       int eafd = -1;
+
+       if ((eafd = openat(filedes, attrpath, oflag | O_XATTR, mode)) == -1) {
+        switch (errno) {
+        case ENOENT:
+        case EEXIST:
+            EC_FAIL;
+        default:
+            LOG(log_debug, logtype_default, "openat(\"%s\"): %s", fullpathname(path), strerror(errno));
+            EC_FAIL;
+        }
+       }
+
+EC_CLEANUP:
+    if (ret != 0) {
+        if (eafd != -1)
+            close(eafd);
+        eafd = -1;
+    }
+    return eafd;
+}
+
+
 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
 {
        int filedes;