]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/sys_ea.c
log messages
[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    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    $Id: sys_ea.c,v 1.6 2009-12-04 10:26:10 franklahm Exp $
29    
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <errno.h>
40
41 #if HAVE_ATTR_XATTR_H
42 #include <attr/xattr.h>
43 #elif HAVE_SYS_XATTR_H
44 #include <sys/xattr.h>
45 #endif
46
47 #ifdef HAVE_SYS_EA_H
48 #include <sys/ea.h>
49 #endif
50
51 #ifdef HAVE_ATTROPEN
52
53 #include <dirent.h>
54 #endif
55
56 #ifdef HAVE_SYS_EXTATTR_H
57 #include <sys/extattr.h>
58 #endif
59
60 #include <atalk/adouble.h>
61 #include <atalk/util.h>
62 #include <atalk/logger.h>
63 #include <atalk/ea.h>
64
65 #ifndef ENOATTR
66 #define ENOATTR ENODATA
67 #endif
68
69 /******** Solaris EA helper function prototypes ********/
70 #ifdef HAVE_ATTROPEN
71 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
72 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
73 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
74 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
75 static int solaris_unlinkat(int attrdirfd, const char *name);
76 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
77 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
78 #endif
79
80 /**************************************************************************
81  Wrappers for extented attribute calls. Based on the Linux package with
82  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
83 ****************************************************************************/
84 static char attr_name[256 +5] = "user.";
85
86 static const char *prefix(const char *uname)
87 {
88 #if defined(HAVE_ATTROPEN)
89         return uname;
90 #else
91         strlcpy(attr_name +5, uname, 256);
92         return attr_name;
93 #endif
94 }
95
96 ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
97 {
98         const char *name = prefix(uname);
99
100 #if defined(HAVE_GETXATTR)
101 #ifndef XATTR_ADD_OPT
102         return getxattr(path, name, value, size);
103 #else
104         int options = 0;
105         return getxattr(path, name, value, size, 0, options);
106 #endif
107 #elif defined(HAVE_GETEA)
108         return getea(path, name, value, size);
109 #elif defined(HAVE_EXTATTR_GET_FILE)
110         ssize_t retval;
111         /*
112          * The BSD implementation has a nasty habit of silently truncating
113          * the returned value to the size of the buffer, so we have to check
114          * that the buffer is large enough to fit the returned value.
115          */
116         if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
117         if (size == 0)
118             /* size == 0 means only return size */
119             return retval;
120                 if (retval > size) {
121                         errno = ERANGE;
122                         return -1;
123                 }
124                 if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
125                         return retval;
126         }
127
128         LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
129         return -1;
130 #elif defined(HAVE_ATTR_GET)
131         int retval, flags = 0;
132         int valuelength = (int)size;
133         char *attrname = strchr(name,'.') + 1;
134         
135         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
136
137         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
138
139         return retval ? retval : valuelength;
140 #elif defined(HAVE_ATTROPEN)
141         ssize_t ret = -1;
142         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
143         if (attrfd >= 0) {
144                 ret = solaris_read_xattr(attrfd, value, size);
145                 close(attrfd);
146         }
147         return ret;
148 #else
149         errno = ENOSYS;
150         return -1;
151 #endif
152 }
153
154 ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
155 {
156         const char *name = prefix(uname);
157
158 #if defined(HAVE_LGETXATTR)
159         return lgetxattr(path, name, value, size);
160 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
161         int options = XATTR_NOFOLLOW;
162         return getxattr(path, name, value, size, 0, options);
163 #elif defined(HAVE_LGETEA)
164         return lgetea(path, name, value, size);
165 #elif defined(HAVE_EXTATTR_GET_LINK)
166         ssize_t retval;
167         if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
168                 if(retval > size) {
169                         errno = ERANGE;
170                         return -1;
171                 }
172                 if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
173                         return retval;
174         }
175         
176         LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
177         return -1;
178 #elif defined(HAVE_ATTR_GET)
179         int retval, flags = ATTR_DONTFOLLOW;
180         int valuelength = (int)size;
181         char *attrname = strchr(name,'.') + 1;
182         
183         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
184
185         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
186
187         return retval ? retval : valuelength;
188 #elif defined(HAVE_ATTROPEN)
189         ssize_t ret = -1;
190         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
191         if (attrfd >= 0) {
192                 ret = solaris_read_xattr(attrfd, value, size);
193                 close(attrfd);
194         }
195         return ret;
196 #else
197         errno = ENOSYS;
198         return -1;
199 #endif
200 }
201
202 #if defined(HAVE_EXTATTR_LIST_FILE)
203
204 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
205
206 static struct {
207         int space;
208         const char *name;
209         size_t len;
210
211 extattr[] = {
212         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
213         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
214 };
215
216 typedef union {
217         const char *path;
218         int filedes;
219 } extattr_arg;
220
221 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
222 {
223         ssize_t list_size;
224         int i, len;
225
226     switch(type) {
227 #if defined(HAVE_EXTATTR_LIST_FILE)
228     case 0:
229         list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
230         break;
231 #endif
232 #if defined(HAVE_EXTATTR_LIST_LINK)
233     case 1:
234         list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
235         break;
236 #endif
237 #if defined(HAVE_EXTATTR_LIST_FD)
238     case 2:
239         list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
240         break;
241 #endif
242     default:
243         errno = ENOSYS;
244         return -1;
245     }
246
247     /* Some error happend. Errno should be set by the previous call */
248     if(list_size < 0)
249         return -1;
250
251     /* No attributes */
252     if(list_size == 0)
253         return 0;
254
255     /* XXX: Call with an empty buffer may be used to calculate
256        necessary buffer size. Unfortunately, we can't say, how
257        many attributes were returned, so here is the potential
258        problem with the emulation.
259     */
260     if(list == NULL)
261         return list_size;
262
263     /* Buffer is too small to fit the results */
264     if(list_size > size) {
265         errno = ERANGE;
266         return -1;
267     }
268
269     /* Convert from pascal strings to C strings */
270     len = list[0];
271     memmove(list, list + 1, list_size);
272
273     for(i = len; i < list_size; ) {
274         LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
275
276         len = list[i];
277         list[i] = '\0';
278         i += len + 1;
279     }
280
281         return list_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         return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
466 #elif defined(HAVE_ATTR_REMOVE)
467         int flags = 0;
468         char *attrname = strchr(name,'.') + 1;
469         
470         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
471
472         return attr_remove(path, attrname, flags);
473 #elif defined(HAVE_ATTROPEN)
474         int ret = -1;
475         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
476         if (attrdirfd >= 0) {
477                 ret = solaris_unlinkat(attrdirfd, name);
478                 close(attrdirfd);
479         }
480         return ret;
481 #else
482         errno = ENOSYS;
483         return -1;
484 #endif
485 }
486
487 int sys_lremovexattr (const char *path, const char *uname)
488 {
489         const char *name = prefix(uname);
490 #if defined(HAVE_LREMOVEXATTR)
491         return lremovexattr(path, name);
492 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
493         int options = XATTR_NOFOLLOW;
494         return removexattr(path, name, options);
495 #elif defined(HAVE_LREMOVEEA)
496         return lremoveea(path, name);
497 #elif defined(HAVE_EXTATTR_DELETE_LINK)
498         return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
499 #elif defined(HAVE_ATTR_REMOVE)
500         int flags = ATTR_DONTFOLLOW;
501         char *attrname = strchr(name,'.') + 1;
502         
503         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
504
505         return attr_remove(path, attrname, flags);
506 #elif defined(HAVE_ATTROPEN)
507         int ret = -1;
508         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
509         if (attrdirfd >= 0) {
510                 ret = solaris_unlinkat(attrdirfd, name);
511                 close(attrdirfd);
512         }
513         return ret;
514 #else
515         errno = ENOSYS;
516         return -1;
517 #endif
518 }
519
520 int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
521 {
522         const char *name = prefix(uname);
523 #if defined(HAVE_SETXATTR)
524 #ifndef XATTR_ADD_OPT
525         return setxattr(path, name, value, size, flags);
526 #else
527         int options = 0;
528         return setxattr(path, name, value, size, 0, options);
529 #endif
530 #elif defined(HAVE_SETEA)
531         return setea(path, name, value, size, flags);
532 #elif defined(HAVE_EXTATTR_SET_FILE)
533         int retval = 0;
534         if (flags) {
535                 /* Check attribute existence */
536                 retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
537                 if (retval < 0) {
538                         /* REPLACE attribute, that doesn't exist */
539                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
540                                 errno = ENOATTR;
541                                 return -1;
542                         }
543                         /* Ignore other errors */
544                 }
545                 else {
546                         /* CREATE attribute, that already exists */
547                         if (flags & XATTR_CREATE) {
548                                 errno = EEXIST;
549                                 return -1;
550                         }
551                 }
552         }
553         retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
554         return (retval < 0) ? -1 : 0;
555 #elif defined(HAVE_ATTR_SET)
556         int myflags = 0;
557         char *attrname = strchr(name,'.') + 1;
558         
559         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
560         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
561         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
562
563         return attr_set(path, attrname, (const char *)value, size, myflags);
564 #elif defined(HAVE_ATTROPEN)
565         int ret = -1;
566         int myflags = O_RDWR;
567         int attrfd;
568         if (flags & XATTR_CREATE) myflags |= O_EXCL;
569         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
570         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
571         if (attrfd >= 0) {
572                 ret = solaris_write_xattr(attrfd, value, size);
573                 close(attrfd);
574         }
575         return ret;
576 #else
577         errno = ENOSYS;
578         return -1;
579 #endif
580 }
581
582 int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
583 {
584         const char *name = prefix(uname);
585 #if defined(HAVE_LSETXATTR)
586         return lsetxattr(path, name, value, size, flags);
587 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
588         int options = XATTR_NOFOLLOW;
589         return setxattr(path, name, value, size, 0, options);
590 #elif defined(LSETEA)
591         return lsetea(path, name, value, size, flags);
592 #elif defined(HAVE_EXTATTR_SET_LINK)
593         int retval = 0;
594         if (flags) {
595                 /* Check attribute existence */
596                 retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
597                 if (retval < 0) {
598                         /* REPLACE attribute, that doesn't exist */
599                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
600                                 errno = ENOATTR;
601                                 return -1;
602                         }
603                         /* Ignore other errors */
604                 }
605                 else {
606                         /* CREATE attribute, that already exists */
607                         if (flags & XATTR_CREATE) {
608                                 errno = EEXIST;
609                                 return -1;
610                         }
611                 }
612         }
613
614         retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
615         return (retval < 0) ? -1 : 0;
616 #elif defined(HAVE_ATTR_SET)
617         int myflags = ATTR_DONTFOLLOW;
618         char *attrname = strchr(name,'.') + 1;
619         
620         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
621         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
622         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
623
624         return attr_set(path, attrname, (const char *)value, size, myflags);
625 #elif defined(HAVE_ATTROPEN)
626         int ret = -1;
627         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
628         int attrfd;
629         if (flags & XATTR_CREATE) myflags |= O_EXCL;
630         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
631         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
632         if (attrfd >= 0) {
633                 ret = solaris_write_xattr(attrfd, value, size);
634                 close(attrfd);
635         }
636         return ret;
637 #else
638         errno = ENOSYS;
639         return -1;
640 #endif
641 }
642
643 /**************************************************************************
644  helper functions for Solaris' EA support
645 ****************************************************************************/
646 #ifdef HAVE_ATTROPEN
647 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
648 {
649         struct stat sbuf;
650
651         if (fstat(attrfd, &sbuf) == -1) {
652                 return -1;
653         }
654
655         /* This is to return the current size of the named extended attribute */
656         if (size == 0) {
657                 return sbuf.st_size;
658         }
659
660         /* check size and read xattr */
661         if (sbuf.st_size > size) {
662                 return -1;
663         }
664
665         return read(attrfd, value, sbuf.st_size);
666 }
667
668 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
669 {
670         ssize_t len = 0;
671         DIR *dirp;
672         struct dirent *de;
673         int newfd = dup(attrdirfd);
674         /* CAUTION: The originating file descriptor should not be
675                     used again following the call to fdopendir().
676                     For that reason we dup() the file descriptor
677                     here to make things more clear. */
678         dirp = fdopendir(newfd);
679
680         while ((de = readdir(dirp))) {
681                 size_t listlen;
682                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
683                      !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw")) 
684                 {
685                         /* we don't want "." and ".." here: */
686                         LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
687                         continue;
688                 }
689
690                 listlen = strlen(de->d_name);
691                 if (size == 0) {
692                         /* return the current size of the list of extended attribute names*/
693                         len += listlen + 1;
694                 } else {
695                         /* check size and copy entry + nul into list. */
696                         if ((len + listlen + 1) > size) {
697                                 errno = ERANGE;
698                                 len = -1;
699                                 break;
700                         } else {
701                                 strcpy(list + len, de->d_name);
702                                 len += listlen;
703                                 list[len] = '\0';
704                                 ++len;
705                         }
706                 }
707         }
708
709         if (closedir(dirp) == -1) {
710                 LOG(log_error, logtype_default, "closedir dirp: %s",strerror(errno));
711                 return -1;
712         }
713         return len;
714 }
715
716 static int solaris_unlinkat(int attrdirfd, const char *name)
717 {
718         if (unlinkat(attrdirfd, name, 0) == -1) {
719                 return -1;
720         }
721         return 0;
722 }
723
724 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
725 {
726         int filedes = attropen(path, attrpath, oflag, mode);
727         if (filedes == -1) {
728         if (errno != ENOENT)
729             LOG(log_error, logtype_default, "attropen(\"%s\", ea:'%s'): %s",
730                 path, attrpath, strerror(errno));
731         errno = ENOATTR;
732         }
733         return filedes;
734 }
735
736 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
737 {
738         int filedes = openat(fildes, path, oflag, mode);
739         if (filedes == -1) {
740                 LOG(log_error, logtype_default, "openat(\"%s\"): %s",
741             path, strerror(errno));
742         }
743         return filedes;
744 }
745
746 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
747 {
748         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
749                 return 0;
750         } else {
751                 LOG(log_error, logtype_default, "solaris_write_xattr: %s",
752             strerror(errno));
753                 return -1;
754         }
755 }
756
757 #endif /*HAVE_ATTROPEN*/
758