CVE-2023-3961:s3: smbd: Remove the SMB_ASSERT() that crashes on bad pipenames.
[Samba.git] / lib / replace / xattr.c
blob1044942f4b9aec7759df36ec7f884c06a4bf1f50
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_XATTR_XATTR)
52 #ifndef XATTR_ADDITIONAL_OPTIONS
53 return getxattr(path, name, value, size);
54 #else
56 /* So that we do not recursively 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_XATTR_EA)
62 return getea(path, name, value, size);
63 #elif defined(HAVE_XATTR_EXTATTR)
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_XATTR_ATTR)
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_XATTR_XATTR)
126 #ifndef XATTR_ADDITIONAL_OPTIONS
127 return fgetxattr(filedes, name, value, size);
128 #else
130 /* So that we do not recursively 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_XATTR_EA)
136 return fgetea(filedes, name, value, size);
137 #elif defined(HAVE_XATTR_EXTATTR)
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_XATTR_ATTR)
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_XATTR_EXTATTR)
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, len;
214 size_t t;
215 char *buf;
216 /* Iterate through extattr(2) namespaces */
217 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
218 if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
219 /* ignore all but user namespace when we are not root, see bug 10247 */
220 continue;
222 switch(type) {
223 case 0:
224 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
225 break;
226 case 1:
227 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
228 break;
229 case 2:
230 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
231 break;
232 default:
233 errno = ENOSYS;
234 return -1;
236 /* Some error happend. Errno should be set by the previous call */
237 if(list_size < 0)
238 return -1;
239 /* No attributes */
240 if(list_size == 0)
241 continue;
242 /* XXX: Call with an empty buffer may be used to calculate
243 necessary buffer size. Unfortunately, we can't say, how
244 many attributes were returned, so here is the potential
245 problem with the emulation.
247 if(list == NULL) {
248 /* Take the worse case of one char attribute names -
249 two bytes per name plus one more for sanity.
251 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
252 continue;
254 /* Count necessary offset to fit namespace prefixes */
255 len = 0;
256 for(i = 0; i < list_size; i += list[i] + 1)
257 len += extattr[t].len;
259 total_size += list_size + len;
260 /* Buffer is too small to fit the results */
261 if(total_size > size) {
262 errno = ERANGE;
263 return -1;
265 /* Shift results back, so we can prepend prefixes */
266 buf = (char *)memmove(list + len, list, list_size);
268 for(i = 0; i < list_size; i += len + 1) {
269 len = buf[i];
272 * If for some reason we receive a truncated
273 * return from call to list xattrs the pascal
274 * string lengths will not be changed and
275 * therefore we must check that we're not
276 * reading garbage data or off end of array
278 if (len + i >= list_size) {
279 errno = ERANGE;
280 return -1;
282 strncpy(list, extattr[t].name, extattr[t].len + 1);
283 list += extattr[t].len;
284 strncpy(list, buf + i + 1, len);
285 list[len] = '\0';
286 list += len + 1;
288 size -= total_size;
290 return total_size;
293 #endif
295 #if defined(HAVE_XATTR_ATTR) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
296 static char attr_buffer[ATTR_MAX_VALUELEN];
298 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
300 int retval = 0, index;
301 attrlist_cursor_t *cursor = 0;
302 int total_size = 0;
303 attrlist_t * al = (attrlist_t *)attr_buffer;
304 attrlist_ent_t *ae;
305 size_t ent_size, left = size;
306 char *bp = list;
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("user.");
317 if (left >= ent_size) {
318 strncpy(bp, "user.", sizeof("user."));
319 strncat(bp, ae->a_name, ent_size - sizeof("user."));
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;
331 if (retval == 0) {
332 flags |= ATTR_ROOT;
333 cursor = 0;
334 while (true) {
335 if (filedes)
336 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
337 else
338 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
339 if (retval) break;
340 for (index = 0; index < al->al_count; index++) {
341 ae = ATTR_ENTRY(attr_buffer, index);
342 ent_size = strlen(ae->a_name) + sizeof("system.");
343 if (left >= ent_size) {
344 strncpy(bp, "system.", sizeof("system."));
345 strncat(bp, ae->a_name, ent_size - sizeof("system."));
346 bp += ent_size;
347 left -= ent_size;
348 } else if (size) {
349 errno = ERANGE;
350 retval = -1;
351 break;
353 total_size += ent_size;
355 if (al->al_more == 0) break;
358 return (ssize_t)(retval ? retval : total_size);
361 #endif
363 ssize_t rep_listxattr (const char *path, char *list, size_t size)
365 #if defined(HAVE_XATTR_XATTR)
366 #ifndef XATTR_ADDITIONAL_OPTIONS
367 return listxattr(path, list, size);
368 #else
369 /* So that we do not recursively call this function */
370 #undef listxattr
371 int options = 0;
372 return listxattr(path, list, size, options);
373 #endif
374 #elif defined(HAVE_XATTR_EA)
375 return listea(path, list, size);
376 #elif defined(HAVE_XATTR_EXTATTR)
377 extattr_arg arg;
378 arg.path = path;
379 return bsd_attr_list(0, arg, list, size);
380 #elif defined(HAVE_XATTR_ATTR) && defined(HAVE_SYS_ATTRIBUTES_H)
381 return irix_attr_list(path, 0, list, size, 0);
382 #elif defined(HAVE_ATTROPEN)
383 ssize_t ret = -1;
384 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
385 if (attrdirfd >= 0) {
386 ret = solaris_list_xattr(attrdirfd, list, size);
387 close(attrdirfd);
389 return ret;
390 #else
391 errno = ENOSYS;
392 return -1;
393 #endif
396 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
398 #if defined(HAVE_XATTR_XATTR)
399 #ifndef XATTR_ADDITIONAL_OPTIONS
400 return flistxattr(filedes, list, size);
401 #else
402 /* So that we do not recursively call this function */
403 #undef flistxattr
404 int options = 0;
405 return flistxattr(filedes, list, size, options);
406 #endif
407 #elif defined(HAVE_XATTR_EA)
408 return flistea(filedes, list, size);
409 #elif defined(HAVE_XATTR_EXTATTR)
410 extattr_arg arg;
411 arg.filedes = filedes;
412 return bsd_attr_list(2, arg, list, size);
413 #elif defined(HAVE_XATTR_ATTR)
414 return irix_attr_list(NULL, filedes, list, size, 0);
415 #elif defined(HAVE_ATTROPEN)
416 ssize_t ret = -1;
417 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
418 if (attrdirfd >= 0) {
419 ret = solaris_list_xattr(attrdirfd, list, size);
420 close(attrdirfd);
422 return ret;
423 #else
424 errno = ENOSYS;
425 return -1;
426 #endif
429 int rep_removexattr (const char *path, const char *name)
431 #if defined(HAVE_XATTR_XATTR)
432 #ifndef XATTR_ADDITIONAL_OPTIONS
433 return removexattr(path, name);
434 #else
435 /* So that we do not recursively call this function */
436 #undef removexattr
437 int options = 0;
438 return removexattr(path, name, options);
439 #endif
440 #elif defined(HAVE_XATTR_EA)
441 return removeea(path, name);
442 #elif defined(HAVE_XATTR_EXTATTR)
443 int attrnamespace;
444 const char *attrname;
446 if (strncmp(name, "system.", 7) == 0) {
447 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
448 attrname = name + 7;
449 } else if (strncmp(name, "user.", 5) == 0) {
450 attrnamespace = EXTATTR_NAMESPACE_USER;
451 attrname = name + 5;
452 } else {
453 errno = EINVAL;
454 return -1;
457 return extattr_delete_file(path, attrnamespace, attrname);
458 #elif defined(HAVE_XATTR_ATTR)
459 int flags = 0;
460 char *attrname = strchr(name,'.') + 1;
462 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
464 return attr_remove(path, attrname, flags);
465 #elif defined(HAVE_ATTROPEN)
466 int ret = -1;
467 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
468 if (attrdirfd >= 0) {
469 ret = solaris_unlinkat(attrdirfd, name);
470 close(attrdirfd);
472 return ret;
473 #else
474 errno = ENOSYS;
475 return -1;
476 #endif
479 int rep_fremovexattr (int filedes, const char *name)
481 #if defined(HAVE_XATTR_XATTR)
482 #ifndef XATTR_ADDITIONAL_OPTIONS
483 return fremovexattr(filedes, name);
484 #else
485 /* So that we do not recursively call this function */
486 #undef fremovexattr
487 int options = 0;
488 return fremovexattr(filedes, name, options);
489 #endif
490 #elif defined(HAVE_XATTR_EA)
491 return fremoveea(filedes, name);
492 #elif defined(HAVE_XATTR_EXTATTR)
493 int attrnamespace;
494 const char *attrname;
496 if (strncmp(name, "system.", 7) == 0) {
497 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
498 attrname = name + 7;
499 } else if (strncmp(name, "user.", 5) == 0) {
500 attrnamespace = EXTATTR_NAMESPACE_USER;
501 attrname = name + 5;
502 } else {
503 errno = EINVAL;
504 return -1;
507 return extattr_delete_fd(filedes, attrnamespace, attrname);
508 #elif defined(HAVE_XATTR_ATTR)
509 int flags = 0;
510 char *attrname = strchr(name,'.') + 1;
512 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
514 return attr_removef(filedes, attrname, flags);
515 #elif defined(HAVE_ATTROPEN)
516 int ret = -1;
517 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
518 if (attrdirfd >= 0) {
519 ret = solaris_unlinkat(attrdirfd, name);
520 close(attrdirfd);
522 return ret;
523 #else
524 errno = ENOSYS;
525 return -1;
526 #endif
529 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
531 int retval = -1;
532 #if defined(HAVE_XATTR_XATTR)
533 #ifndef XATTR_ADDITIONAL_OPTIONS
534 retval = setxattr(path, name, value, size, flags);
535 if (retval < 0) {
536 if (errno == ENOSPC || errno == E2BIG) {
537 errno = ENAMETOOLONG;
540 return retval;
541 #else
542 /* So that we do not recursively call this function */
543 #undef setxattr
544 retval = setxattr(path, name, value, size, 0, flags);
545 if (retval < 0) {
546 if (errno == E2BIG) {
547 errno = ENAMETOOLONG;
550 return retval;
551 #endif
552 #elif defined(HAVE_XATTR_EA)
553 if (flags) {
554 retval = getea(path, name, NULL, 0);
555 if (retval < 0) {
556 if (flags & XATTR_REPLACE && errno == ENOATTR) {
557 return -1;
559 } else {
560 if (flags & XATTR_CREATE) {
561 errno = EEXIST;
562 return -1;
566 retval = setea(path, name, value, size, 0);
567 return retval;
568 #elif defined(HAVE_XATTR_EXTATTR)
569 int attrnamespace;
570 const char *attrname;
572 if (strncmp(name, "system.", 7) == 0) {
573 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
574 attrname = name + 7;
575 } else if (strncmp(name, "user.", 5) == 0) {
576 attrnamespace = EXTATTR_NAMESPACE_USER;
577 attrname = name + 5;
578 } else {
579 errno = EINVAL;
580 return -1;
583 if (flags) {
584 /* Check attribute existence */
585 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
586 if (retval < 0) {
587 /* REPLACE attribute, that doesn't exist */
588 if (flags & XATTR_REPLACE && errno == ENOATTR) {
589 errno = ENOATTR;
590 return -1;
592 /* Ignore other errors */
594 else {
595 /* CREATE attribute, that already exists */
596 if (flags & XATTR_CREATE) {
597 errno = EEXIST;
598 return -1;
602 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
603 return (retval < 0) ? -1 : 0;
604 #elif defined(HAVE_XATTR_ATTR)
605 int myflags = 0;
606 char *attrname = strchr(name,'.') + 1;
608 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
609 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
610 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
612 retval = attr_set(path, attrname, (const char *)value, size, myflags);
613 if (retval < 0) {
614 if (errno == E2BIG) {
615 errno = ENAMETOOLONG;
618 return retval;
619 #elif defined(HAVE_ATTROPEN)
620 int myflags = O_RDWR;
621 int attrfd;
622 if (flags & XATTR_CREATE) myflags |= O_EXCL;
623 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
624 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
625 if (attrfd >= 0) {
626 retval = solaris_write_xattr(attrfd, value, size);
627 close(attrfd);
629 return retval;
630 #else
631 errno = ENOSYS;
632 return -1;
633 #endif
636 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
638 int retval = -1;
639 #if defined(HAVE_XATTR_XATTR)
640 #ifndef XATTR_ADDITIONAL_OPTIONS
641 retval = fsetxattr(filedes, name, value, size, flags);
642 if (retval < 0) {
643 if (errno == ENOSPC) {
644 errno = ENAMETOOLONG;
647 return retval;
648 #else
649 /* So that we do not recursively call this function */
650 #undef fsetxattr
651 retval = fsetxattr(filedes, name, value, size, 0, flags);
652 if (retval < 0) {
653 if (errno == E2BIG) {
654 errno = ENAMETOOLONG;
657 return retval;
658 #endif
659 #elif defined(HAVE_XATTR_EA)
660 if (flags) {
661 retval = fgetea(filedes, name, NULL, 0);
662 if (retval < 0) {
663 if (flags & XATTR_REPLACE && errno == ENOATTR) {
664 return -1;
666 } else {
667 if (flags & XATTR_CREATE) {
668 errno = EEXIST;
669 return -1;
673 retval = fsetea(filedes, name, value, size, 0);
674 return retval;
675 #elif defined(HAVE_XATTR_EXTATTR)
676 int attrnamespace;
677 const char *attrname;
679 if (strncmp(name, "system.", 7) == 0) {
680 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
681 attrname = name + 7;
682 } else if (strncmp(name, "user.", 5) == 0) {
683 attrnamespace = EXTATTR_NAMESPACE_USER;
684 attrname = name + 5;
685 } else {
686 errno = EINVAL;
687 return -1;
690 if (flags) {
691 /* Check attribute existence */
692 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
693 if (retval < 0) {
694 /* REPLACE attribute, that doesn't exist */
695 if (flags & XATTR_REPLACE && errno == ENOATTR) {
696 errno = ENOATTR;
697 return -1;
699 /* Ignore other errors */
701 else {
702 /* CREATE attribute, that already exists */
703 if (flags & XATTR_CREATE) {
704 errno = EEXIST;
705 return -1;
709 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
710 return (retval < 0) ? -1 : 0;
711 #elif defined(HAVE_XATTR_ATTR)
712 int myflags = 0;
713 char *attrname = strchr(name,'.') + 1;
715 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
716 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
717 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
719 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
720 #elif defined(HAVE_ATTROPEN)
721 int myflags = O_RDWR | O_XATTR;
722 int attrfd;
723 if (flags & XATTR_CREATE) myflags |= O_EXCL;
724 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
725 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
726 if (attrfd >= 0) {
727 retval = solaris_write_xattr(attrfd, value, size);
728 close(attrfd);
730 return retval;
731 #else
732 errno = ENOSYS;
733 return -1;
734 #endif
737 /**************************************************************************
738 helper functions for Solaris' EA support
739 ****************************************************************************/
740 #ifdef HAVE_ATTROPEN
741 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
743 struct stat sbuf;
745 if (fstat(attrfd, &sbuf) == -1) {
746 errno = ENOATTR;
747 return -1;
750 /* This is to return the current size of the named extended attribute */
751 if (size == 0) {
752 return sbuf.st_size;
755 /* check size and read xattr */
756 if (sbuf.st_size > size) {
757 errno = ERANGE;
758 return -1;
761 return read(attrfd, value, sbuf.st_size);
764 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
766 ssize_t len = 0;
767 DIR *dirp;
768 struct dirent *de;
769 int newfd = dup(attrdirfd);
770 /* CAUTION: The originating file descriptor should not be
771 used again following the call to fdopendir().
772 For that reason we dup() the file descriptor
773 here to make things more clear. */
774 dirp = fdopendir(newfd);
776 while ((de = readdir(dirp))) {
777 size_t listlen = strlen(de->d_name) + 1;
778 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
779 /* we don't want "." and ".." here: */
780 continue;
783 if (size == 0) {
784 /* return the current size of the list of extended attribute names*/
785 len += listlen;
786 } else {
787 /* check size and copy entrieѕ + nul into list. */
788 if ((len + listlen) > size) {
789 errno = ERANGE;
790 len = -1;
791 break;
792 } else {
793 strlcpy(list + len, de->d_name, listlen);
794 len += listlen;
799 if (closedir(dirp) == -1) {
800 return -1;
802 return len;
805 static int solaris_unlinkat(int attrdirfd, const char *name)
807 if (unlinkat(attrdirfd, name, 0) == -1) {
808 if (errno == ENOENT) {
809 errno = ENOATTR;
811 return -1;
813 return 0;
816 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
818 int filedes = attropen(path, attrpath, oflag, mode);
819 if (filedes == -1) {
820 if (errno == EINVAL) {
821 errno = ENOTSUP;
822 } else {
823 errno = ENOATTR;
826 return filedes;
829 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
831 int filedes = openat(fildes, path, oflag, mode);
832 if (filedes == -1) {
833 if (errno == EINVAL) {
834 errno = ENOTSUP;
835 } else {
836 errno = ENOATTR;
839 return filedes;
842 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
844 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
845 return 0;
846 } else {
847 return -1;
850 #endif /*HAVE_ATTROPEN*/