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