lib/param: Merge "Logging Options" section from source3/param
[Samba.git] / lib / replace / xattr.c
blob8e1c989a3d317cec90f962c5a14b45cd9f1b2f98
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(retval > size) {
75 errno = ERANGE;
76 return -1;
78 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
79 return retval;
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;
88 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
90 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
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);
100 return ret;
101 #else
102 errno = ENOSYS;
103 return -1;
104 #endif
107 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
109 #if defined(HAVE_FGETXATTR)
110 #ifndef XATTR_ADDITIONAL_OPTIONS
111 return fgetxattr(filedes, name, value, size);
112 #else
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;
128 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
129 if(retval > size) {
130 errno = ERANGE;
131 return -1;
133 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
134 return retval;
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;
143 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
145 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
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);
155 return ret;
156 #else
157 errno = ENOSYS;
158 return -1;
159 #endif
162 #if defined(HAVE_EXTATTR_LIST_FILE)
164 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
166 static struct {
167 int space;
168 const char *name;
169 size_t len;
171 extattr[] = {
172 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
173 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
176 typedef union {
177 const char *path;
178 int filedes;
179 } extattr_arg;
181 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
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;
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.
219 if(list == NULL) {
220 /* Take the worse case of one char attribute names -
221 two bytes per name plus one more for sanity.
223 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
224 continue;
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;
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;
237 /* Shift results back, so we can prepend prefixes */
238 buf = (char *)memmove(list + len, list, list_size);
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;
248 size -= total_size;
250 return total_size;
253 #endif
255 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
256 static char attr_buffer[ATTR_MAX_VALUELEN];
258 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
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;
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;
287 total_size += ent_size;
289 if (al->al_more == 0) break;
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;
313 total_size += ent_size;
315 if (al->al_more == 0) break;
318 return (ssize_t)(retval ? retval : total_size);
321 #endif
323 ssize_t rep_listxattr (const char *path, char *list, size_t size)
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);
349 return ret;
350 #else
351 errno = ENOSYS;
352 return -1;
353 #endif
356 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
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);
382 return ret;
383 #else
384 errno = ENOSYS;
385 return -1;
386 #endif
389 int rep_removexattr (const char *path, const char *name)
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;
408 return extattr_delete_file(path, attrnamespace, attrname);
409 #elif defined(HAVE_ATTR_REMOVE)
410 int flags = 0;
411 char *attrname = strchr(name,'.') + 1;
413 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
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);
423 return ret;
424 #else
425 errno = ENOSYS;
426 return -1;
427 #endif
430 int rep_fremovexattr (int filedes, const char *name)
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;
449 return extattr_delete_fd(filedes, attrnamespace, attrname);
450 #elif defined(HAVE_ATTR_REMOVEF)
451 int flags = 0;
452 char *attrname = strchr(name,'.') + 1;
454 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
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);
464 return ret;
465 #else
466 errno = ENOSYS;
467 return -1;
468 #endif
471 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
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;
499 /* Ignore other errors */
501 else {
502 /* CREATE attribute, that already exists */
503 if (flags & XATTR_CREATE) {
504 errno = EEXIST;
505 return -1;
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;
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;
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);
531 return ret;
532 #else
533 errno = ENOSYS;
534 return -1;
535 #endif
538 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
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;
566 /* Ignore other errors */
568 else {
569 /* CREATE attribute, that already exists */
570 if (flags & XATTR_CREATE) {
571 errno = EEXIST;
572 return -1;
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;
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;
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);
598 return ret;
599 #else
600 errno = ENOSYS;
601 return -1;
602 #endif
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)
611 struct stat sbuf;
613 if (fstat(attrfd, &sbuf) == -1) {
614 errno = ENOATTR;
615 return -1;
618 /* This is to return the current size of the named extended attribute */
619 if (size == 0) {
620 return sbuf.st_size;
623 /* check size and read xattr */
624 if (sbuf.st_size > size) {
625 errno = ERANGE;
626 return -1;
629 return read(attrfd, value, sbuf.st_size);
632 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
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);
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;
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;
667 if (closedir(dirp) == -1) {
668 return -1;
670 return len;
673 static int solaris_unlinkat(int attrdirfd, const char *name)
675 if (unlinkat(attrdirfd, name, 0) == -1) {
676 if (errno == ENOENT) {
677 errno = ENOATTR;
679 return -1;
681 return 0;
684 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
686 int filedes = attropen(path, attrpath, oflag, mode);
687 if (filedes == -1) {
688 if (errno == EINVAL) {
689 errno = ENOTSUP;
690 } else {
691 errno = ENOATTR;
694 return filedes;
697 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
699 int filedes = openat(fildes, path, 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_write_xattr(int attrfd, const char *value, size_t size)
712 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
713 return 0;
714 } else {
715 return -1;
718 #endif /*HAVE_ATTROPEN*/