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