PY3: switch current build to use python3
[kamenim/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_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