s3:test_smbclient_posix_large.sh: there's no posix test to rename to test_smbclient_l...
[Samba.git] / lib / replace / xattr.c
blob2479c21b5533886442ffae178cd585d16f8aaf0c
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
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
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.
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.
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/>.
28 #define UID_WRAPPER_NOT_REPLACE
29 #include "replace.h"
30 #include "system/filesys.h"
31 #include "system/dir.h"
33 /******** Solaris EA helper function prototypes ********/
34 #ifdef HAVE_ATTROPEN
35 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
36 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
37 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
38 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
39 static int solaris_unlinkat(int attrdirfd, const char *name);
40 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
41 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
42 #endif
44 /**************************************************************************
45 Wrappers for extented attribute calls. Based on the Linux package with
46 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
47 ****************************************************************************/
49 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
51 #if defined(HAVE_GETXATTR)
52 #ifndef XATTR_ADDITIONAL_OPTIONS
53 return getxattr(path, name, value, size);
54 #else
56 /* So that we do not recursivly call this function */
57 #undef getxattr
58 int options = 0;
59 return getxattr(path, name, value, size, 0, options);
60 #endif
61 #elif defined(HAVE_GETEA)
62 return getea(path, name, value, size);
63 #elif defined(HAVE_EXTATTR_GET_FILE)
64 ssize_t retval;
65 int attrnamespace;
66 const char *attrname;
68 if (strncmp(name, "system.", 7) == 0) {
69 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
70 attrname = name + 7;
71 } else if (strncmp(name, "user.", 5) == 0) {
72 attrnamespace = EXTATTR_NAMESPACE_USER;
73 attrname = name + 5;
74 } else {
75 errno = EINVAL;
76 return -1;
80 * The BSD implementation has a nasty habit of silently truncating
81 * the returned value to the size of the buffer, so we have to check
82 * that the buffer is large enough to fit the returned value.
84 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
85 if (size == 0) {
86 return retval;
87 } else if (retval > size) {
88 errno = ERANGE;
89 return -1;
91 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
92 return retval;
95 return -1;
96 #elif defined(HAVE_ATTR_GET)
97 int retval, flags = 0;
98 int valuelength = (int)size;
99 char *attrname = strchr(name,'.') + 1;
101 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
103 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
104 if (size == 0 && retval == -1 && errno == E2BIG) {
105 return valuelength;
108 return retval ? retval : valuelength;
109 #elif defined(HAVE_ATTROPEN)
110 ssize_t ret = -1;
111 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
112 if (attrfd >= 0) {
113 ret = solaris_read_xattr(attrfd, value, size);
114 close(attrfd);
116 return ret;
117 #else
118 errno = ENOSYS;
119 return -1;
120 #endif
123 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
125 #if defined(HAVE_FGETXATTR)
126 #ifndef XATTR_ADDITIONAL_OPTIONS
127 return fgetxattr(filedes, name, value, size);
128 #else
130 /* So that we do not recursivly call this function */
131 #undef fgetxattr
132 int options = 0;
133 return fgetxattr(filedes, name, value, size, 0, options);
134 #endif
135 #elif defined(HAVE_FGETEA)
136 return fgetea(filedes, name, value, size);
137 #elif defined(HAVE_EXTATTR_GET_FD)
138 ssize_t retval;
139 int attrnamespace;
140 const char *attrname;
142 if (strncmp(name, "system.", 7) == 0) {
143 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
144 attrname = name + 7;
145 } else if (strncmp(name, "user.", 5) == 0) {
146 attrnamespace = EXTATTR_NAMESPACE_USER;
147 attrname = name + 5;
148 } else {
149 errno = EINVAL;
150 return -1;
153 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
154 if (size == 0) {
155 return retval;
156 } else if (retval > size) {
157 errno = ERANGE;
158 return -1;
160 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
161 return retval;
164 return -1;
165 #elif defined(HAVE_ATTR_GETF)
166 int retval, flags = 0;
167 int valuelength = (int)size;
168 char *attrname = strchr(name,'.') + 1;
170 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
172 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
173 if (size == 0 && retval == -1 && errno == E2BIG) {
174 return valuelength;
176 return retval ? retval : valuelength;
177 #elif defined(HAVE_ATTROPEN)
178 ssize_t ret = -1;
179 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
180 if (attrfd >= 0) {
181 ret = solaris_read_xattr(attrfd, value, size);
182 close(attrfd);
184 return ret;
185 #else
186 errno = ENOSYS;
187 return -1;
188 #endif
191 #if defined(HAVE_EXTATTR_LIST_FILE)
193 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
195 static struct {
196 int space;
197 const char *name;
198 size_t len;
200 extattr[] = {
201 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
202 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
205 typedef union {
206 const char *path;
207 int filedes;
208 } extattr_arg;
210 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
212 ssize_t list_size, total_size = 0;
213 int i, t, len;
214 char *buf;
215 /* Iterate through extattr(2) namespaces */
216 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
217 if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
218 /* ignore all but user namespace when we are not root, see bug 10247 */
219 continue;
221 switch(type) {
222 #if defined(HAVE_EXTATTR_LIST_FILE)
223 case 0:
224 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
225 break;
226 #endif
227 #if defined(HAVE_EXTATTR_LIST_LINK)
228 case 1:
229 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
230 break;
231 #endif
232 #if defined(HAVE_EXTATTR_LIST_FD)
233 case 2:
234 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
235 break;
236 #endif
237 default:
238 errno = ENOSYS;
239 return -1;
241 /* Some error happend. Errno should be set by the previous call */
242 if(list_size < 0)
243 return -1;
244 /* No attributes */
245 if(list_size == 0)
246 continue;
247 /* XXX: Call with an empty buffer may be used to calculate
248 necessary buffer size. Unfortunately, we can't say, how
249 many attributes were returned, so here is the potential
250 problem with the emulation.
252 if(list == NULL) {
253 /* Take the worse case of one char attribute names -
254 two bytes per name plus one more for sanity.
256 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
257 continue;
259 /* Count necessary offset to fit namespace prefixes */
260 len = 0;
261 for(i = 0; i < list_size; i += list[i] + 1)
262 len += extattr[t].len;
264 total_size += list_size + len;
265 /* Buffer is too small to fit the results */
266 if(total_size > size) {
267 errno = ERANGE;
268 return -1;
270 /* Shift results back, so we can prepend prefixes */
271 buf = (char *)memmove(list + len, list, list_size);
273 for(i = 0; i < list_size; i += len + 1) {
274 len = buf[i];
275 strncpy(list, extattr[t].name, extattr[t].len + 1);
276 list += extattr[t].len;
277 strncpy(list, buf + i + 1, len);
278 list[len] = '\0';
279 list += len + 1;
281 size -= total_size;
283 return total_size;
286 #endif
288 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
289 static char attr_buffer[ATTR_MAX_VALUELEN];
291 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
293 int retval = 0, index;
294 attrlist_cursor_t *cursor = 0;
295 int total_size = 0;
296 attrlist_t * al = (attrlist_t *)attr_buffer;
297 attrlist_ent_t *ae;
298 size_t ent_size, left = size;
299 char *bp = list;
301 while (true) {
302 if (filedes)
303 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
304 else
305 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
306 if (retval) break;
307 for (index = 0; index < al->al_count; index++) {
308 ae = ATTR_ENTRY(attr_buffer, index);
309 ent_size = strlen(ae->a_name) + sizeof("user.");
310 if (left >= ent_size) {
311 strncpy(bp, "user.", sizeof("user."));
312 strncat(bp, ae->a_name, ent_size - sizeof("user."));
313 bp += ent_size;
314 left -= ent_size;
315 } else if (size) {
316 errno = ERANGE;
317 retval = -1;
318 break;
320 total_size += ent_size;
322 if (al->al_more == 0) break;
324 if (retval == 0) {
325 flags |= ATTR_ROOT;
326 cursor = 0;
327 while (true) {
328 if (filedes)
329 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
330 else
331 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
332 if (retval) break;
333 for (index = 0; index < al->al_count; index++) {
334 ae = ATTR_ENTRY(attr_buffer, index);
335 ent_size = strlen(ae->a_name) + sizeof("system.");
336 if (left >= ent_size) {
337 strncpy(bp, "system.", sizeof("system."));
338 strncat(bp, ae->a_name, ent_size - sizeof("system."));
339 bp += ent_size;
340 left -= ent_size;
341 } else if (size) {
342 errno = ERANGE;
343 retval = -1;
344 break;
346 total_size += ent_size;
348 if (al->al_more == 0) break;
351 return (ssize_t)(retval ? retval : total_size);
354 #endif
356 ssize_t rep_listxattr (const char *path, char *list, size_t size)
358 #if defined(HAVE_LISTXATTR)
359 #ifndef XATTR_ADDITIONAL_OPTIONS
360 return listxattr(path, list, size);
361 #else
362 /* So that we do not recursivly call this function */
363 #undef listxattr
364 int options = 0;
365 return listxattr(path, list, size, options);
366 #endif
367 #elif defined(HAVE_LISTEA)
368 return listea(path, list, size);
369 #elif defined(HAVE_EXTATTR_LIST_FILE)
370 extattr_arg arg;
371 arg.path = path;
372 return bsd_attr_list(0, arg, list, size);
373 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
374 return irix_attr_list(path, 0, list, size, 0);
375 #elif defined(HAVE_ATTROPEN)
376 ssize_t ret = -1;
377 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
378 if (attrdirfd >= 0) {
379 ret = solaris_list_xattr(attrdirfd, list, size);
380 close(attrdirfd);
382 return ret;
383 #else
384 errno = ENOSYS;
385 return -1;
386 #endif
389 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
391 #if defined(HAVE_FLISTXATTR)
392 #ifndef XATTR_ADDITIONAL_OPTIONS
393 return flistxattr(filedes, list, size);
394 #else
395 /* So that we do not recursivly call this function */
396 #undef flistxattr
397 int options = 0;
398 return flistxattr(filedes, list, size, options);
399 #endif
400 #elif defined(HAVE_FLISTEA)
401 return flistea(filedes, list, size);
402 #elif defined(HAVE_EXTATTR_LIST_FD)
403 extattr_arg arg;
404 arg.filedes = filedes;
405 return bsd_attr_list(2, arg, list, size);
406 #elif defined(HAVE_ATTR_LISTF)
407 return irix_attr_list(NULL, filedes, list, size, 0);
408 #elif defined(HAVE_ATTROPEN)
409 ssize_t ret = -1;
410 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
411 if (attrdirfd >= 0) {
412 ret = solaris_list_xattr(attrdirfd, list, size);
413 close(attrdirfd);
415 return ret;
416 #else
417 errno = ENOSYS;
418 return -1;
419 #endif
422 int rep_removexattr (const char *path, const char *name)
424 #if defined(HAVE_REMOVEXATTR)
425 #ifndef XATTR_ADDITIONAL_OPTIONS
426 return removexattr(path, name);
427 #else
428 /* So that we do not recursivly call this function */
429 #undef removexattr
430 int options = 0;
431 return removexattr(path, name, options);
432 #endif
433 #elif defined(HAVE_REMOVEEA)
434 return removeea(path, name);
435 #elif defined(HAVE_EXTATTR_DELETE_FILE)
436 int attrnamespace;
437 const char *attrname;
439 if (strncmp(name, "system.", 7) == 0) {
440 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
441 attrname = name + 7;
442 } else if (strncmp(name, "user.", 5) == 0) {
443 attrnamespace = EXTATTR_NAMESPACE_USER;
444 attrname = name + 5;
445 } else {
446 errno = EINVAL;
447 return -1;
450 return extattr_delete_file(path, attrnamespace, attrname);
451 #elif defined(HAVE_ATTR_REMOVE)
452 int flags = 0;
453 char *attrname = strchr(name,'.') + 1;
455 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
457 return attr_remove(path, attrname, flags);
458 #elif defined(HAVE_ATTROPEN)
459 int ret = -1;
460 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
461 if (attrdirfd >= 0) {
462 ret = solaris_unlinkat(attrdirfd, name);
463 close(attrdirfd);
465 return ret;
466 #else
467 errno = ENOSYS;
468 return -1;
469 #endif
472 int rep_fremovexattr (int filedes, const char *name)
474 #if defined(HAVE_FREMOVEXATTR)
475 #ifndef XATTR_ADDITIONAL_OPTIONS
476 return fremovexattr(filedes, name);
477 #else
478 /* So that we do not recursivly call this function */
479 #undef fremovexattr
480 int options = 0;
481 return fremovexattr(filedes, name, options);
482 #endif
483 #elif defined(HAVE_FREMOVEEA)
484 return fremoveea(filedes, name);
485 #elif defined(HAVE_EXTATTR_DELETE_FD)
486 int attrnamespace;
487 const char *attrname;
489 if (strncmp(name, "system.", 7) == 0) {
490 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
491 attrname = name + 7;
492 } else if (strncmp(name, "user.", 5) == 0) {
493 attrnamespace = EXTATTR_NAMESPACE_USER;
494 attrname = name + 5;
495 } else {
496 errno = EINVAL;
497 return -1;
500 return extattr_delete_fd(filedes, attrnamespace, attrname);
501 #elif defined(HAVE_ATTR_REMOVEF)
502 int flags = 0;
503 char *attrname = strchr(name,'.') + 1;
505 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
507 return attr_removef(filedes, attrname, flags);
508 #elif defined(HAVE_ATTROPEN)
509 int ret = -1;
510 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
511 if (attrdirfd >= 0) {
512 ret = solaris_unlinkat(attrdirfd, name);
513 close(attrdirfd);
515 return ret;
516 #else
517 errno = ENOSYS;
518 return -1;
519 #endif
522 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
524 #if defined(HAVE_SETXATTR)
525 #ifndef XATTR_ADDITIONAL_OPTIONS
526 return setxattr(path, name, value, size, flags);
527 #else
528 /* So that we do not recursivly call this function */
529 #undef setxattr
530 int options = 0;
531 return setxattr(path, name, value, size, 0, options);
532 #endif
533 #elif defined(HAVE_SETEA)
534 return setea(path, name, value, size, flags);
535 #elif defined(HAVE_EXTATTR_SET_FILE)
536 int retval = 0;
537 int attrnamespace;
538 const char *attrname;
540 if (strncmp(name, "system.", 7) == 0) {
541 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
542 attrname = name + 7;
543 } else if (strncmp(name, "user.", 5) == 0) {
544 attrnamespace = EXTATTR_NAMESPACE_USER;
545 attrname = name + 5;
546 } else {
547 errno = EINVAL;
548 return -1;
551 if (flags) {
552 /* Check attribute existence */
553 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
554 if (retval < 0) {
555 /* REPLACE attribute, that doesn't exist */
556 if (flags & XATTR_REPLACE && errno == ENOATTR) {
557 errno = ENOATTR;
558 return -1;
560 /* Ignore other errors */
562 else {
563 /* CREATE attribute, that already exists */
564 if (flags & XATTR_CREATE) {
565 errno = EEXIST;
566 return -1;
570 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
571 return (retval < 0) ? -1 : 0;
572 #elif defined(HAVE_ATTR_SET)
573 int myflags = 0;
574 char *attrname = strchr(name,'.') + 1;
576 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
577 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
578 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
580 return attr_set(path, attrname, (const char *)value, size, myflags);
581 #elif defined(HAVE_ATTROPEN)
582 int ret = -1;
583 int myflags = O_RDWR;
584 int attrfd;
585 if (flags & XATTR_CREATE) myflags |= O_EXCL;
586 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
587 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
588 if (attrfd >= 0) {
589 ret = solaris_write_xattr(attrfd, value, size);
590 close(attrfd);
592 return ret;
593 #else
594 errno = ENOSYS;
595 return -1;
596 #endif
599 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
601 #if defined(HAVE_FSETXATTR)
602 #ifndef XATTR_ADDITIONAL_OPTIONS
603 return fsetxattr(filedes, name, value, size, flags);
604 #else
605 /* So that we do not recursivly call this function */
606 #undef fsetxattr
607 int options = 0;
608 return fsetxattr(filedes, name, value, size, 0, options);
609 #endif
610 #elif defined(HAVE_FSETEA)
611 return fsetea(filedes, name, value, size, flags);
612 #elif defined(HAVE_EXTATTR_SET_FD)
613 int retval = 0;
614 int attrnamespace;
615 const char *attrname;
617 if (strncmp(name, "system.", 7) == 0) {
618 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
619 attrname = name + 7;
620 } else if (strncmp(name, "user.", 5) == 0) {
621 attrnamespace = EXTATTR_NAMESPACE_USER;
622 attrname = name + 5;
623 } else {
624 errno = EINVAL;
625 return -1;
628 if (flags) {
629 /* Check attribute existence */
630 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
631 if (retval < 0) {
632 /* REPLACE attribute, that doesn't exist */
633 if (flags & XATTR_REPLACE && errno == ENOATTR) {
634 errno = ENOATTR;
635 return -1;
637 /* Ignore other errors */
639 else {
640 /* CREATE attribute, that already exists */
641 if (flags & XATTR_CREATE) {
642 errno = EEXIST;
643 return -1;
647 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
648 return (retval < 0) ? -1 : 0;
649 #elif defined(HAVE_ATTR_SETF)
650 int myflags = 0;
651 char *attrname = strchr(name,'.') + 1;
653 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
654 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
655 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
657 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
658 #elif defined(HAVE_ATTROPEN)
659 int ret = -1;
660 int myflags = O_RDWR | O_XATTR;
661 int attrfd;
662 if (flags & XATTR_CREATE) myflags |= O_EXCL;
663 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
664 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
665 if (attrfd >= 0) {
666 ret = solaris_write_xattr(attrfd, value, size);
667 close(attrfd);
669 return ret;
670 #else
671 errno = ENOSYS;
672 return -1;
673 #endif
676 /**************************************************************************
677 helper functions for Solaris' EA support
678 ****************************************************************************/
679 #ifdef HAVE_ATTROPEN
680 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
682 struct stat sbuf;
684 if (fstat(attrfd, &sbuf) == -1) {
685 errno = ENOATTR;
686 return -1;
689 /* This is to return the current size of the named extended attribute */
690 if (size == 0) {
691 return sbuf.st_size;
694 /* check size and read xattr */
695 if (sbuf.st_size > size) {
696 errno = ERANGE;
697 return -1;
700 return read(attrfd, value, sbuf.st_size);
703 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
705 ssize_t len = 0;
706 DIR *dirp;
707 struct dirent *de;
708 int newfd = dup(attrdirfd);
709 /* CAUTION: The originating file descriptor should not be
710 used again following the call to fdopendir().
711 For that reason we dup() the file descriptor
712 here to make things more clear. */
713 dirp = fdopendir(newfd);
715 while ((de = readdir(dirp))) {
716 size_t listlen = strlen(de->d_name) + 1;
717 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
718 /* we don't want "." and ".." here: */
719 continue;
722 if (size == 0) {
723 /* return the current size of the list of extended attribute names*/
724 len += listlen;
725 } else {
726 /* check size and copy entrieѕ + nul into list. */
727 if ((len + listlen) > size) {
728 errno = ERANGE;
729 len = -1;
730 break;
731 } else {
732 strlcpy(list + len, de->d_name, listlen);
733 len += listlen;
738 if (closedir(dirp) == -1) {
739 return -1;
741 return len;
744 static int solaris_unlinkat(int attrdirfd, const char *name)
746 if (unlinkat(attrdirfd, name, 0) == -1) {
747 if (errno == ENOENT) {
748 errno = ENOATTR;
750 return -1;
752 return 0;
755 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
757 int filedes = attropen(path, attrpath, oflag, mode);
758 if (filedes == -1) {
759 if (errno == EINVAL) {
760 errno = ENOTSUP;
761 } else {
762 errno = ENOATTR;
765 return filedes;
768 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
770 int filedes = openat(fildes, path, oflag, mode);
771 if (filedes == -1) {
772 if (errno == EINVAL) {
773 errno = ENOTSUP;
774 } else {
775 errno = ENOATTR;
778 return filedes;
781 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
783 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
784 return 0;
785 } else {
786 return -1;
789 #endif /*HAVE_ATTROPEN*/