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
f()6    Copyright (C) Bjoern Jacke    2006-2007
7    Copyright (C) Herb Lewis           2003
8    Copyright (C) Andrew Bartlett      2012
9 
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
13 
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.
18 
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.
23 
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/>.
26 */
27 
28 #define UID_WRAPPER_NOT_REPLACE
29 #include "replace.h"
30 #include "system/filesys.h"
31 #include "system/dir.h"
32 
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
43 
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 ****************************************************************************/
48 
49 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
50 {
51 #if defined(HAVE_XATTR_XATTR)
52 #ifndef XATTR_ADDITIONAL_OPTIONS
53 	return getxattr(path, name, value, size);
54 #else
55 
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_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;
67 
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;
77 	}
78 
79 	/*
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.
83 	 */
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;
90 		}
91 		if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
92 			return retval;
93 	}
94 
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;
100 
101 	if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
102 
103 	retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
104 	if (size == 0 && retval == -1 && errno == E2BIG) {
105 		return valuelength;
106 	}
107 
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);
115 	}
116 	return ret;
117 #else
118 	errno = ENOSYS;
119 	return -1;
120 #endif
121 }
122 
123 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
124 {
125 #if defined(HAVE_XATTR_XATTR)
126 #ifndef XATTR_ADDITIONAL_OPTIONS
127 	return fgetxattr(filedes, name, value, size);
128 #else
129 
130 /* So that we do not recursivly 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;
141 
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;
151 	}
152 
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;
159 		}
160 		if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
161 			return retval;
162 	}
163 
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;
169 
170 	if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
171 
172 	retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
173 	if (size == 0 && retval == -1 && errno == E2BIG) {
174 		return valuelength;
175 	}
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);
183 	}
184 	return ret;
185 #else
186 	errno = ENOSYS;
187 	return -1;
188 #endif
189 }
190 
191 #if defined(HAVE_XATTR_EXTATTR)
192 
193 #define EXTATTR_PREFIX(s)	(s), (sizeof((s))-1)
194 
195 static struct {
196         int space;
197 	const char *name;
198 	size_t len;
199 }
200 extattr[] = {
201 	{ EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
202         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
203 };
204 
205 typedef union {
206 	const char *path;
207 	int filedes;
208 } extattr_arg;
209 
210 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
211 {
212 	ssize_t list_size, total_size = 0;
213 	int i, t, len;
214 	char *buf;
215 	/* Iterate through extattr(2) namespaces */
216 	for(t = 0; t < ARRAY_SIZE(extattr); t++) {
217 		if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) {
218 			/* ignore all but user namespace when we are not root, see bug 10247 */
219 			continue;
220 		}
221 		switch(type) {
222 			case 0:
223 				list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
224 				break;
225 			case 1:
226 				list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
227 				break;
228 			case 2:
229 				list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
230 				break;
231 			default:
232 				errno = ENOSYS;
233 				return -1;
234 		}
235 		/* Some error happend. Errno should be set by the previous call */
236 		if(list_size < 0)
237 			return -1;
238 		/* No attributes */
239 		if(list_size == 0)
240 			continue;
241 		/* XXX: Call with an empty buffer may be used to calculate
242 		   necessary buffer size. Unfortunately, we can't say, how
243 		   many attributes were returned, so here is the potential
244 		   problem with the emulation.
245 		*/
246 		if(list == NULL) {
247 			/* Take the worse case of one char attribute names -
248 			   two bytes per name plus one more for sanity.
249 			*/
250 			total_size += list_size + (list_size/2 + 1)*extattr[t].len;
251 			continue;
252 		}
253 		/* Count necessary offset to fit namespace prefixes */
254 		len = 0;
255 		for(i = 0; i < list_size; i += list[i] + 1)
256 			len += extattr[t].len;
257 
258 		total_size += list_size + len;
259 		/* Buffer is too small to fit the results */
260 		if(total_size > size) {
261 			errno = ERANGE;
262 			return -1;
263 		}
264 		/* Shift results back, so we can prepend prefixes */
265 		buf = (char *)memmove(list + len, list, list_size);
266 
267 		for(i = 0; i < list_size; i += len + 1) {
268 			len = buf[i];
269 			strncpy(list, extattr[t].name, extattr[t].len + 1);
270 			list += extattr[t].len;
271 			strncpy(list, buf + i + 1, len);
272 			list[len] = '\0';
273 			list += len + 1;
274 		}
275 		size -= total_size;
276 	}
277 	return total_size;
278 }
279 
280 #endif
281 
282 #if defined(HAVE_XATTR_ATTR) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
283 static char attr_buffer[ATTR_MAX_VALUELEN];
284 
285 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
286 {
287 	int retval = 0, index;
288 	attrlist_cursor_t *cursor = 0;
289 	int total_size = 0;
290 	attrlist_t * al = (attrlist_t *)attr_buffer;
291 	attrlist_ent_t *ae;
292 	size_t ent_size, left = size;
293 	char *bp = list;
294 
295 	while (true) {
296 	    if (filedes)
297 		retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
298 	    else
299 		retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
300 	    if (retval) break;
301 	    for (index = 0; index < al->al_count; index++) {
302 		ae = ATTR_ENTRY(attr_buffer, index);
303 		ent_size = strlen(ae->a_name) + sizeof("user.");
304 		if (left >= ent_size) {
305 		    strncpy(bp, "user.", sizeof("user."));
306 		    strncat(bp, ae->a_name, ent_size - sizeof("user."));
307 		    bp += ent_size;
308 		    left -= ent_size;
309 		} else if (size) {
310 		    errno = ERANGE;
311 		    retval = -1;
312 		    break;
313 		}
314 		total_size += ent_size;
315 	    }
316 	    if (al->al_more == 0) break;
317 	}
318 	if (retval == 0) {
319 	    flags |= ATTR_ROOT;
320 	    cursor = 0;
321 	    while (true) {
322 		if (filedes)
323 		    retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
324 		else
325 		    retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
326 		if (retval) break;
327 		for (index = 0; index < al->al_count; index++) {
328 		    ae = ATTR_ENTRY(attr_buffer, index);
329 		    ent_size = strlen(ae->a_name) + sizeof("system.");
330 		    if (left >= ent_size) {
331 			strncpy(bp, "system.", sizeof("system."));
332 			strncat(bp, ae->a_name, ent_size - sizeof("system."));
333 			bp += ent_size;
334 			left -= ent_size;
335 		    } else if (size) {
336 			errno = ERANGE;
337 			retval = -1;
338 			break;
339 		    }
340 		    total_size += ent_size;
341 		}
342 		if (al->al_more == 0) break;
343 	    }
344 	}
345 	return (ssize_t)(retval ? retval : total_size);
346 }
347 
348 #endif
349 
350 ssize_t rep_listxattr (const char *path, char *list, size_t size)
351 {
352 #if defined(HAVE_XATTR_XATTR)
353 #ifndef XATTR_ADDITIONAL_OPTIONS
354 	return listxattr(path, list, size);
355 #else
356 /* So that we do not recursivly call this function */
357 #undef listxattr
358 	int options = 0;
359 	return listxattr(path, list, size, options);
360 #endif
361 #elif defined(HAVE_XATTR_EA)
362 	return listea(path, list, size);
363 #elif defined(HAVE_XATTR_EXTATTR)
364 	extattr_arg arg;
365 	arg.path = path;
366 	return bsd_attr_list(0, arg, list, size);
367 #elif defined(HAVE_XATTR_ATTR) && defined(HAVE_SYS_ATTRIBUTES_H)
368 	return irix_attr_list(path, 0, list, size, 0);
369 #elif defined(HAVE_ATTROPEN)
370 	ssize_t ret = -1;
371 	int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
372 	if (attrdirfd >= 0) {
373 		ret = solaris_list_xattr(attrdirfd, list, size);
374 		close(attrdirfd);
375 	}
376 	return ret;
377 #else
378 	errno = ENOSYS;
379 	return -1;
380 #endif
381 }
382 
383 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
384 {
385 #if defined(HAVE_XATTR_XATTR)
386 #ifndef XATTR_ADDITIONAL_OPTIONS
387 	return flistxattr(filedes, list, size);
388 #else
389 /* So that we do not recursivly call this function */
390 #undef flistxattr
391 	int options = 0;
392 	return flistxattr(filedes, list, size, options);
393 #endif
394 #elif defined(HAVE_XATTR_EA)
395 	return flistea(filedes, list, size);
396 #elif defined(HAVE_XATTR_EXTATTR)
397 	extattr_arg arg;
398 	arg.filedes = filedes;
399 	return bsd_attr_list(2, arg, list, size);
400 #elif defined(HAVE_XATTR_ATTR)
401 	return irix_attr_list(NULL, filedes, list, size, 0);
402 #elif defined(HAVE_ATTROPEN)
403 	ssize_t ret = -1;
404 	int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
405 	if (attrdirfd >= 0) {
406 		ret = solaris_list_xattr(attrdirfd, list, size);
407 		close(attrdirfd);
408 	}
409 	return ret;
410 #else
411 	errno = ENOSYS;
412 	return -1;
413 #endif
414 }
415 
416 int rep_removexattr (const char *path, const char *name)
417 {
418 #if defined(HAVE_XATTR_XATTR)
419 #ifndef XATTR_ADDITIONAL_OPTIONS
420 	return removexattr(path, name);
421 #else
422 /* So that we do not recursivly call this function */
423 #undef removexattr
424 	int options = 0;
425 	return removexattr(path, name, options);
426 #endif
427 #elif defined(HAVE_XATTR_EA)
428 	return removeea(path, name);
429 #elif defined(HAVE_XATTR_EXTATTR)
430 	int attrnamespace;
431 	const char *attrname;
432 
433 	if (strncmp(name, "system.", 7) == 0) {
434 		attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
435 		attrname = name + 7;
436 	} else if (strncmp(name, "user.", 5) == 0) {
437 		attrnamespace = EXTATTR_NAMESPACE_USER;
438 		attrname = name + 5;
439 	} else {
440 		errno = EINVAL;
441 		return -1;
442 	}
443 
444 	return extattr_delete_file(path, attrnamespace, attrname);
445 #elif defined(HAVE_XATTR_ATTR)
446 	int flags = 0;
447 	char *attrname = strchr(name,'.') + 1;
448 
449 	if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
450 
451 	return attr_remove(path, attrname, flags);
452 #elif defined(HAVE_ATTROPEN)
453 	int ret = -1;
454 	int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
455 	if (attrdirfd >= 0) {
456 		ret = solaris_unlinkat(attrdirfd, name);
457 		close(attrdirfd);
458 	}
459 	return ret;
460 #else
461 	errno = ENOSYS;
462 	return -1;
463 #endif
464 }
465 
466 int rep_fremovexattr (int filedes, const char *name)
467 {
468 #if defined(HAVE_XATTR_XATTR)
469 #ifndef XATTR_ADDITIONAL_OPTIONS
470 	return fremovexattr(filedes, name);
471 #else
472 /* So that we do not recursivly call this function */
473 #undef fremovexattr
474 	int options = 0;
475 	return fremovexattr(filedes, name, options);
476 #endif
477 #elif defined(HAVE_XATTR_EA)
478 	return fremoveea(filedes, name);
479 #elif defined(HAVE_XATTR_EXTATTR)
480 	int attrnamespace;
481 	const char *attrname;
482 
483 	if (strncmp(name, "system.", 7) == 0) {
484 		attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
485 		attrname = name + 7;
486 	} else if (strncmp(name, "user.", 5) == 0) {
487 		attrnamespace = EXTATTR_NAMESPACE_USER;
488 		attrname = name + 5;
489 	} else {
490 		errno = EINVAL;
491 		return -1;
492 	}
493 
494 	return extattr_delete_fd(filedes, attrnamespace, attrname);
495 #elif defined(HAVE_XATTR_ATTR)
496 	int flags = 0;
497 	char *attrname = strchr(name,'.') + 1;
498 
499 	if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
500 
501 	return attr_removef(filedes, attrname, flags);
502 #elif defined(HAVE_ATTROPEN)
503 	int ret = -1;
504 	int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
505 	if (attrdirfd >= 0) {
506 		ret = solaris_unlinkat(attrdirfd, name);
507 		close(attrdirfd);
508 	}
509 	return ret;
510 #else
511 	errno = ENOSYS;
512 	return -1;
513 #endif
514 }
515 
516 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
517 {
518 #if defined(HAVE_XATTR_XATTR)
519 #ifndef XATTR_ADDITIONAL_OPTIONS
520 	return setxattr(path, name, value, size, flags);
521 #else
522 /* So that we do not recursivly call this function */
523 #undef setxattr
524 	int options = 0;
525 	return setxattr(path, name, value, size, 0, options);
526 #endif
527 #elif defined(HAVE_XATTR_EA)
528 	return setea(path, name, value, size, flags);
529 #elif defined(HAVE_XATTR_EXTATTR)
530 	int retval = 0;
531 	int attrnamespace;
532 	const char *attrname;
533 
534 	if (strncmp(name, "system.", 7) == 0) {
535 		attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
536 		attrname = name + 7;
537 	} else if (strncmp(name, "user.", 5) == 0) {
538 		attrnamespace = EXTATTR_NAMESPACE_USER;
539 		attrname = name + 5;
540 	} else {
541 		errno = EINVAL;
542 		return -1;
543 	}
544 
545 	if (flags) {
546 		/* Check attribute existence */
547 		retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
548 		if (retval < 0) {
549 			/* REPLACE attribute, that doesn't exist */
550 			if (flags & XATTR_REPLACE && errno == ENOATTR) {
551 				errno = ENOATTR;
552 				return -1;
553 			}
554 			/* Ignore other errors */
555 		}
556 		else {
557 			/* CREATE attribute, that already exists */
558 			if (flags & XATTR_CREATE) {
559 				errno = EEXIST;
560 				return -1;
561 			}
562 		}
563 	}
564 	retval = extattr_set_file(path, attrnamespace, attrname, value, size);
565 	return (retval < 0) ? -1 : 0;
566 #elif defined(HAVE_XATTR_ATTR)
567 	int myflags = 0;
568 	char *attrname = strchr(name,'.') + 1;
569 
570 	if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
571 	if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
572 	if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
573 
574 	return attr_set(path, attrname, (const char *)value, size, myflags);
575 #elif defined(HAVE_ATTROPEN)
576 	int ret = -1;
577 	int myflags = O_RDWR;
578 	int attrfd;
579 	if (flags & XATTR_CREATE) myflags |= O_EXCL;
580 	if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
581 	attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
582 	if (attrfd >= 0) {
583 		ret = solaris_write_xattr(attrfd, value, size);
584 		close(attrfd);
585 	}
586 	return ret;
587 #else
588 	errno = ENOSYS;
589 	return -1;
590 #endif
591 }
592 
593 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
594 {
595 #if defined(HAVE_XATTR_XATTR)
596 #ifndef XATTR_ADDITIONAL_OPTIONS
597 	return fsetxattr(filedes, name, value, size, flags);
598 #else
599 /* So that we do not recursivly call this function */
600 #undef fsetxattr
601 	int options = 0;
602 	return fsetxattr(filedes, name, value, size, 0, options);
603 #endif
604 #elif defined(HAVE_XATTR_EA)
605 	return fsetea(filedes, name, value, size, flags);
606 #elif defined(HAVE_XATTR_EXTATTR)
607 	int retval = 0;
608 	int attrnamespace;
609 	const char *attrname;
610 
611 	if (strncmp(name, "system.", 7) == 0) {
612 		attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
613 		attrname = name + 7;
614 	} else if (strncmp(name, "user.", 5) == 0) {
615 		attrnamespace = EXTATTR_NAMESPACE_USER;
616 		attrname = name + 5;
617 	} else {
618 		errno = EINVAL;
619 		return -1;
620 	}
621 
622 	if (flags) {
623 		/* Check attribute existence */
624 		retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
625 		if (retval < 0) {
626 			/* REPLACE attribute, that doesn't exist */
627 			if (flags & XATTR_REPLACE && errno == ENOATTR) {
628 				errno = ENOATTR;
629 				return -1;
630 			}
631 			/* Ignore other errors */
632 		}
633 		else {
634 			/* CREATE attribute, that already exists */
635 			if (flags & XATTR_CREATE) {
636 				errno = EEXIST;
637 				return -1;
638 			}
639 		}
640 	}
641 	retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
642 	return (retval < 0) ? -1 : 0;
643 #elif defined(HAVE_XATTR_ATTR)
644 	int myflags = 0;
645 	char *attrname = strchr(name,'.') + 1;
646 
647 	if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
648 	if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
649 	if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
650 
651 	return attr_setf(filedes, attrname, (const char *)value, size, myflags);
652 #elif defined(HAVE_ATTROPEN)
653 	int ret = -1;
654 	int myflags = O_RDWR | O_XATTR;
655 	int attrfd;
656 	if (flags & XATTR_CREATE) myflags |= O_EXCL;
657 	if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
658 	attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
659 	if (attrfd >= 0) {
660 		ret = solaris_write_xattr(attrfd, value, size);
661 		close(attrfd);
662 	}
663 	return ret;
664 #else
665 	errno = ENOSYS;
666 	return -1;
667 #endif
668 }
669 
670 /**************************************************************************
671  helper functions for Solaris' EA support
672 ****************************************************************************/
673 #ifdef HAVE_ATTROPEN
674 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
675 {
676 	struct stat sbuf;
677 
678 	if (fstat(attrfd, &sbuf) == -1) {
679 		errno = ENOATTR;
680 		return -1;
681 	}
682 
683 	/* This is to return the current size of the named extended attribute */
684 	if (size == 0) {
685 		return sbuf.st_size;
686 	}
687 
688 	/* check size and read xattr */
689 	if (sbuf.st_size > size) {
690 		errno = ERANGE;
691 		return -1;
692 	}
693 
694 	return read(attrfd, value, sbuf.st_size);
695 }
696 
697 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
698 {
699 	ssize_t len = 0;
700 	DIR *dirp;
701 	struct dirent *de;
702 	int newfd = dup(attrdirfd);
703 	/* CAUTION: The originating file descriptor should not be
704 	            used again following the call to fdopendir().
705 	            For that reason we dup() the file descriptor
706 		    here to make things more clear. */
707 	dirp = fdopendir(newfd);
708 
709 	while ((de = readdir(dirp))) {
710 		size_t listlen = strlen(de->d_name) + 1;
711 		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
712 			/* we don't want "." and ".." here: */
713 			continue;
714 		}
715 
716 		if (size == 0) {
717 			/* return the current size of the list of extended attribute names*/
718 			len += listlen;
719 		} else {
720 			/* check size and copy entrieѕ + nul into list. */
721 			if ((len + listlen) > size) {
722 				errno = ERANGE;
723 				len = -1;
724 				break;
725 			} else {
726 				strlcpy(list + len, de->d_name, listlen);
727 				len += listlen;
728 			}
729 		}
730 	}
731 
732 	if (closedir(dirp) == -1) {
733 		return -1;
734 	}
735 	return len;
736 }
737 
738 static int solaris_unlinkat(int attrdirfd, const char *name)
739 {
740 	if (unlinkat(attrdirfd, name, 0) == -1) {
741 		if (errno == ENOENT) {
742 			errno = ENOATTR;
743 		}
744 		return -1;
745 	}
746 	return 0;
747 }
748 
749 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
750 {
751 	int filedes = attropen(path, attrpath, oflag, mode);
752 	if (filedes == -1) {
753 		if (errno == EINVAL) {
754 			errno = ENOTSUP;
755 		} else {
756 			errno = ENOATTR;
757 		}
758 	}
759 	return filedes;
760 }
761 
762 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
763 {
764 	int filedes = openat(fildes, path, oflag, mode);
765 	if (filedes == -1) {
766 		if (errno == EINVAL) {
767 			errno = ENOTSUP;
768 		} else {
769 			errno = ENOATTR;
770 		}
771 	}
772 	return filedes;
773 }
774 
775 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
776 {
777 	if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
778 		return 0;
779 	} else {
780 		return -1;
781 	}
782 }
783 #endif /*HAVE_ATTROPEN*/
784 
785 
786