From 76b379ad71f4b129fade5611356b103b7ca6d39a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 15 Aug 2014 10:46:48 +0200 Subject: [PATCH] afpd: Solaris locking problem, bug #559 Authored-by: Peter Baranski Reviewed-by: Ralph Boehme --- NEWS | 1 + etc/afpd/directory.c | 4 +- etc/afpd/extattrs.c | 79 ++++++++++++++++++++++++++++------ include/atalk/ea.h | 6 ++- include/atalk/vfs.h | 20 ++++----- libatalk/vfs/ea_ad.c | 2 +- libatalk/vfs/ea_sys.c | 94 ++++++++++++++++++++++++++++------------ libatalk/vfs/extattr.c | 97 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 246 insertions(+), 57 deletions(-) diff --git a/NEWS b/NEWS index 1aca7b8f..d0e32b56 100644 --- 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 ================ diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index e83e5e76..470cfb01 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -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); diff --git a/etc/afpd/extattrs.c b/etc/afpd/extattrs.c index f6b1cf66..18f5c787 100644 --- a/etc/afpd/extattrs.c +++ b/etc/afpd/extattrs.c @@ -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; } diff --git a/include/atalk/ea.h b/include/atalk/ea.h index fbbafafa..7cd4234a 100644 --- a/include/atalk/ea.h +++ b/include/atalk/ea.h @@ -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); diff --git a/include/atalk/vfs.h b/include/atalk/vfs.h index 6021c150..580c22b2 100644 --- a/include/atalk/vfs.h +++ b/include/atalk/vfs.h @@ -74,20 +74,20 @@ #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 diff --git a/libatalk/vfs/ea_ad.c b/libatalk/vfs/ea_ad.c index 19c23e06..5b99a5c3 100644 --- a/libatalk/vfs/ea_ad.c +++ b/libatalk/vfs/ea_ad.c @@ -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; diff --git a/libatalk/vfs/ea_sys.c b/libatalk/vfs/ea_sys.c index 0b899903..7ed87294 100644 --- a/libatalk/vfs/ea_sys.c +++ b/libatalk/vfs/ea_sys.c @@ -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) { diff --git a/libatalk/vfs/extattr.c b/libatalk/vfs/extattr.c index 4a338bae..9e45bb8b 100644 --- a/libatalk/vfs/extattr.c +++ b/libatalk/vfs/extattr.c @@ -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; -- 2.39.2