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