Fix bug # 9666 - Broken filtering of link-local addresses.
[Samba/gbeck.git] / lib / replace / xattr.c
bloba26ff674a13824bd9948a8949dc79e0e28905c60
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 switch(type) {
198 #if defined(HAVE_EXTATTR_LIST_FILE)
199 case 0:
200 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
201 break;
202 #endif
203 #if defined(HAVE_EXTATTR_LIST_LINK)
204 case 1:
205 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
206 break;
207 #endif
208 #if defined(HAVE_EXTATTR_LIST_FD)
209 case 2:
210 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
211 break;
212 #endif
213 default:
214 errno = ENOSYS;
215 return -1;
217 /* Some error happend. Errno should be set by the previous call */
218 if(list_size < 0)
219 return -1;
220 /* No attributes */
221 if(list_size == 0)
222 continue;
223 /* XXX: Call with an empty buffer may be used to calculate
224 necessary buffer size. Unfortunately, we can't say, how
225 many attributes were returned, so here is the potential
226 problem with the emulation.
228 if(list == NULL) {
229 /* Take the worse case of one char attribute names -
230 two bytes per name plus one more for sanity.
232 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
233 continue;
235 /* Count necessary offset to fit namespace prefixes */
236 len = 0;
237 for(i = 0; i < list_size; i += list[i] + 1)
238 len += extattr[t].len;
240 total_size += list_size + len;
241 /* Buffer is too small to fit the results */
242 if(total_size > size) {
243 errno = ERANGE;
244 return -1;
246 /* Shift results back, so we can prepend prefixes */
247 buf = (char *)memmove(list + len, list, list_size);
249 for(i = 0; i < list_size; i += len + 1) {
250 len = buf[i];
251 strncpy(list, extattr[t].name, extattr[t].len + 1);
252 list += extattr[t].len;
253 strncpy(list, buf + i + 1, len);
254 list[len] = '\0';
255 list += len + 1;
257 size -= total_size;
259 return total_size;
262 #endif
264 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
265 static char attr_buffer[ATTR_MAX_VALUELEN];
267 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
269 int retval = 0, index;
270 attrlist_cursor_t *cursor = 0;
271 int total_size = 0;
272 attrlist_t * al = (attrlist_t *)attr_buffer;
273 attrlist_ent_t *ae;
274 size_t ent_size, left = size;
275 char *bp = list;
277 while (true) {
278 if (filedes)
279 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
280 else
281 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
282 if (retval) break;
283 for (index = 0; index < al->al_count; index++) {
284 ae = ATTR_ENTRY(attr_buffer, index);
285 ent_size = strlen(ae->a_name) + sizeof("user.");
286 if (left >= ent_size) {
287 strncpy(bp, "user.", sizeof("user."));
288 strncat(bp, ae->a_name, ent_size - sizeof("user."));
289 bp += ent_size;
290 left -= ent_size;
291 } else if (size) {
292 errno = ERANGE;
293 retval = -1;
294 break;
296 total_size += ent_size;
298 if (al->al_more == 0) break;
300 if (retval == 0) {
301 flags |= ATTR_ROOT;
302 cursor = 0;
303 while (true) {
304 if (filedes)
305 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
306 else
307 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
308 if (retval) break;
309 for (index = 0; index < al->al_count; index++) {
310 ae = ATTR_ENTRY(attr_buffer, index);
311 ent_size = strlen(ae->a_name) + sizeof("system.");
312 if (left >= ent_size) {
313 strncpy(bp, "system.", sizeof("system."));
314 strncat(bp, ae->a_name, ent_size - sizeof("system."));
315 bp += ent_size;
316 left -= ent_size;
317 } else if (size) {
318 errno = ERANGE;
319 retval = -1;
320 break;
322 total_size += ent_size;
324 if (al->al_more == 0) break;
327 return (ssize_t)(retval ? retval : total_size);
330 #endif
332 ssize_t rep_listxattr (const char *path, char *list, size_t size)
334 #if defined(HAVE_LISTXATTR)
335 #ifndef XATTR_ADDITIONAL_OPTIONS
336 return listxattr(path, list, size);
337 #else
338 /* So that we do not recursivly call this function */
339 #undef listxattr
340 int options = 0;
341 return listxattr(path, list, size, options);
342 #endif
343 #elif defined(HAVE_LISTEA)
344 return listea(path, list, size);
345 #elif defined(HAVE_EXTATTR_LIST_FILE)
346 extattr_arg arg;
347 arg.path = path;
348 return bsd_attr_list(0, arg, list, size);
349 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
350 return irix_attr_list(path, 0, list, size, 0);
351 #elif defined(HAVE_ATTROPEN)
352 ssize_t ret = -1;
353 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
354 if (attrdirfd >= 0) {
355 ret = solaris_list_xattr(attrdirfd, list, size);
356 close(attrdirfd);
358 return ret;
359 #else
360 errno = ENOSYS;
361 return -1;
362 #endif
365 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
367 #if defined(HAVE_FLISTXATTR)
368 #ifndef XATTR_ADDITIONAL_OPTIONS
369 return flistxattr(filedes, list, size);
370 #else
371 /* So that we do not recursivly call this function */
372 #undef flistxattr
373 int options = 0;
374 return flistxattr(filedes, list, size, options);
375 #endif
376 #elif defined(HAVE_FLISTEA)
377 return flistea(filedes, list, size);
378 #elif defined(HAVE_EXTATTR_LIST_FD)
379 extattr_arg arg;
380 arg.filedes = filedes;
381 return bsd_attr_list(2, arg, list, size);
382 #elif defined(HAVE_ATTR_LISTF)
383 return irix_attr_list(NULL, filedes, list, size, 0);
384 #elif defined(HAVE_ATTROPEN)
385 ssize_t ret = -1;
386 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
387 if (attrdirfd >= 0) {
388 ret = solaris_list_xattr(attrdirfd, list, size);
389 close(attrdirfd);
391 return ret;
392 #else
393 errno = ENOSYS;
394 return -1;
395 #endif
398 int rep_removexattr (const char *path, const char *name)
400 #if defined(HAVE_REMOVEXATTR)
401 #ifndef XATTR_ADDITIONAL_OPTIONS
402 return removexattr(path, name);
403 #else
404 /* So that we do not recursivly call this function */
405 #undef removexattr
406 int options = 0;
407 return removexattr(path, name, options);
408 #endif
409 #elif defined(HAVE_REMOVEEA)
410 return removeea(path, name);
411 #elif defined(HAVE_EXTATTR_DELETE_FILE)
412 char *s;
413 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
414 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
415 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
417 return extattr_delete_file(path, attrnamespace, attrname);
418 #elif defined(HAVE_ATTR_REMOVE)
419 int flags = 0;
420 char *attrname = strchr(name,'.') + 1;
422 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
424 return attr_remove(path, attrname, flags);
425 #elif defined(HAVE_ATTROPEN)
426 int ret = -1;
427 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
428 if (attrdirfd >= 0) {
429 ret = solaris_unlinkat(attrdirfd, name);
430 close(attrdirfd);
432 return ret;
433 #else
434 errno = ENOSYS;
435 return -1;
436 #endif
439 int rep_fremovexattr (int filedes, const char *name)
441 #if defined(HAVE_FREMOVEXATTR)
442 #ifndef XATTR_ADDITIONAL_OPTIONS
443 return fremovexattr(filedes, name);
444 #else
445 /* So that we do not recursivly call this function */
446 #undef fremovexattr
447 int options = 0;
448 return fremovexattr(filedes, name, options);
449 #endif
450 #elif defined(HAVE_FREMOVEEA)
451 return fremoveea(filedes, name);
452 #elif defined(HAVE_EXTATTR_DELETE_FD)
453 char *s;
454 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
455 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
456 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
458 return extattr_delete_fd(filedes, attrnamespace, attrname);
459 #elif defined(HAVE_ATTR_REMOVEF)
460 int flags = 0;
461 char *attrname = strchr(name,'.') + 1;
463 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
465 return attr_removef(filedes, attrname, flags);
466 #elif defined(HAVE_ATTROPEN)
467 int ret = -1;
468 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
469 if (attrdirfd >= 0) {
470 ret = solaris_unlinkat(attrdirfd, name);
471 close(attrdirfd);
473 return ret;
474 #else
475 errno = ENOSYS;
476 return -1;
477 #endif
480 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
482 #if defined(HAVE_SETXATTR)
483 #ifndef XATTR_ADDITIONAL_OPTIONS
484 return setxattr(path, name, value, size, flags);
485 #else
486 /* So that we do not recursivly call this function */
487 #undef setxattr
488 int options = 0;
489 return setxattr(path, name, value, size, 0, options);
490 #endif
491 #elif defined(HAVE_SETEA)
492 return setea(path, name, value, size, flags);
493 #elif defined(HAVE_EXTATTR_SET_FILE)
494 char *s;
495 int retval = 0;
496 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
497 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
498 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
499 if (flags) {
500 /* Check attribute existence */
501 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
502 if (retval < 0) {
503 /* REPLACE attribute, that doesn't exist */
504 if (flags & XATTR_REPLACE && errno == ENOATTR) {
505 errno = ENOATTR;
506 return -1;
508 /* Ignore other errors */
510 else {
511 /* CREATE attribute, that already exists */
512 if (flags & XATTR_CREATE) {
513 errno = EEXIST;
514 return -1;
518 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
519 return (retval < 0) ? -1 : 0;
520 #elif defined(HAVE_ATTR_SET)
521 int myflags = 0;
522 char *attrname = strchr(name,'.') + 1;
524 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
525 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
526 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
528 return attr_set(path, attrname, (const char *)value, size, myflags);
529 #elif defined(HAVE_ATTROPEN)
530 int ret = -1;
531 int myflags = O_RDWR;
532 int attrfd;
533 if (flags & XATTR_CREATE) myflags |= O_EXCL;
534 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
535 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
536 if (attrfd >= 0) {
537 ret = solaris_write_xattr(attrfd, value, size);
538 close(attrfd);
540 return ret;
541 #else
542 errno = ENOSYS;
543 return -1;
544 #endif
547 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
549 #if defined(HAVE_FSETXATTR)
550 #ifndef XATTR_ADDITIONAL_OPTIONS
551 return fsetxattr(filedes, name, value, size, flags);
552 #else
553 /* So that we do not recursivly call this function */
554 #undef fsetxattr
555 int options = 0;
556 return fsetxattr(filedes, name, value, size, 0, options);
557 #endif
558 #elif defined(HAVE_FSETEA)
559 return fsetea(filedes, name, value, size, flags);
560 #elif defined(HAVE_EXTATTR_SET_FD)
561 char *s;
562 int retval = 0;
563 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
564 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
565 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
566 if (flags) {
567 /* Check attribute existence */
568 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
569 if (retval < 0) {
570 /* REPLACE attribute, that doesn't exist */
571 if (flags & XATTR_REPLACE && errno == ENOATTR) {
572 errno = ENOATTR;
573 return -1;
575 /* Ignore other errors */
577 else {
578 /* CREATE attribute, that already exists */
579 if (flags & XATTR_CREATE) {
580 errno = EEXIST;
581 return -1;
585 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
586 return (retval < 0) ? -1 : 0;
587 #elif defined(HAVE_ATTR_SETF)
588 int myflags = 0;
589 char *attrname = strchr(name,'.') + 1;
591 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
592 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
593 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
595 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
596 #elif defined(HAVE_ATTROPEN)
597 int ret = -1;
598 int myflags = O_RDWR | O_XATTR;
599 int attrfd;
600 if (flags & XATTR_CREATE) myflags |= O_EXCL;
601 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
602 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
603 if (attrfd >= 0) {
604 ret = solaris_write_xattr(attrfd, value, size);
605 close(attrfd);
607 return ret;
608 #else
609 errno = ENOSYS;
610 return -1;
611 #endif
614 /**************************************************************************
615 helper functions for Solaris' EA support
616 ****************************************************************************/
617 #ifdef HAVE_ATTROPEN
618 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
620 struct stat sbuf;
622 if (fstat(attrfd, &sbuf) == -1) {
623 errno = ENOATTR;
624 return -1;
627 /* This is to return the current size of the named extended attribute */
628 if (size == 0) {
629 return sbuf.st_size;
632 /* check size and read xattr */
633 if (sbuf.st_size > size) {
634 errno = ERANGE;
635 return -1;
638 return read(attrfd, value, sbuf.st_size);
641 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
643 ssize_t len = 0;
644 DIR *dirp;
645 struct dirent *de;
646 int newfd = dup(attrdirfd);
647 /* CAUTION: The originating file descriptor should not be
648 used again following the call to fdopendir().
649 For that reason we dup() the file descriptor
650 here to make things more clear. */
651 dirp = fdopendir(newfd);
653 while ((de = readdir(dirp))) {
654 size_t listlen = strlen(de->d_name) + 1;
655 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
656 /* we don't want "." and ".." here: */
657 continue;
660 if (size == 0) {
661 /* return the current size of the list of extended attribute names*/
662 len += listlen;
663 } else {
664 /* check size and copy entrieѕ + nul into list. */
665 if ((len + listlen) > size) {
666 errno = ERANGE;
667 len = -1;
668 break;
669 } else {
670 strlcpy(list + len, de->d_name, listlen);
671 len += listlen;
676 if (closedir(dirp) == -1) {
677 return -1;
679 return len;
682 static int solaris_unlinkat(int attrdirfd, const char *name)
684 if (unlinkat(attrdirfd, name, 0) == -1) {
685 if (errno == ENOENT) {
686 errno = ENOATTR;
688 return -1;
690 return 0;
693 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
695 int filedes = attropen(path, attrpath, oflag, mode);
696 if (filedes == -1) {
697 if (errno == EINVAL) {
698 errno = ENOTSUP;
699 } else {
700 errno = ENOATTR;
703 return filedes;
706 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
708 int filedes = openat(fildes, path, oflag, mode);
709 if (filedes == -1) {
710 if (errno == EINVAL) {
711 errno = ENOTSUP;
712 } else {
713 errno = ENOATTR;
716 return filedes;
719 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
721 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
722 return 0;
723 } else {
724 return -1;
727 #endif /*HAVE_ATTROPEN*/