VERSION: Disable git snapshots for the 4.0.24 release.
[Samba.git] / lib / replace / xattr.c
blob459b7f3b65d67dabff761fe05d32e14d00c66cac
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 #include "replace.h"
29 #include "system/filesys.h"
30 #include "system/dir.h"
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
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 ****************************************************************************/
48 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
50 #if defined(HAVE_GETXATTR)
51 #ifndef XATTR_ADDITIONAL_OPTIONS
52 return getxattr(path, name, value, size);
53 #else
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;
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.
73 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
74 if (size == 0) {
75 return retval;
76 } else if (retval > size) {
77 errno = ERANGE;
78 return -1;
80 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
81 return retval;
84 return -1;
85 #elif defined(HAVE_ATTR_GET)
86 int retval, flags = 0;
87 int valuelength = (int)size;
88 char *attrname = strchr(name,'.') + 1;
90 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
92 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
93 if (size == 0 && retval == -1 && errno == E2BIG) {
94 return valuelength;
97 return retval ? retval : valuelength;
98 #elif defined(HAVE_ATTROPEN)
99 ssize_t ret = -1;
100 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
101 if (attrfd >= 0) {
102 ret = solaris_read_xattr(attrfd, value, size);
103 close(attrfd);
105 return ret;
106 #else
107 errno = ENOSYS;
108 return -1;
109 #endif
112 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
114 #if defined(HAVE_FGETXATTR)
115 #ifndef XATTR_ADDITIONAL_OPTIONS
116 return fgetxattr(filedes, name, value, size);
117 #else
119 /* So that we do not recursivly call this function */
120 #undef fgetxattr
121 int options = 0;
122 return fgetxattr(filedes, name, value, size, 0, options);
123 #endif
124 #elif defined(HAVE_FGETEA)
125 return fgetea(filedes, name, value, size);
126 #elif defined(HAVE_EXTATTR_GET_FD)
127 char *s;
128 ssize_t retval;
129 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
130 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
131 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
133 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
134 if (size == 0) {
135 return retval;
136 } else if (retval > size) {
137 errno = ERANGE;
138 return -1;
140 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
141 return retval;
144 return -1;
145 #elif defined(HAVE_ATTR_GETF)
146 int retval, flags = 0;
147 int valuelength = (int)size;
148 char *attrname = strchr(name,'.') + 1;
150 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
152 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
153 if (size == 0 && retval == -1 && errno == E2BIG) {
154 return valuelength;
156 return retval ? retval : valuelength;
157 #elif defined(HAVE_ATTROPEN)
158 ssize_t ret = -1;
159 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
160 if (attrfd >= 0) {
161 ret = solaris_read_xattr(attrfd, value, size);
162 close(attrfd);
164 return ret;
165 #else
166 errno = ENOSYS;
167 return -1;
168 #endif
171 #if defined(HAVE_EXTATTR_LIST_FILE)
173 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
175 static struct {
176 int space;
177 const char *name;
178 size_t len;
180 extattr[] = {
181 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
182 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
185 typedef union {
186 const char *path;
187 int filedes;
188 } extattr_arg;
190 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
192 ssize_t list_size, total_size = 0;
193 int i, t, len;
194 char *buf;
195 /* Iterate through extattr(2) namespaces */
196 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
197 if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
198 /* ignore all but user namespace when we are not root, see bug 10247 */
199 continue;
201 switch(type) {
202 #if defined(HAVE_EXTATTR_LIST_FILE)
203 case 0:
204 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
205 break;
206 #endif
207 #if defined(HAVE_EXTATTR_LIST_LINK)
208 case 1:
209 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
210 break;
211 #endif
212 #if defined(HAVE_EXTATTR_LIST_FD)
213 case 2:
214 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
215 break;
216 #endif
217 default:
218 errno = ENOSYS;
219 return -1;
221 /* Some error happend. Errno should be set by the previous call */
222 if(list_size < 0)
223 return -1;
224 /* No attributes */
225 if(list_size == 0)
226 continue;
227 /* XXX: Call with an empty buffer may be used to calculate
228 necessary buffer size. Unfortunately, we can't say, how
229 many attributes were returned, so here is the potential
230 problem with the emulation.
232 if(list == NULL) {
233 /* Take the worse case of one char attribute names -
234 two bytes per name plus one more for sanity.
236 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
237 continue;
239 /* Count necessary offset to fit namespace prefixes */
240 len = 0;
241 for(i = 0; i < list_size; i += list[i] + 1)
242 len += extattr[t].len;
244 total_size += list_size + len;
245 /* Buffer is too small to fit the results */
246 if(total_size > size) {
247 errno = ERANGE;
248 return -1;
250 /* Shift results back, so we can prepend prefixes */
251 buf = (char *)memmove(list + len, list, list_size);
253 for(i = 0; i < list_size; i += len + 1) {
254 len = buf[i];
255 strncpy(list, extattr[t].name, extattr[t].len + 1);
256 list += extattr[t].len;
257 strncpy(list, buf + i + 1, len);
258 list[len] = '\0';
259 list += len + 1;
261 size -= total_size;
263 return total_size;
266 #endif
268 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
269 static char attr_buffer[ATTR_MAX_VALUELEN];
271 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
273 int retval = 0, index;
274 attrlist_cursor_t *cursor = 0;
275 int total_size = 0;
276 attrlist_t * al = (attrlist_t *)attr_buffer;
277 attrlist_ent_t *ae;
278 size_t ent_size, left = size;
279 char *bp = list;
281 while (true) {
282 if (filedes)
283 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
284 else
285 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
286 if (retval) break;
287 for (index = 0; index < al->al_count; index++) {
288 ae = ATTR_ENTRY(attr_buffer, index);
289 ent_size = strlen(ae->a_name) + sizeof("user.");
290 if (left >= ent_size) {
291 strncpy(bp, "user.", sizeof("user."));
292 strncat(bp, ae->a_name, ent_size - sizeof("user."));
293 bp += ent_size;
294 left -= ent_size;
295 } else if (size) {
296 errno = ERANGE;
297 retval = -1;
298 break;
300 total_size += ent_size;
302 if (al->al_more == 0) break;
304 if (retval == 0) {
305 flags |= ATTR_ROOT;
306 cursor = 0;
307 while (true) {
308 if (filedes)
309 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
310 else
311 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
312 if (retval) break;
313 for (index = 0; index < al->al_count; index++) {
314 ae = ATTR_ENTRY(attr_buffer, index);
315 ent_size = strlen(ae->a_name) + sizeof("system.");
316 if (left >= ent_size) {
317 strncpy(bp, "system.", sizeof("system."));
318 strncat(bp, ae->a_name, ent_size - sizeof("system."));
319 bp += ent_size;
320 left -= ent_size;
321 } else if (size) {
322 errno = ERANGE;
323 retval = -1;
324 break;
326 total_size += ent_size;
328 if (al->al_more == 0) break;
331 return (ssize_t)(retval ? retval : total_size);
334 #endif
336 ssize_t rep_listxattr (const char *path, char *list, size_t size)
338 #if defined(HAVE_LISTXATTR)
339 #ifndef XATTR_ADDITIONAL_OPTIONS
340 return listxattr(path, list, size);
341 #else
342 /* So that we do not recursivly call this function */
343 #undef listxattr
344 int options = 0;
345 return listxattr(path, list, size, options);
346 #endif
347 #elif defined(HAVE_LISTEA)
348 return listea(path, list, size);
349 #elif defined(HAVE_EXTATTR_LIST_FILE)
350 extattr_arg arg;
351 arg.path = path;
352 return bsd_attr_list(0, arg, list, size);
353 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
354 return irix_attr_list(path, 0, list, size, 0);
355 #elif defined(HAVE_ATTROPEN)
356 ssize_t ret = -1;
357 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
358 if (attrdirfd >= 0) {
359 ret = solaris_list_xattr(attrdirfd, list, size);
360 close(attrdirfd);
362 return ret;
363 #else
364 errno = ENOSYS;
365 return -1;
366 #endif
369 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
371 #if defined(HAVE_FLISTXATTR)
372 #ifndef XATTR_ADDITIONAL_OPTIONS
373 return flistxattr(filedes, list, size);
374 #else
375 /* So that we do not recursivly call this function */
376 #undef flistxattr
377 int options = 0;
378 return flistxattr(filedes, list, size, options);
379 #endif
380 #elif defined(HAVE_FLISTEA)
381 return flistea(filedes, list, size);
382 #elif defined(HAVE_EXTATTR_LIST_FD)
383 extattr_arg arg;
384 arg.filedes = filedes;
385 return bsd_attr_list(2, arg, list, size);
386 #elif defined(HAVE_ATTR_LISTF)
387 return irix_attr_list(NULL, filedes, list, size, 0);
388 #elif defined(HAVE_ATTROPEN)
389 ssize_t ret = -1;
390 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
391 if (attrdirfd >= 0) {
392 ret = solaris_list_xattr(attrdirfd, list, size);
393 close(attrdirfd);
395 return ret;
396 #else
397 errno = ENOSYS;
398 return -1;
399 #endif
402 int rep_removexattr (const char *path, const char *name)
404 #if defined(HAVE_REMOVEXATTR)
405 #ifndef XATTR_ADDITIONAL_OPTIONS
406 return removexattr(path, name);
407 #else
408 /* So that we do not recursivly call this function */
409 #undef removexattr
410 int options = 0;
411 return removexattr(path, name, options);
412 #endif
413 #elif defined(HAVE_REMOVEEA)
414 return removeea(path, name);
415 #elif defined(HAVE_EXTATTR_DELETE_FILE)
416 char *s;
417 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
418 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
419 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
421 return extattr_delete_file(path, attrnamespace, attrname);
422 #elif defined(HAVE_ATTR_REMOVE)
423 int flags = 0;
424 char *attrname = strchr(name,'.') + 1;
426 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
428 return attr_remove(path, attrname, flags);
429 #elif defined(HAVE_ATTROPEN)
430 int ret = -1;
431 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
432 if (attrdirfd >= 0) {
433 ret = solaris_unlinkat(attrdirfd, name);
434 close(attrdirfd);
436 return ret;
437 #else
438 errno = ENOSYS;
439 return -1;
440 #endif
443 int rep_fremovexattr (int filedes, const char *name)
445 #if defined(HAVE_FREMOVEXATTR)
446 #ifndef XATTR_ADDITIONAL_OPTIONS
447 return fremovexattr(filedes, name);
448 #else
449 /* So that we do not recursivly call this function */
450 #undef fremovexattr
451 int options = 0;
452 return fremovexattr(filedes, name, options);
453 #endif
454 #elif defined(HAVE_FREMOVEEA)
455 return fremoveea(filedes, name);
456 #elif defined(HAVE_EXTATTR_DELETE_FD)
457 char *s;
458 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
459 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
460 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
462 return extattr_delete_fd(filedes, attrnamespace, attrname);
463 #elif defined(HAVE_ATTR_REMOVEF)
464 int flags = 0;
465 char *attrname = strchr(name,'.') + 1;
467 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
469 return attr_removef(filedes, attrname, flags);
470 #elif defined(HAVE_ATTROPEN)
471 int ret = -1;
472 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
473 if (attrdirfd >= 0) {
474 ret = solaris_unlinkat(attrdirfd, name);
475 close(attrdirfd);
477 return ret;
478 #else
479 errno = ENOSYS;
480 return -1;
481 #endif
484 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
486 #if defined(HAVE_SETXATTR)
487 #ifndef XATTR_ADDITIONAL_OPTIONS
488 return setxattr(path, name, value, size, flags);
489 #else
490 /* So that we do not recursivly call this function */
491 #undef setxattr
492 int options = 0;
493 return setxattr(path, name, value, size, 0, options);
494 #endif
495 #elif defined(HAVE_SETEA)
496 return setea(path, name, value, size, flags);
497 #elif defined(HAVE_EXTATTR_SET_FILE)
498 char *s;
499 int retval = 0;
500 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
501 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
502 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
503 if (flags) {
504 /* Check attribute existence */
505 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
506 if (retval < 0) {
507 /* REPLACE attribute, that doesn't exist */
508 if (flags & XATTR_REPLACE && errno == ENOATTR) {
509 errno = ENOATTR;
510 return -1;
512 /* Ignore other errors */
514 else {
515 /* CREATE attribute, that already exists */
516 if (flags & XATTR_CREATE) {
517 errno = EEXIST;
518 return -1;
522 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
523 return (retval < 0) ? -1 : 0;
524 #elif defined(HAVE_ATTR_SET)
525 int myflags = 0;
526 char *attrname = strchr(name,'.') + 1;
528 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
529 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
530 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
532 return attr_set(path, attrname, (const char *)value, size, myflags);
533 #elif defined(HAVE_ATTROPEN)
534 int ret = -1;
535 int myflags = O_RDWR;
536 int attrfd;
537 if (flags & XATTR_CREATE) myflags |= O_EXCL;
538 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
539 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
540 if (attrfd >= 0) {
541 ret = solaris_write_xattr(attrfd, value, size);
542 close(attrfd);
544 return ret;
545 #else
546 errno = ENOSYS;
547 return -1;
548 #endif
551 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
553 #if defined(HAVE_FSETXATTR)
554 #ifndef XATTR_ADDITIONAL_OPTIONS
555 return fsetxattr(filedes, name, value, size, flags);
556 #else
557 /* So that we do not recursivly call this function */
558 #undef fsetxattr
559 int options = 0;
560 return fsetxattr(filedes, name, value, size, 0, options);
561 #endif
562 #elif defined(HAVE_FSETEA)
563 return fsetea(filedes, name, value, size, flags);
564 #elif defined(HAVE_EXTATTR_SET_FD)
565 char *s;
566 int retval = 0;
567 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
568 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
569 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
570 if (flags) {
571 /* Check attribute existence */
572 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
573 if (retval < 0) {
574 /* REPLACE attribute, that doesn't exist */
575 if (flags & XATTR_REPLACE && errno == ENOATTR) {
576 errno = ENOATTR;
577 return -1;
579 /* Ignore other errors */
581 else {
582 /* CREATE attribute, that already exists */
583 if (flags & XATTR_CREATE) {
584 errno = EEXIST;
585 return -1;
589 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
590 return (retval < 0) ? -1 : 0;
591 #elif defined(HAVE_ATTR_SETF)
592 int myflags = 0;
593 char *attrname = strchr(name,'.') + 1;
595 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
596 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
597 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
599 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
600 #elif defined(HAVE_ATTROPEN)
601 int ret = -1;
602 int myflags = O_RDWR | O_XATTR;
603 int attrfd;
604 if (flags & XATTR_CREATE) myflags |= O_EXCL;
605 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
606 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
607 if (attrfd >= 0) {
608 ret = solaris_write_xattr(attrfd, value, size);
609 close(attrfd);
611 return ret;
612 #else
613 errno = ENOSYS;
614 return -1;
615 #endif
618 /**************************************************************************
619 helper functions for Solaris' EA support
620 ****************************************************************************/
621 #ifdef HAVE_ATTROPEN
622 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
624 struct stat sbuf;
626 if (fstat(attrfd, &sbuf) == -1) {
627 errno = ENOATTR;
628 return -1;
631 /* This is to return the current size of the named extended attribute */
632 if (size == 0) {
633 return sbuf.st_size;
636 /* check size and read xattr */
637 if (sbuf.st_size > size) {
638 errno = ERANGE;
639 return -1;
642 return read(attrfd, value, sbuf.st_size);
645 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
647 ssize_t len = 0;
648 DIR *dirp;
649 struct dirent *de;
650 int newfd = dup(attrdirfd);
651 /* CAUTION: The originating file descriptor should not be
652 used again following the call to fdopendir().
653 For that reason we dup() the file descriptor
654 here to make things more clear. */
655 dirp = fdopendir(newfd);
657 while ((de = readdir(dirp))) {
658 size_t listlen = strlen(de->d_name) + 1;
659 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
660 /* we don't want "." and ".." here: */
661 continue;
664 if (size == 0) {
665 /* return the current size of the list of extended attribute names*/
666 len += listlen;
667 } else {
668 /* check size and copy entrieѕ + nul into list. */
669 if ((len + listlen) > size) {
670 errno = ERANGE;
671 len = -1;
672 break;
673 } else {
674 strlcpy(list + len, de->d_name, listlen);
675 len += listlen;
680 if (closedir(dirp) == -1) {
681 return -1;
683 return len;
686 static int solaris_unlinkat(int attrdirfd, const char *name)
688 if (unlinkat(attrdirfd, name, 0) == -1) {
689 if (errno == ENOENT) {
690 errno = ENOATTR;
692 return -1;
694 return 0;
697 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
699 int filedes = attropen(path, attrpath, oflag, mode);
700 if (filedes == -1) {
701 if (errno == EINVAL) {
702 errno = ENOTSUP;
703 } else {
704 errno = ENOATTR;
707 return filedes;
710 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
712 int filedes = openat(fildes, path, oflag, mode);
713 if (filedes == -1) {
714 if (errno == EINVAL) {
715 errno = ENOTSUP;
716 } else {
717 errno = ENOATTR;
720 return filedes;
723 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
725 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
726 return 0;
727 } else {
728 return -1;
731 #endif /*HAVE_ATTROPEN*/