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