]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/extattr.c
Fix fd handling on Solaris
[netatalk.git] / libatalk / vfs / extattr.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba system utilities
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Jeremy Allison  1998-2005
6    Copyright (C) Timur Bakeyev        2005
7    Copyright (C) Bjoern Jacke    2006-2007
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23    sys_copyxattr modified from LGPL2.1 libattr copyright
24    Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
25    Copyright (C) 2001 Andreas Gruenbacher.
26       
27    Samba 3.0.28, modified for netatalk.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <errno.h>
38
39 #if HAVE_ATTR_XATTR_H
40 #include <attr/xattr.h>
41 #elif HAVE_SYS_XATTR_H
42 #include <sys/xattr.h>
43 #endif
44
45 #ifdef HAVE_SYS_EA_H
46 #include <sys/ea.h>
47 #endif
48
49 #ifdef HAVE_ATTROPEN
50
51 #include <dirent.h>
52 #endif
53
54 #ifdef HAVE_SYS_EXTATTR_H
55 #include <sys/extattr.h>
56 #endif
57
58 #include <atalk/adouble.h>
59 #include <atalk/util.h>
60 #include <atalk/logger.h>
61 #include <atalk/ea.h>
62 #include <atalk/compat.h>
63
64 /******** Solaris EA helper function prototypes ********/
65 #ifdef HAVE_ATTROPEN
66 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
67 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
68 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
69 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
70 static int solaris_unlinkat(int attrdirfd, const char *name);
71 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
72 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
73 #endif
74
75 /**************************************************************************
76  Wrappers for extented attribute calls. Based on the Linux package with
77  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
78 ****************************************************************************/
79 static char attr_name[256 +5] = "user.";
80
81 static const char *prefix(const char *uname)
82 {
83 #if defined(HAVE_ATTROPEN)
84         return uname;
85 #else
86         strlcpy(attr_name +5, uname, 256);
87         return attr_name;
88 #endif
89 }
90
91 int sys_getxattrfd(int fd, const char *uname, int oflag, ...)
92 {
93 #if defined HAVE_ATTROPEN
94     int eafd;
95     va_list args;
96     mode_t mode = 0;
97
98     if (oflag & O_CREAT) {
99         va_start(args, oflag);
100         mode = va_arg(args, mode_t);
101         va_end(args);
102     }
103
104     if (oflag & O_CREAT)
105         eafd = solaris_openat(fd, uname, oflag | O_XATTR, mode);
106     else
107         eafd = solaris_openat(fd, uname, oflag | O_XATTR, mode);
108
109     return eafd;
110 #else
111     errno = ENOSYS;
112     return -1;
113 #endif
114 }
115
116 ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
117 {
118         const char *name = prefix(uname);
119
120 #if defined(HAVE_GETXATTR)
121 #ifndef XATTR_ADD_OPT
122         return getxattr(path, name, value, size);
123 #else
124         int options = 0;
125         return getxattr(path, name, value, size, 0, options);
126 #endif
127 #elif defined(HAVE_GETEA)
128         return getea(path, name, value, size);
129 #elif defined(HAVE_EXTATTR_GET_FILE)
130         ssize_t retval;
131         /*
132          * The BSD implementation has a nasty habit of silently truncating
133          * the returned value to the size of the buffer, so we have to check
134          * that the buffer is large enough to fit the returned value.
135          */
136         if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
137         if (size == 0)
138             /* size == 0 means only return size */
139             return retval;
140                 if (retval > size) {
141                         errno = ERANGE;
142                         return -1;
143                 }
144                 if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
145                         return retval;
146         }
147
148         LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
149         return -1;
150 #elif defined(HAVE_ATTR_GET)
151         int retval, flags = 0;
152         int valuelength = (int)size;
153         char *attrname = strchr(name,'.') + 1;
154         
155         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
156
157         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
158
159         return retval ? retval : valuelength;
160 #elif defined(HAVE_ATTROPEN)
161         ssize_t ret = -1;
162         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
163         if (attrfd >= 0) {
164                 ret = solaris_read_xattr(attrfd, value, size);
165                 close(attrfd);
166         }
167         return ret;
168 #else
169         errno = ENOSYS;
170         return -1;
171 #endif
172 }
173
174 ssize_t sys_fgetxattr (int filedes, const char *uname, void *value, size_t size)
175 {
176     const char *name = prefix(uname);
177
178 #if defined(HAVE_FGETXATTR)
179 #ifndef XATTR_ADD_OPT
180     return fgetxattr(filedes, name, value, size);
181 #else
182     int options = 0;
183     return fgetxattr(filedes, name, value, size, 0, options);
184 #endif
185 #elif defined(HAVE_FGETEA)
186     return fgetea(filedes, name, value, size);
187 #elif defined(HAVE_EXTATTR_GET_FD)
188     char *s;
189     ssize_t retval;
190     int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
191         EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
192     const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
193
194     if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
195         if(retval > size) {
196             errno = ERANGE;
197             return -1;
198         }
199         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
200             return retval;
201     }
202
203     LOG(log_debug, logtype_default, "sys_fgetxattr: extattr_get_fd(): %s",
204         strerror(errno)));
205     return -1;
206 #elif defined(HAVE_ATTR_GETF)
207     int retval, flags = 0;
208     int valuelength = (int)size;
209     char *attrname = strchr(name,'.') + 1;
210
211     if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
212
213     retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
214
215     return retval ? retval : valuelength;
216 #elif defined(HAVE_ATTROPEN)
217     ssize_t ret = -1;
218     int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
219     if (attrfd >= 0) {
220         ret = solaris_read_xattr(attrfd, value, size);
221         close(attrfd);
222     }
223     return ret;
224 #else
225     errno = ENOSYS;
226     return -1;
227 #endif
228 }
229
230 ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
231 {
232         const char *name = prefix(uname);
233
234 #if defined(HAVE_LGETXATTR)
235         return lgetxattr(path, name, value, size);
236 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
237         int options = XATTR_NOFOLLOW;
238         return getxattr(path, name, value, size, 0, options);
239 #elif defined(HAVE_LGETEA)
240         return lgetea(path, name, value, size);
241 #elif defined(HAVE_EXTATTR_GET_LINK)
242         ssize_t retval;
243         if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
244                 if(retval > size) {
245                         errno = ERANGE;
246                         return -1;
247                 }
248                 if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
249                         return retval;
250         }
251         
252         LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
253         return -1;
254 #elif defined(HAVE_ATTR_GET)
255         int retval, flags = ATTR_DONTFOLLOW;
256         int valuelength = (int)size;
257         char *attrname = strchr(name,'.') + 1;
258         
259         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
260
261         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
262
263         return retval ? retval : valuelength;
264 #elif defined(HAVE_ATTROPEN)
265         ssize_t ret = -1;
266         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
267         if (attrfd >= 0) {
268                 ret = solaris_read_xattr(attrfd, value, size);
269                 close(attrfd);
270         }
271         return ret;
272 #else
273         errno = ENOSYS;
274         return -1;
275 #endif
276 }
277
278 #if defined(HAVE_EXTATTR_LIST_FILE)
279
280 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
281
282 static struct {
283         int space;
284         const char *name;
285         size_t len;
286
287 extattr[] = {
288         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
289         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
290 };
291
292 typedef union {
293         const char *path;
294         int filedes;
295 } extattr_arg;
296
297 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
298 {
299         ssize_t list_size;
300         int i, len;
301
302     switch(type) {
303 #if defined(HAVE_EXTATTR_LIST_FILE)
304     case 0:
305         list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
306         break;
307 #endif
308 #if defined(HAVE_EXTATTR_LIST_LINK)
309     case 1:
310         list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
311         break;
312 #endif
313 #if defined(HAVE_EXTATTR_LIST_FD)
314     case 2:
315         list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
316         break;
317 #endif
318     default:
319         errno = ENOSYS;
320         return -1;
321     }
322
323     /* Some error happend. Errno should be set by the previous call */
324     if(list_size < 0)
325         return -1;
326
327     /* No attributes */
328     if(list_size == 0)
329         return 0;
330
331     /* XXX: Call with an empty buffer may be used to calculate
332        necessary buffer size. Unfortunately, we can't say, how
333        many attributes were returned, so here is the potential
334        problem with the emulation.
335     */
336     if(list == NULL)
337         return list_size;
338
339     /* Buffer is too small to fit the results */
340     if(list_size > size) {
341         errno = ERANGE;
342         return -1;
343     }
344
345     /* Convert from pascal strings to C strings */
346     len = list[0];
347     memmove(list, list + 1, list_size);
348
349     for(i = len; i < list_size; ) {
350         LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
351
352         len = list[i];
353         list[i] = '\0';
354         i += len + 1;
355     }
356
357         return list_size;
358 }
359
360 #endif
361
362 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
363 static char attr_buffer[ATTR_MAX_VALUELEN];
364
365 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
366 {
367         int retval = 0, index;
368         attrlist_cursor_t *cursor = 0;
369         int total_size = 0;
370         attrlist_t * al = (attrlist_t *)attr_buffer;
371         attrlist_ent_t *ae;
372         size_t ent_size, left = size;
373         char *bp = list;
374
375         while (True) {
376             if (filedes)
377                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
378             else
379                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
380             if (retval) break;
381             for (index = 0; index < al->al_count; index++) {
382                 ae = ATTR_ENTRY(attr_buffer, index);
383                 ent_size = strlen(ae->a_name) + sizeof("user.");
384                 if (left >= ent_size) {
385                     strncpy(bp, "user.", sizeof("user."));
386                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
387                     bp += ent_size;
388                     left -= ent_size;
389                 } else if (size) {
390                     errno = ERANGE;
391                     retval = -1;
392                     break;
393                 }
394                 total_size += ent_size;
395             }
396             if (al->al_more == 0) break;
397         }
398         if (retval == 0) {
399             flags |= ATTR_ROOT;
400             cursor = 0;
401             while (True) {
402                 if (filedes)
403                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
404                 else
405                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
406                 if (retval) break;
407                 for (index = 0; index < al->al_count; index++) {
408                     ae = ATTR_ENTRY(attr_buffer, index);
409                     ent_size = strlen(ae->a_name) + sizeof("system.");
410                     if (left >= ent_size) {
411                         strncpy(bp, "system.", sizeof("system."));
412                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
413                         bp += ent_size;
414                         left -= ent_size;
415                     } else if (size) {
416                         errno = ERANGE;
417                         retval = -1;
418                         break;
419                     }
420                     total_size += ent_size;
421                 }
422                 if (al->al_more == 0) break;
423             }
424         }
425         return (ssize_t)(retval ? retval : total_size);
426 }
427
428 #endif
429
430 #if defined(HAVE_LISTXATTR)
431 static ssize_t remove_user(ssize_t ret, char *list, size_t size)
432 {
433         size_t len;
434         char *ptr;
435         char *ptr1;
436         ssize_t ptrsize;
437         
438         if (ret <= 0 || size == 0)
439                 return ret;
440         ptrsize = ret;
441         ptr = ptr1 = list;
442         while (ptrsize > 0) {
443                 len = strlen(ptr1) +1;
444                 ptrsize -= len;
445                 if (strncmp(ptr1, "user.",5)) {
446                         ptr1 += len;
447                         continue;
448                 }
449                 memmove(ptr, ptr1 +5, len -5);
450                 ptr += len -5;
451                 ptr1 += len;
452         }
453         return ptr -list;
454 }
455 #endif
456
457 ssize_t sys_listxattr (const char *path, char *list, size_t size)
458 {
459 #if defined(HAVE_LISTXATTR)
460         ssize_t ret;
461
462 #ifndef XATTR_ADD_OPT
463         ret = listxattr(path, list, size);
464 #else
465         int options = 0;
466         ret = listxattr(path, list, size, options);
467 #endif
468         return remove_user(ret, list, size);
469
470 #elif defined(HAVE_LISTEA)
471         return listea(path, list, size);
472 #elif defined(HAVE_EXTATTR_LIST_FILE)
473         extattr_arg arg;
474         arg.path = path;
475         return bsd_attr_list(0, arg, list, size);
476 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
477         return irix_attr_list(path, 0, list, size, 0);
478 #elif defined(HAVE_ATTROPEN)
479         ssize_t ret = -1;
480         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
481         if (attrdirfd >= 0) {
482                 ret = solaris_list_xattr(attrdirfd, list, size);
483                 close(attrdirfd);
484         }
485         return ret;
486 #else
487         errno = ENOSYS;
488         return -1;
489 #endif
490 }
491
492 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
493 {
494 #if defined(HAVE_LLISTXATTR)
495         ssize_t ret;
496
497         ret = llistxattr(path, list, size);
498         return remove_user(ret, list, size);
499 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
500         ssize_t ret;
501         int options = XATTR_NOFOLLOW;
502
503         ret = listxattr(path, list, size, options);
504         return remove_user(ret, list, size);
505
506 #elif defined(HAVE_LLISTEA)
507         return llistea(path, list, size);
508 #elif defined(HAVE_EXTATTR_LIST_LINK)
509         extattr_arg arg;
510         arg.path = path;
511         return bsd_attr_list(1, arg, list, size);
512 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
513         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
514 #elif defined(HAVE_ATTROPEN)
515         ssize_t ret = -1;
516         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
517         if (attrdirfd >= 0) {
518                 ret = solaris_list_xattr(attrdirfd, list, size);
519                 close(attrdirfd);
520         }
521         return ret;
522 #else
523         errno = ENOSYS;
524         return -1;
525 #endif
526 }
527
528 int sys_removexattr (const char *path, const char *uname)
529 {
530         const char *name = prefix(uname);
531 #if defined(HAVE_REMOVEXATTR)
532 #ifndef XATTR_ADD_OPT
533         return removexattr(path, name);
534 #else
535         int options = 0;
536         return removexattr(path, name, options);
537 #endif
538 #elif defined(HAVE_REMOVEEA)
539         return removeea(path, name);
540 #elif defined(HAVE_EXTATTR_DELETE_FILE)
541         return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
542 #elif defined(HAVE_ATTR_REMOVE)
543         int flags = 0;
544         char *attrname = strchr(name,'.') + 1;
545         
546         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
547
548         return attr_remove(path, attrname, flags);
549 #elif defined(HAVE_ATTROPEN)
550         int ret = -1;
551         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
552         if (attrdirfd >= 0) {
553                 ret = solaris_unlinkat(attrdirfd, name);
554                 close(attrdirfd);
555         }
556         return ret;
557 #else
558         errno = ENOSYS;
559         return -1;
560 #endif
561 }
562
563 int sys_lremovexattr (const char *path, const char *uname)
564 {
565         const char *name = prefix(uname);
566 #if defined(HAVE_LREMOVEXATTR)
567         return lremovexattr(path, name);
568 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
569         int options = XATTR_NOFOLLOW;
570         return removexattr(path, name, options);
571 #elif defined(HAVE_LREMOVEEA)
572         return lremoveea(path, name);
573 #elif defined(HAVE_EXTATTR_DELETE_LINK)
574         return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
575 #elif defined(HAVE_ATTR_REMOVE)
576         int flags = ATTR_DONTFOLLOW;
577         char *attrname = strchr(name,'.') + 1;
578         
579         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
580
581         return attr_remove(path, attrname, flags);
582 #elif defined(HAVE_ATTROPEN)
583         int ret = -1;
584         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
585         if (attrdirfd >= 0) {
586                 ret = solaris_unlinkat(attrdirfd, name);
587                 close(attrdirfd);
588         }
589         return ret;
590 #else
591         errno = ENOSYS;
592         return -1;
593 #endif
594 }
595
596 int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
597 {
598         const char *name = prefix(uname);
599 #if defined(HAVE_SETXATTR)
600 #ifndef XATTR_ADD_OPT
601         return setxattr(path, name, value, size, flags);
602 #else
603         int options = 0;
604         return setxattr(path, name, value, size, 0, options);
605 #endif
606 #elif defined(HAVE_SETEA)
607         return setea(path, name, value, size, flags);
608 #elif defined(HAVE_EXTATTR_SET_FILE)
609         int retval = 0;
610         if (flags) {
611                 /* Check attribute existence */
612                 retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
613                 if (retval < 0) {
614                         /* REPLACE attribute, that doesn't exist */
615                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
616                                 errno = ENOATTR;
617                                 return -1;
618                         }
619                         /* Ignore other errors */
620                 }
621                 else {
622                         /* CREATE attribute, that already exists */
623                         if (flags & XATTR_CREATE) {
624                                 errno = EEXIST;
625                                 return -1;
626                         }
627                 }
628         }
629         retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
630         return (retval < 0) ? -1 : 0;
631 #elif defined(HAVE_ATTR_SET)
632         int myflags = 0;
633         char *attrname = strchr(name,'.') + 1;
634         
635         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
636         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
637         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
638
639         return attr_set(path, attrname, (const char *)value, size, myflags);
640 #elif defined(HAVE_ATTROPEN)
641         int ret = -1;
642         int myflags = O_RDWR;
643         int attrfd;
644         if (flags & XATTR_CREATE) myflags |= O_EXCL;
645         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
646         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
647         if (attrfd >= 0) {
648                 ret = solaris_write_xattr(attrfd, value, size);
649                 close(attrfd);
650         }
651         return ret;
652 #else
653         errno = ENOSYS;
654         return -1;
655 #endif
656 }
657
658 int sys_fsetxattr (int filedes, const char *uname, const void *value, size_t size, int flags)
659 {
660     const char *name = prefix(uname);
661
662 #if defined(HAVE_FSETXATTR)
663 #ifndef XATTR_ADD_OPT
664     return fsetxattr(filedes, name, value, size, flags);
665 #else
666     int options = 0;
667     return fsetxattr(filedes, name, value, size, 0, options);
668 #endif
669 #elif defined(HAVE_FSETEA)
670     return fsetea(filedes, name, value, size, flags);
671 #elif defined(HAVE_EXTATTR_SET_FD)
672     char *s;
673     int retval = 0;
674     int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
675         EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
676     const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
677     if (flags) {
678         /* Check attribute existence */
679         retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
680         if (retval < 0) {
681             /* REPLACE attribute, that doesn't exist */
682             if (flags & XATTR_REPLACE && errno == ENOATTR) {
683                 errno = ENOATTR;
684                 return -1;
685             }
686             /* Ignore other errors */
687         }
688         else {
689             log_error, logtype_default            /* CREATE attribute, that already exists */
690             if (flags & XATTR_CREATE) {
691                 errno = EEXIST;
692                 return -1;
693             }
694         }
695     }
696     retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
697     return (retval < 0) ? -1 : 0;
698 #elif defined(HAVE_ATTR_SETF)
699     int myflags = 0;
700     char *attrname = strchr(name,'.') + 1;
701
702     if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
703     if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
704     if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
705
706     return attr_setf(filedes, attrname, (const char *)value, size, myflags);
707 #elif defined(HAVE_ATTROPEN)
708     int ret = -1;
709     int myflags = O_RDWR | O_XATTR;
710     int attrfd;
711     if (flags & XATTR_CREATE) myflags |= O_EXCL;
712     if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
713     attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
714     if (attrfd >= 0) {
715         ret = solaris_write_xattr(attrfd, value, size);
716         close(attrfd);
717     }
718     return ret;
719 #else
720     errno = ENOSYS;
721     return -1;
722 #endif
723 }
724
725 int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
726 {
727         const char *name = prefix(uname);
728 #if defined(HAVE_LSETXATTR)
729         return lsetxattr(path, name, value, size, flags);
730 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
731         int options = XATTR_NOFOLLOW;
732         return setxattr(path, name, value, size, 0, options);
733 #elif defined(LSETEA)
734         return lsetea(path, name, value, size, flags);
735 #elif defined(HAVE_EXTATTR_SET_LINK)
736         int retval = 0;
737         if (flags) {
738                 /* Check attribute existence */
739                 retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
740                 if (retval < 0) {
741                         /* REPLACE attribute, that doesn't exist */
742                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
743                                 errno = ENOATTR;
744                                 return -1;
745                         }
746                         /* Ignore other errors */
747                 }
748                 else {
749                         /* CREATE attribute, that already exists */
750                         if (flags & XATTR_CREATE) {
751                                 errno = EEXIST;
752                                 return -1;
753                         }
754                 }
755         }
756
757         retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
758         return (retval < 0) ? -1 : 0;
759 #elif defined(HAVE_ATTR_SET)
760         int myflags = ATTR_DONTFOLLOW;
761         char *attrname = strchr(name,'.') + 1;
762         
763         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
764         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
765         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
766
767         return attr_set(path, attrname, (const char *)value, size, myflags);
768 #elif defined(HAVE_ATTROPEN)
769         int ret = -1;
770         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
771         int attrfd;
772         if (flags & XATTR_CREATE) myflags |= O_EXCL;
773         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
774         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
775         if (attrfd >= 0) {
776                 ret = solaris_write_xattr(attrfd, value, size);
777                 close(attrfd);
778         }
779         return ret;
780 #else
781         errno = ENOSYS;
782         return -1;
783 #endif
784 }
785
786 /**************************************************************************
787  helper functions for Solaris' EA support
788 ****************************************************************************/
789 #ifdef HAVE_ATTROPEN
790 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
791 {
792         struct stat sbuf;
793
794         if (fstat(attrfd, &sbuf) == -1) {
795                 return -1;
796         }
797
798         /* This is to return the current size of the named extended attribute */
799         if (size == 0) {
800                 return sbuf.st_size;
801         }
802
803         /* check size and read xattr */
804         if (sbuf.st_size > size) {
805                 return -1;
806         }
807
808         return read(attrfd, value, sbuf.st_size);
809 }
810
811 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
812 {
813         ssize_t len = 0;
814         DIR *dirp;
815         struct dirent *de;
816         int newfd = dup(attrdirfd);
817         /* CAUTION: The originating file descriptor should not be
818                     used again following the call to fdopendir().
819                     For that reason we dup() the file descriptor
820                     here to make things more clear. */
821         dirp = fdopendir(newfd);
822
823         while ((de = readdir(dirp))) {
824                 size_t listlen;
825                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
826                      !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw")) 
827                 {
828                         /* we don't want "." and ".." here: */
829                         LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
830                         continue;
831                 }
832
833                 listlen = strlen(de->d_name);
834                 if (size == 0) {
835                         /* return the current size of the list of extended attribute names*/
836                         len += listlen + 1;
837                 } else {
838                         /* check size and copy entry + nul into list. */
839                         if ((len + listlen + 1) > size) {
840                                 errno = ERANGE;
841                                 len = -1;
842                                 break;
843                         } else {
844                                 strcpy(list + len, de->d_name);
845                                 len += listlen;
846                                 list[len] = '\0';
847                                 ++len;
848                         }
849                 }
850         }
851
852         if (closedir(dirp) == -1) {
853                 LOG(log_error, logtype_default, "closedir dirp: %s",strerror(errno));
854                 return -1;
855         }
856         return len;
857 }
858
859 static int solaris_unlinkat(int attrdirfd, const char *name)
860 {
861         if (unlinkat(attrdirfd, name, 0) == -1) {
862                 return -1;
863         }
864         return 0;
865 }
866
867 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
868 {
869         int filedes = attropen(path, attrpath, oflag, mode);
870         if (filedes == -1) {
871         if (errno != ENOENT)
872             LOG(log_error, logtype_default, "attropen(\"%s\", ea:'%s'): %s",
873                 path, attrpath, strerror(errno));
874         errno = ENOATTR;
875         }
876         return filedes;
877 }
878
879 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
880 {
881         int filedes = openat(fildes, path, oflag, mode);
882         if (filedes == -1) {
883         if (errno != ENOENT)
884             LOG(log_error, logtype_default, "openat(\"%s\"): %s",
885                 path, strerror(errno));
886         errno = ENOATTR;
887         }
888         return filedes;
889 }
890
891 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
892 {
893         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
894                 return 0;
895         } else {
896                 LOG(log_error, logtype_default, "solaris_write_xattr: %s",
897             strerror(errno));
898                 return -1;
899         }
900 }
901
902 #endif /*HAVE_ATTROPEN*/
903