ldb: Add Doxygen docs for ldb_schema_attribute_set_override_handler
[sfrench/samba-autobuild/.git] / lib / replace / xattr.c
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
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_GETXATTR)
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_GETEA)
62         return getea(path, name, value, size);
63 #elif defined(HAVE_EXTATTR_GET_FILE)
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_ATTR_GET)
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_FGETXATTR)
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_FGETEA)
136         return fgetea(filedes, name, value, size);
137 #elif defined(HAVE_EXTATTR_GET_FD)
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_ATTR_GETF)
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_EXTATTR_LIST_FILE)
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 #if defined(HAVE_EXTATTR_LIST_FILE)
223                         case 0:
224                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
225                                 break;
226 #endif
227 #if defined(HAVE_EXTATTR_LIST_LINK)
228                         case 1:
229                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
230                                 break;
231 #endif
232 #if defined(HAVE_EXTATTR_LIST_FD)
233                         case 2:
234                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
235                                 break;
236 #endif
237                         default:
238                                 errno = ENOSYS;
239                                 return -1;
240                 }
241                 /* Some error happend. Errno should be set by the previous call */
242                 if(list_size < 0)
243                         return -1;
244                 /* No attributes */
245                 if(list_size == 0)
246                         continue;
247                 /* XXX: Call with an empty buffer may be used to calculate
248                    necessary buffer size. Unfortunately, we can't say, how
249                    many attributes were returned, so here is the potential
250                    problem with the emulation.
251                 */
252                 if(list == NULL) {
253                         /* Take the worse case of one char attribute names - 
254                            two bytes per name plus one more for sanity.
255                         */
256                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
257                         continue;
258                 }
259                 /* Count necessary offset to fit namespace prefixes */
260                 len = 0;
261                 for(i = 0; i < list_size; i += list[i] + 1)
262                         len += extattr[t].len;
263
264                 total_size += list_size + len;
265                 /* Buffer is too small to fit the results */
266                 if(total_size > size) {
267                         errno = ERANGE;
268                         return -1;
269                 }
270                 /* Shift results back, so we can prepend prefixes */
271                 buf = (char *)memmove(list + len, list, list_size);
272
273                 for(i = 0; i < list_size; i += len + 1) {
274                         len = buf[i];
275                         strncpy(list, extattr[t].name, extattr[t].len + 1);
276                         list += extattr[t].len;
277                         strncpy(list, buf + i + 1, len);
278                         list[len] = '\0';
279                         list += len + 1;
280                 }
281                 size -= total_size;
282         }
283         return total_size;
284 }
285
286 #endif
287
288 #if defined(HAVE_ATTR_LIST) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H))
289 static char attr_buffer[ATTR_MAX_VALUELEN];
290
291 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
292 {
293         int retval = 0, index;
294         attrlist_cursor_t *cursor = 0;
295         int total_size = 0;
296         attrlist_t * al = (attrlist_t *)attr_buffer;
297         attrlist_ent_t *ae;
298         size_t ent_size, left = size;
299         char *bp = list;
300
301         while (true) {
302             if (filedes)
303                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
304             else
305                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
306             if (retval) break;
307             for (index = 0; index < al->al_count; index++) {
308                 ae = ATTR_ENTRY(attr_buffer, index);
309                 ent_size = strlen(ae->a_name) + sizeof("user.");
310                 if (left >= ent_size) {
311                     strncpy(bp, "user.", sizeof("user."));
312                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
313                     bp += ent_size;
314                     left -= ent_size;
315                 } else if (size) {
316                     errno = ERANGE;
317                     retval = -1;
318                     break;
319                 }
320                 total_size += ent_size;
321             }
322             if (al->al_more == 0) break;
323         }
324         if (retval == 0) {
325             flags |= ATTR_ROOT;
326             cursor = 0;
327             while (true) {
328                 if (filedes)
329                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
330                 else
331                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
332                 if (retval) break;
333                 for (index = 0; index < al->al_count; index++) {
334                     ae = ATTR_ENTRY(attr_buffer, index);
335                     ent_size = strlen(ae->a_name) + sizeof("system.");
336                     if (left >= ent_size) {
337                         strncpy(bp, "system.", sizeof("system."));
338                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
339                         bp += ent_size;
340                         left -= ent_size;
341                     } else if (size) {
342                         errno = ERANGE;
343                         retval = -1;
344                         break;
345                     }
346                     total_size += ent_size;
347                 }
348                 if (al->al_more == 0) break;
349             }
350         }
351         return (ssize_t)(retval ? retval : total_size);
352 }
353
354 #endif
355
356 ssize_t rep_listxattr (const char *path, char *list, size_t size)
357 {
358 #if defined(HAVE_LISTXATTR)
359 #ifndef XATTR_ADDITIONAL_OPTIONS
360         return listxattr(path, list, size);
361 #else
362 /* So that we do not recursivly call this function */
363 #undef listxattr
364         int options = 0;
365         return listxattr(path, list, size, options);
366 #endif
367 #elif defined(HAVE_LISTEA)
368         return listea(path, list, size);
369 #elif defined(HAVE_EXTATTR_LIST_FILE)
370         extattr_arg arg;
371         arg.path = path;
372         return bsd_attr_list(0, arg, list, size);
373 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
374         return irix_attr_list(path, 0, list, size, 0);
375 #elif defined(HAVE_ATTROPEN)
376         ssize_t ret = -1;
377         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
378         if (attrdirfd >= 0) {
379                 ret = solaris_list_xattr(attrdirfd, list, size);
380                 close(attrdirfd);
381         }
382         return ret;
383 #else
384         errno = ENOSYS;
385         return -1;
386 #endif
387 }
388
389 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
390 {
391 #if defined(HAVE_FLISTXATTR)
392 #ifndef XATTR_ADDITIONAL_OPTIONS
393         return flistxattr(filedes, list, size);
394 #else
395 /* So that we do not recursivly call this function */
396 #undef flistxattr
397         int options = 0;
398         return flistxattr(filedes, list, size, options);
399 #endif
400 #elif defined(HAVE_FLISTEA)
401         return flistea(filedes, list, size);
402 #elif defined(HAVE_EXTATTR_LIST_FD)
403         extattr_arg arg;
404         arg.filedes = filedes;
405         return bsd_attr_list(2, arg, list, size);
406 #elif defined(HAVE_ATTR_LISTF)
407         return irix_attr_list(NULL, filedes, list, size, 0);
408 #elif defined(HAVE_ATTROPEN)
409         ssize_t ret = -1;
410         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
411         if (attrdirfd >= 0) {
412                 ret = solaris_list_xattr(attrdirfd, list, size);
413                 close(attrdirfd);
414         }
415         return ret;
416 #else
417         errno = ENOSYS;
418         return -1;
419 #endif
420 }
421
422 int rep_removexattr (const char *path, const char *name)
423 {
424 #if defined(HAVE_REMOVEXATTR)
425 #ifndef XATTR_ADDITIONAL_OPTIONS
426         return removexattr(path, name);
427 #else
428 /* So that we do not recursivly call this function */
429 #undef removexattr
430         int options = 0;
431         return removexattr(path, name, options);
432 #endif
433 #elif defined(HAVE_REMOVEEA)
434         return removeea(path, name);
435 #elif defined(HAVE_EXTATTR_DELETE_FILE)
436         int attrnamespace;
437         const char *attrname;
438
439         if (strncmp(name, "system.", 7) == 0) {
440                 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
441                 attrname = name + 7;
442         } else if (strncmp(name, "user.", 5) == 0) {
443                 attrnamespace = EXTATTR_NAMESPACE_USER;
444                 attrname = name + 5;
445         } else {
446                 errno = EINVAL;
447                 return -1;
448         }
449
450         return extattr_delete_file(path, attrnamespace, attrname);
451 #elif defined(HAVE_ATTR_REMOVE)
452         int flags = 0;
453         char *attrname = strchr(name,'.') + 1;
454
455         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
456
457         return attr_remove(path, attrname, flags);
458 #elif defined(HAVE_ATTROPEN)
459         int ret = -1;
460         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
461         if (attrdirfd >= 0) {
462                 ret = solaris_unlinkat(attrdirfd, name);
463                 close(attrdirfd);
464         }
465         return ret;
466 #else
467         errno = ENOSYS;
468         return -1;
469 #endif
470 }
471
472 int rep_fremovexattr (int filedes, const char *name)
473 {
474 #if defined(HAVE_FREMOVEXATTR)
475 #ifndef XATTR_ADDITIONAL_OPTIONS
476         return fremovexattr(filedes, name);
477 #else
478 /* So that we do not recursivly call this function */
479 #undef fremovexattr
480         int options = 0;
481         return fremovexattr(filedes, name, options);
482 #endif
483 #elif defined(HAVE_FREMOVEEA)
484         return fremoveea(filedes, name);
485 #elif defined(HAVE_EXTATTR_DELETE_FD)
486         int attrnamespace;
487         const char *attrname;
488
489         if (strncmp(name, "system.", 7) == 0) {
490                 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
491                 attrname = name + 7;
492         } else if (strncmp(name, "user.", 5) == 0) {
493                 attrnamespace = EXTATTR_NAMESPACE_USER;
494                 attrname = name + 5;
495         } else {
496                 errno = EINVAL;
497                 return -1;
498         }
499
500         return extattr_delete_fd(filedes, attrnamespace, attrname);
501 #elif defined(HAVE_ATTR_REMOVEF)
502         int flags = 0;
503         char *attrname = strchr(name,'.') + 1;
504
505         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
506
507         return attr_removef(filedes, attrname, flags);
508 #elif defined(HAVE_ATTROPEN)
509         int ret = -1;
510         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
511         if (attrdirfd >= 0) {
512                 ret = solaris_unlinkat(attrdirfd, name);
513                 close(attrdirfd);
514         }
515         return ret;
516 #else
517         errno = ENOSYS;
518         return -1;
519 #endif
520 }
521
522 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
523 {
524 #if defined(HAVE_SETXATTR)
525 #ifndef XATTR_ADDITIONAL_OPTIONS
526         return setxattr(path, name, value, size, flags);
527 #else
528 /* So that we do not recursivly call this function */
529 #undef setxattr
530         int options = 0;
531         return setxattr(path, name, value, size, 0, options);
532 #endif
533 #elif defined(HAVE_SETEA)
534         return setea(path, name, value, size, flags);
535 #elif defined(HAVE_EXTATTR_SET_FILE)
536         int retval = 0;
537         int attrnamespace;
538         const char *attrname;
539
540         if (strncmp(name, "system.", 7) == 0) {
541                 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
542                 attrname = name + 7;
543         } else if (strncmp(name, "user.", 5) == 0) {
544                 attrnamespace = EXTATTR_NAMESPACE_USER;
545                 attrname = name + 5;
546         } else {
547                 errno = EINVAL;
548                 return -1;
549         }
550
551         if (flags) {
552                 /* Check attribute existence */
553                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
554                 if (retval < 0) {
555                         /* REPLACE attribute, that doesn't exist */
556                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
557                                 errno = ENOATTR;
558                                 return -1;
559                         }
560                         /* Ignore other errors */
561                 }
562                 else {
563                         /* CREATE attribute, that already exists */
564                         if (flags & XATTR_CREATE) {
565                                 errno = EEXIST;
566                                 return -1;
567                         }
568                 }
569         }
570         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
571         return (retval < 0) ? -1 : 0;
572 #elif defined(HAVE_ATTR_SET)
573         int myflags = 0;
574         char *attrname = strchr(name,'.') + 1;
575
576         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
577         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
578         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
579
580         return attr_set(path, attrname, (const char *)value, size, myflags);
581 #elif defined(HAVE_ATTROPEN)
582         int ret = -1;
583         int myflags = O_RDWR;
584         int attrfd;
585         if (flags & XATTR_CREATE) myflags |= O_EXCL;
586         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
587         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
588         if (attrfd >= 0) {
589                 ret = solaris_write_xattr(attrfd, value, size);
590                 close(attrfd);
591         }
592         return ret;
593 #else
594         errno = ENOSYS;
595         return -1;
596 #endif
597 }
598
599 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
600 {
601 #if defined(HAVE_FSETXATTR)
602 #ifndef XATTR_ADDITIONAL_OPTIONS
603         return fsetxattr(filedes, name, value, size, flags);
604 #else
605 /* So that we do not recursivly call this function */
606 #undef fsetxattr
607         int options = 0;
608         return fsetxattr(filedes, name, value, size, 0, options);
609 #endif
610 #elif defined(HAVE_FSETEA)
611         return fsetea(filedes, name, value, size, flags);
612 #elif defined(HAVE_EXTATTR_SET_FD)
613         int retval = 0;
614         int attrnamespace;
615         const char *attrname;
616
617         if (strncmp(name, "system.", 7) == 0) {
618                 attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
619                 attrname = name + 7;
620         } else if (strncmp(name, "user.", 5) == 0) {
621                 attrnamespace = EXTATTR_NAMESPACE_USER;
622                 attrname = name + 5;
623         } else {
624                 errno = EINVAL;
625                 return -1;
626         }
627
628         if (flags) {
629                 /* Check attribute existence */
630                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
631                 if (retval < 0) {
632                         /* REPLACE attribute, that doesn't exist */
633                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
634                                 errno = ENOATTR;
635                                 return -1;
636                         }
637                         /* Ignore other errors */
638                 }
639                 else {
640                         /* CREATE attribute, that already exists */
641                         if (flags & XATTR_CREATE) {
642                                 errno = EEXIST;
643                                 return -1;
644                         }
645                 }
646         }
647         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
648         return (retval < 0) ? -1 : 0;
649 #elif defined(HAVE_ATTR_SETF)
650         int myflags = 0;
651         char *attrname = strchr(name,'.') + 1;
652
653         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
654         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
655         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
656
657         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
658 #elif defined(HAVE_ATTROPEN)
659         int ret = -1;
660         int myflags = O_RDWR | O_XATTR;
661         int attrfd;
662         if (flags & XATTR_CREATE) myflags |= O_EXCL;
663         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
664         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
665         if (attrfd >= 0) {
666                 ret = solaris_write_xattr(attrfd, value, size);
667                 close(attrfd);
668         }
669         return ret;
670 #else
671         errno = ENOSYS;
672         return -1;
673 #endif
674 }
675
676 /**************************************************************************
677  helper functions for Solaris' EA support
678 ****************************************************************************/
679 #ifdef HAVE_ATTROPEN
680 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
681 {
682         struct stat sbuf;
683
684         if (fstat(attrfd, &sbuf) == -1) {
685                 errno = ENOATTR;
686                 return -1;
687         }
688
689         /* This is to return the current size of the named extended attribute */
690         if (size == 0) {
691                 return sbuf.st_size;
692         }
693
694         /* check size and read xattr */
695         if (sbuf.st_size > size) {
696                 errno = ERANGE;
697                 return -1;
698         }
699
700         return read(attrfd, value, sbuf.st_size);
701 }
702
703 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
704 {
705         ssize_t len = 0;
706         DIR *dirp;
707         struct dirent *de;
708         int newfd = dup(attrdirfd);
709         /* CAUTION: The originating file descriptor should not be
710                     used again following the call to fdopendir().
711                     For that reason we dup() the file descriptor
712                     here to make things more clear. */
713         dirp = fdopendir(newfd);
714
715         while ((de = readdir(dirp))) {
716                 size_t listlen = strlen(de->d_name) + 1;
717                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
718                         /* we don't want "." and ".." here: */
719                         continue;
720                 }
721
722                 if (size == 0) {
723                         /* return the current size of the list of extended attribute names*/
724                         len += listlen;
725                 } else {
726                         /* check size and copy entrieŃ• + nul into list. */
727                         if ((len + listlen) > size) {
728                                 errno = ERANGE;
729                                 len = -1;
730                                 break;
731                         } else {
732                                 strlcpy(list + len, de->d_name, listlen);
733                                 len += listlen;
734                         }
735                 }
736         }
737
738         if (closedir(dirp) == -1) {
739                 return -1;
740         }
741         return len;
742 }
743
744 static int solaris_unlinkat(int attrdirfd, const char *name)
745 {
746         if (unlinkat(attrdirfd, name, 0) == -1) {
747                 if (errno == ENOENT) {
748                         errno = ENOATTR;
749                 }
750                 return -1;
751         }
752         return 0;
753 }
754
755 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
756 {
757         int filedes = attropen(path, attrpath, oflag, mode);
758         if (filedes == -1) {
759                 if (errno == EINVAL) {
760                         errno = ENOTSUP;
761                 } else {
762                         errno = ENOATTR;
763                 }
764         }
765         return filedes;
766 }
767
768 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
769 {
770         int filedes = openat(fildes, path, oflag, mode);
771         if (filedes == -1) {
772                 if (errno == EINVAL) {
773                         errno = ENOTSUP;
774                 } else {
775                         errno = ENOATTR;
776                 }
777         }
778         return filedes;
779 }
780
781 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
782 {
783         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
784                 return 0;
785         } else {
786                 return -1;
787         }
788 }
789 #endif /*HAVE_ATTROPEN*/
790
791