build: rename HAVE_MSGHDR_MSG_ACCTRIGHTS to HAVE_STRUCT_MSGHDR_MSG_ACCTRIGHTS
[Samba.git] / lib / replace / xattr.c
blobce52d1a581a9bae1d0de017f48a6ecff84e26f95
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 char *s;
65 ssize_t retval;
66 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
67 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
68 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
70 * The BSD implementation has a nasty habit of silently truncating
71 * the returned value to the size of the buffer, so we have to check
72 * that the buffer is large enough to fit the returned value.
74 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
75 if (size == 0) {
76 return retval;
77 } else if (retval > size) {
78 errno = ERANGE;
79 return -1;
81 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
82 return retval;
85 return -1;
86 #elif defined(HAVE_ATTR_GET)
87 int retval, flags = 0;
88 int valuelength = (int)size;
89 char *attrname = strchr(name,'.') + 1;
91 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
93 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
94 if (size == 0 && retval == -1 && errno == E2BIG) {
95 return valuelength;
98 return retval ? retval : valuelength;
99 #elif defined(HAVE_ATTROPEN)
100 ssize_t ret = -1;
101 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
102 if (attrfd >= 0) {
103 ret = solaris_read_xattr(attrfd, value, size);
104 close(attrfd);
106 return ret;
107 #else
108 errno = ENOSYS;
109 return -1;
110 #endif
113 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
115 #if defined(HAVE_FGETXATTR)
116 #ifndef XATTR_ADDITIONAL_OPTIONS
117 return fgetxattr(filedes, name, value, size);
118 #else
120 /* So that we do not recursivly call this function */
121 #undef fgetxattr
122 int options = 0;
123 return fgetxattr(filedes, name, value, size, 0, options);
124 #endif
125 #elif defined(HAVE_FGETEA)
126 return fgetea(filedes, name, value, size);
127 #elif defined(HAVE_EXTATTR_GET_FD)
128 char *s;
129 ssize_t retval;
130 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
131 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
132 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
134 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
135 if (size == 0) {
136 return retval;
137 } else if (retval > size) {
138 errno = ERANGE;
139 return -1;
141 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
142 return retval;
145 return -1;
146 #elif defined(HAVE_ATTR_GETF)
147 int retval, flags = 0;
148 int valuelength = (int)size;
149 char *attrname = strchr(name,'.') + 1;
151 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
153 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
154 if (size == 0 && retval == -1 && errno == E2BIG) {
155 return valuelength;
157 return retval ? retval : valuelength;
158 #elif defined(HAVE_ATTROPEN)
159 ssize_t ret = -1;
160 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
161 if (attrfd >= 0) {
162 ret = solaris_read_xattr(attrfd, value, size);
163 close(attrfd);
165 return ret;
166 #else
167 errno = ENOSYS;
168 return -1;
169 #endif
172 #if defined(HAVE_EXTATTR_LIST_FILE)
174 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
176 static struct {
177 int space;
178 const char *name;
179 size_t len;
181 extattr[] = {
182 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
183 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
186 typedef union {
187 const char *path;
188 int filedes;
189 } extattr_arg;
191 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
193 ssize_t list_size, total_size = 0;
194 int i, t, len;
195 char *buf;
196 /* Iterate through extattr(2) namespaces */
197 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
198 if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
199 /* ignore all but user namespace when we are not root, see bug 10247 */
200 continue;
202 switch(type) {
203 #if defined(HAVE_EXTATTR_LIST_FILE)
204 case 0:
205 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
206 break;
207 #endif
208 #if defined(HAVE_EXTATTR_LIST_LINK)
209 case 1:
210 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
211 break;
212 #endif
213 #if defined(HAVE_EXTATTR_LIST_FD)
214 case 2:
215 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
216 break;
217 #endif
218 default:
219 errno = ENOSYS;
220 return -1;
222 /* Some error happend. Errno should be set by the previous call */
223 if(list_size < 0)
224 return -1;
225 /* No attributes */
226 if(list_size == 0)
227 continue;
228 /* XXX: Call with an empty buffer may be used to calculate
229 necessary buffer size. Unfortunately, we can't say, how
230 many attributes were returned, so here is the potential
231 problem with the emulation.
233 if(list == NULL) {
234 /* Take the worse case of one char attribute names -
235 two bytes per name plus one more for sanity.
237 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
238 continue;
240 /* Count necessary offset to fit namespace prefixes */
241 len = 0;
242 for(i = 0; i < list_size; i += list[i] + 1)
243 len += extattr[t].len;
245 total_size += list_size + len;
246 /* Buffer is too small to fit the results */
247 if(total_size > size) {
248 errno = ERANGE;
249 return -1;
251 /* Shift results back, so we can prepend prefixes */
252 buf = (char *)memmove(list + len, list, list_size);
254 for(i = 0; i < list_size; i += len + 1) {
255 len = buf[i];
256 strncpy(list, extattr[t].name, extattr[t].len + 1);
257 list += extattr[t].len;
258 strncpy(list, buf + i + 1, len);
259 list[len] = '\0';
260 list += len + 1;
262 size -= total_size;
264 return total_size;
267 #endif
269 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
270 static char attr_buffer[ATTR_MAX_VALUELEN];
272 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
274 int retval = 0, index;
275 attrlist_cursor_t *cursor = 0;
276 int total_size = 0;
277 attrlist_t * al = (attrlist_t *)attr_buffer;
278 attrlist_ent_t *ae;
279 size_t ent_size, left = size;
280 char *bp = list;
282 while (true) {
283 if (filedes)
284 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
285 else
286 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
287 if (retval) break;
288 for (index = 0; index < al->al_count; index++) {
289 ae = ATTR_ENTRY(attr_buffer, index);
290 ent_size = strlen(ae->a_name) + sizeof("user.");
291 if (left >= ent_size) {
292 strncpy(bp, "user.", sizeof("user."));
293 strncat(bp, ae->a_name, ent_size - sizeof("user."));
294 bp += ent_size;
295 left -= ent_size;
296 } else if (size) {
297 errno = ERANGE;
298 retval = -1;
299 break;
301 total_size += ent_size;
303 if (al->al_more == 0) break;
305 if (retval == 0) {
306 flags |= ATTR_ROOT;
307 cursor = 0;
308 while (true) {
309 if (filedes)
310 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
311 else
312 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
313 if (retval) break;
314 for (index = 0; index < al->al_count; index++) {
315 ae = ATTR_ENTRY(attr_buffer, index);
316 ent_size = strlen(ae->a_name) + sizeof("system.");
317 if (left >= ent_size) {
318 strncpy(bp, "system.", sizeof("system."));
319 strncat(bp, ae->a_name, ent_size - sizeof("system."));
320 bp += ent_size;
321 left -= ent_size;
322 } else if (size) {
323 errno = ERANGE;
324 retval = -1;
325 break;
327 total_size += ent_size;
329 if (al->al_more == 0) break;
332 return (ssize_t)(retval ? retval : total_size);
335 #endif
337 ssize_t rep_listxattr (const char *path, char *list, size_t size)
339 #if defined(HAVE_LISTXATTR)
340 #ifndef XATTR_ADDITIONAL_OPTIONS
341 return listxattr(path, list, size);
342 #else
343 /* So that we do not recursivly call this function */
344 #undef listxattr
345 int options = 0;
346 return listxattr(path, list, size, options);
347 #endif
348 #elif defined(HAVE_LISTEA)
349 return listea(path, list, size);
350 #elif defined(HAVE_EXTATTR_LIST_FILE)
351 extattr_arg arg;
352 arg.path = path;
353 return bsd_attr_list(0, arg, list, size);
354 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
355 return irix_attr_list(path, 0, list, size, 0);
356 #elif defined(HAVE_ATTROPEN)
357 ssize_t ret = -1;
358 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
359 if (attrdirfd >= 0) {
360 ret = solaris_list_xattr(attrdirfd, list, size);
361 close(attrdirfd);
363 return ret;
364 #else
365 errno = ENOSYS;
366 return -1;
367 #endif
370 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
372 #if defined(HAVE_FLISTXATTR)
373 #ifndef XATTR_ADDITIONAL_OPTIONS
374 return flistxattr(filedes, list, size);
375 #else
376 /* So that we do not recursivly call this function */
377 #undef flistxattr
378 int options = 0;
379 return flistxattr(filedes, list, size, options);
380 #endif
381 #elif defined(HAVE_FLISTEA)
382 return flistea(filedes, list, size);
383 #elif defined(HAVE_EXTATTR_LIST_FD)
384 extattr_arg arg;
385 arg.filedes = filedes;
386 return bsd_attr_list(2, arg, list, size);
387 #elif defined(HAVE_ATTR_LISTF)
388 return irix_attr_list(NULL, filedes, list, size, 0);
389 #elif defined(HAVE_ATTROPEN)
390 ssize_t ret = -1;
391 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
392 if (attrdirfd >= 0) {
393 ret = solaris_list_xattr(attrdirfd, list, size);
394 close(attrdirfd);
396 return ret;
397 #else
398 errno = ENOSYS;
399 return -1;
400 #endif
403 int rep_removexattr (const char *path, const char *name)
405 #if defined(HAVE_REMOVEXATTR)
406 #ifndef XATTR_ADDITIONAL_OPTIONS
407 return removexattr(path, name);
408 #else
409 /* So that we do not recursivly call this function */
410 #undef removexattr
411 int options = 0;
412 return removexattr(path, name, options);
413 #endif
414 #elif defined(HAVE_REMOVEEA)
415 return removeea(path, name);
416 #elif defined(HAVE_EXTATTR_DELETE_FILE)
417 char *s;
418 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
419 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
420 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
422 return extattr_delete_file(path, attrnamespace, attrname);
423 #elif defined(HAVE_ATTR_REMOVE)
424 int flags = 0;
425 char *attrname = strchr(name,'.') + 1;
427 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
429 return attr_remove(path, attrname, flags);
430 #elif defined(HAVE_ATTROPEN)
431 int ret = -1;
432 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
433 if (attrdirfd >= 0) {
434 ret = solaris_unlinkat(attrdirfd, name);
435 close(attrdirfd);
437 return ret;
438 #else
439 errno = ENOSYS;
440 return -1;
441 #endif
444 int rep_fremovexattr (int filedes, const char *name)
446 #if defined(HAVE_FREMOVEXATTR)
447 #ifndef XATTR_ADDITIONAL_OPTIONS
448 return fremovexattr(filedes, name);
449 #else
450 /* So that we do not recursivly call this function */
451 #undef fremovexattr
452 int options = 0;
453 return fremovexattr(filedes, name, options);
454 #endif
455 #elif defined(HAVE_FREMOVEEA)
456 return fremoveea(filedes, name);
457 #elif defined(HAVE_EXTATTR_DELETE_FD)
458 char *s;
459 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
460 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
461 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
463 return extattr_delete_fd(filedes, attrnamespace, attrname);
464 #elif defined(HAVE_ATTR_REMOVEF)
465 int flags = 0;
466 char *attrname = strchr(name,'.') + 1;
468 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
470 return attr_removef(filedes, attrname, flags);
471 #elif defined(HAVE_ATTROPEN)
472 int ret = -1;
473 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
474 if (attrdirfd >= 0) {
475 ret = solaris_unlinkat(attrdirfd, name);
476 close(attrdirfd);
478 return ret;
479 #else
480 errno = ENOSYS;
481 return -1;
482 #endif
485 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
487 #if defined(HAVE_SETXATTR)
488 #ifndef XATTR_ADDITIONAL_OPTIONS
489 return setxattr(path, name, value, size, flags);
490 #else
491 /* So that we do not recursivly call this function */
492 #undef setxattr
493 int options = 0;
494 return setxattr(path, name, value, size, 0, options);
495 #endif
496 #elif defined(HAVE_SETEA)
497 return setea(path, name, value, size, flags);
498 #elif defined(HAVE_EXTATTR_SET_FILE)
499 char *s;
500 int retval = 0;
501 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
502 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
503 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
504 if (flags) {
505 /* Check attribute existence */
506 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
507 if (retval < 0) {
508 /* REPLACE attribute, that doesn't exist */
509 if (flags & XATTR_REPLACE && errno == ENOATTR) {
510 errno = ENOATTR;
511 return -1;
513 /* Ignore other errors */
515 else {
516 /* CREATE attribute, that already exists */
517 if (flags & XATTR_CREATE) {
518 errno = EEXIST;
519 return -1;
523 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
524 return (retval < 0) ? -1 : 0;
525 #elif defined(HAVE_ATTR_SET)
526 int myflags = 0;
527 char *attrname = strchr(name,'.') + 1;
529 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
530 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
531 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
533 return attr_set(path, attrname, (const char *)value, size, myflags);
534 #elif defined(HAVE_ATTROPEN)
535 int ret = -1;
536 int myflags = O_RDWR;
537 int attrfd;
538 if (flags & XATTR_CREATE) myflags |= O_EXCL;
539 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
540 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
541 if (attrfd >= 0) {
542 ret = solaris_write_xattr(attrfd, value, size);
543 close(attrfd);
545 return ret;
546 #else
547 errno = ENOSYS;
548 return -1;
549 #endif
552 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
554 #if defined(HAVE_FSETXATTR)
555 #ifndef XATTR_ADDITIONAL_OPTIONS
556 return fsetxattr(filedes, name, value, size, flags);
557 #else
558 /* So that we do not recursivly call this function */
559 #undef fsetxattr
560 int options = 0;
561 return fsetxattr(filedes, name, value, size, 0, options);
562 #endif
563 #elif defined(HAVE_FSETEA)
564 return fsetea(filedes, name, value, size, flags);
565 #elif defined(HAVE_EXTATTR_SET_FD)
566 char *s;
567 int retval = 0;
568 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
569 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
570 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
571 if (flags) {
572 /* Check attribute existence */
573 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
574 if (retval < 0) {
575 /* REPLACE attribute, that doesn't exist */
576 if (flags & XATTR_REPLACE && errno == ENOATTR) {
577 errno = ENOATTR;
578 return -1;
580 /* Ignore other errors */
582 else {
583 /* CREATE attribute, that already exists */
584 if (flags & XATTR_CREATE) {
585 errno = EEXIST;
586 return -1;
590 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
591 return (retval < 0) ? -1 : 0;
592 #elif defined(HAVE_ATTR_SETF)
593 int myflags = 0;
594 char *attrname = strchr(name,'.') + 1;
596 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
597 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
598 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
600 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
601 #elif defined(HAVE_ATTROPEN)
602 int ret = -1;
603 int myflags = O_RDWR | O_XATTR;
604 int attrfd;
605 if (flags & XATTR_CREATE) myflags |= O_EXCL;
606 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
607 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
608 if (attrfd >= 0) {
609 ret = solaris_write_xattr(attrfd, value, size);
610 close(attrfd);
612 return ret;
613 #else
614 errno = ENOSYS;
615 return -1;
616 #endif
619 /**************************************************************************
620 helper functions for Solaris' EA support
621 ****************************************************************************/
622 #ifdef HAVE_ATTROPEN
623 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
625 struct stat sbuf;
627 if (fstat(attrfd, &sbuf) == -1) {
628 errno = ENOATTR;
629 return -1;
632 /* This is to return the current size of the named extended attribute */
633 if (size == 0) {
634 return sbuf.st_size;
637 /* check size and read xattr */
638 if (sbuf.st_size > size) {
639 errno = ERANGE;
640 return -1;
643 return read(attrfd, value, sbuf.st_size);
646 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
648 ssize_t len = 0;
649 DIR *dirp;
650 struct dirent *de;
651 int newfd = dup(attrdirfd);
652 /* CAUTION: The originating file descriptor should not be
653 used again following the call to fdopendir().
654 For that reason we dup() the file descriptor
655 here to make things more clear. */
656 dirp = fdopendir(newfd);
658 while ((de = readdir(dirp))) {
659 size_t listlen = strlen(de->d_name) + 1;
660 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
661 /* we don't want "." and ".." here: */
662 continue;
665 if (size == 0) {
666 /* return the current size of the list of extended attribute names*/
667 len += listlen;
668 } else {
669 /* check size and copy entrieѕ + nul into list. */
670 if ((len + listlen) > size) {
671 errno = ERANGE;
672 len = -1;
673 break;
674 } else {
675 strlcpy(list + len, de->d_name, listlen);
676 len += listlen;
681 if (closedir(dirp) == -1) {
682 return -1;
684 return len;
687 static int solaris_unlinkat(int attrdirfd, const char *name)
689 if (unlinkat(attrdirfd, name, 0) == -1) {
690 if (errno == ENOENT) {
691 errno = ENOATTR;
693 return -1;
695 return 0;
698 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
700 int filedes = attropen(path, attrpath, oflag, mode);
701 if (filedes == -1) {
702 if (errno == EINVAL) {
703 errno = ENOTSUP;
704 } else {
705 errno = ENOATTR;
708 return filedes;
711 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
713 int filedes = openat(fildes, path, oflag, mode);
714 if (filedes == -1) {
715 if (errno == EINVAL) {
716 errno = ENOTSUP;
717 } else {
718 errno = ENOATTR;
721 return filedes;
724 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
726 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
727 return 0;
728 } else {
729 return -1;
732 #endif /*HAVE_ATTROPEN*/