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