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