libreplace: Use true rather than True in xattr.c
[nivanova/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
8      ** NOTE! The following LGPL license applies to the replace
9      ** library. This does NOT imply that all of Samba is released
10      ** under the LGPL
11    
12    This library is free software; you can redistribute it and/or
13    modify it under the terms of the GNU Lesser General Public
14    License as published by the Free Software Foundation; either
15    version 3 of the License, or (at your option) any later version.
16
17    This library is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20    Lesser General Public License for more details.
21
22    You should have received a copy of the GNU Lesser General Public
23    License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/dir.h"
29
30 /******** Solaris EA helper function prototypes ********/
31 #ifdef HAVE_ATTROPEN
32 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
33 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
34 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
35 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
36 static int solaris_unlinkat(int attrdirfd, const char *name);
37 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
38 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
39 #endif
40
41 /**************************************************************************
42  Wrappers for extented attribute calls. Based on the Linux package with
43  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
44 ****************************************************************************/
45
46 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
47 {
48 #if defined(HAVE_GETXATTR)
49 #ifndef XATTR_ADDITIONAL_OPTIONS
50         return getxattr(path, name, value, size);
51 #else
52         int options = 0;
53         return getxattr(path, name, value, size, 0, options);
54 #endif
55 #elif defined(HAVE_GETEA)
56         return getea(path, name, value, size);
57 #elif defined(HAVE_EXTATTR_GET_FILE)
58         char *s;
59         ssize_t retval;
60         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
61                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
62         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
63         /*
64          * The BSD implementation has a nasty habit of silently truncating
65          * the returned value to the size of the buffer, so we have to check
66          * that the buffer is large enough to fit the returned value.
67          */
68         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
69                 if(retval > size) {
70                         errno = ERANGE;
71                         return -1;
72                 }
73                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
74                         return retval;
75         }
76
77         return -1;
78 #elif defined(HAVE_ATTR_GET)
79         int retval, flags = 0;
80         int valuelength = (int)size;
81         char *attrname = strchr(name,'.') + 1;
82
83         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
84
85         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
86
87         return retval ? retval : valuelength;
88 #elif defined(HAVE_ATTROPEN)
89         ssize_t ret = -1;
90         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
91         if (attrfd >= 0) {
92                 ret = solaris_read_xattr(attrfd, value, size);
93                 close(attrfd);
94         }
95         return ret;
96 #else
97         errno = ENOSYS;
98         return -1;
99 #endif
100 }
101
102 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
103 {
104 #if defined(HAVE_FGETXATTR)
105 #ifndef XATTR_ADDITIONAL_OPTIONS
106         return fgetxattr(filedes, name, value, size);
107 #else
108         int options = 0;
109         return fgetxattr(filedes, name, value, size, 0, options);
110 #endif
111 #elif defined(HAVE_FGETEA)
112         return fgetea(filedes, name, value, size);
113 #elif defined(HAVE_EXTATTR_GET_FD)
114         char *s;
115         ssize_t retval;
116         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
117                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
118         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
119
120         if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
121                 if(retval > size) {
122                         errno = ERANGE;
123                         return -1;
124                 }
125                 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
126                         return retval;
127         }
128
129         return -1;
130 #elif defined(HAVE_ATTR_GETF)
131         int retval, flags = 0;
132         int valuelength = (int)size;
133         char *attrname = strchr(name,'.') + 1;
134
135         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
136
137         retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
138
139         return retval ? retval : valuelength;
140 #elif defined(HAVE_ATTROPEN)
141         ssize_t ret = -1;
142         int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
143         if (attrfd >= 0) {
144                 ret = solaris_read_xattr(attrfd, value, size);
145                 close(attrfd);
146         }
147         return ret;
148 #else
149         errno = ENOSYS;
150         return -1;
151 #endif
152 }
153
154 #if defined(HAVE_EXTATTR_LIST_FILE)
155
156 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
157
158 static struct {
159         int space;
160         const char *name;
161         size_t len;
162
163 extattr[] = {
164         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
165         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
166 };
167
168 typedef union {
169         const char *path;
170         int filedes;
171 } extattr_arg;
172
173 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
174 {
175         ssize_t list_size, total_size = 0;
176         int i, t, len;
177         char *buf;
178         /* Iterate through extattr(2) namespaces */
179         for(t = 0; t < ARRAY_SIZE(extattr); t++) {
180                 switch(type) {
181 #if defined(HAVE_EXTATTR_LIST_FILE)
182                         case 0:
183                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
184                                 break;
185 #endif
186 #if defined(HAVE_EXTATTR_LIST_LINK)
187                         case 1:
188                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
189                                 break;
190 #endif
191 #if defined(HAVE_EXTATTR_LIST_FD)
192                         case 2:
193                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
194                                 break;
195 #endif
196                         default:
197                                 errno = ENOSYS;
198                                 return -1;
199                 }
200                 /* Some error happend. Errno should be set by the previous call */
201                 if(list_size < 0)
202                         return -1;
203                 /* No attributes */
204                 if(list_size == 0)
205                         continue;
206                 /* XXX: Call with an empty buffer may be used to calculate
207                    necessary buffer size. Unfortunately, we can't say, how
208                    many attributes were returned, so here is the potential
209                    problem with the emulation.
210                 */
211                 if(list == NULL) {
212                         /* Take the worse case of one char attribute names - 
213                            two bytes per name plus one more for sanity.
214                         */
215                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
216                         continue;
217                 }
218                 /* Count necessary offset to fit namespace prefixes */
219                 len = 0;
220                 for(i = 0; i < list_size; i += list[i] + 1)
221                         len += extattr[t].len;
222
223                 total_size += list_size + len;
224                 /* Buffer is too small to fit the results */
225                 if(total_size > size) {
226                         errno = ERANGE;
227                         return -1;
228                 }
229                 /* Shift results back, so we can prepend prefixes */
230                 buf = (char *)memmove(list + len, list, list_size);
231
232                 for(i = 0; i < list_size; i += len + 1) {
233                         len = buf[i];
234                         strncpy(list, extattr[t].name, extattr[t].len + 1);
235                         list += extattr[t].len;
236                         strncpy(list, buf + i + 1, len);
237                         list[len] = '\0';
238                         list += len + 1;
239                 }
240                 size -= total_size;
241         }
242         return total_size;
243 }
244
245 #endif
246
247 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
248 static char attr_buffer[ATTR_MAX_VALUELEN];
249
250 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
251 {
252         int retval = 0, index;
253         attrlist_cursor_t *cursor = 0;
254         int total_size = 0;
255         attrlist_t * al = (attrlist_t *)attr_buffer;
256         attrlist_ent_t *ae;
257         size_t ent_size, left = size;
258         char *bp = list;
259
260         while (true) {
261             if (filedes)
262                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
263             else
264                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
265             if (retval) break;
266             for (index = 0; index < al->al_count; index++) {
267                 ae = ATTR_ENTRY(attr_buffer, index);
268                 ent_size = strlen(ae->a_name) + sizeof("user.");
269                 if (left >= ent_size) {
270                     strncpy(bp, "user.", sizeof("user."));
271                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
272                     bp += ent_size;
273                     left -= ent_size;
274                 } else if (size) {
275                     errno = ERANGE;
276                     retval = -1;
277                     break;
278                 }
279                 total_size += ent_size;
280             }
281             if (al->al_more == 0) break;
282         }
283         if (retval == 0) {
284             flags |= ATTR_ROOT;
285             cursor = 0;
286             while (true) {
287                 if (filedes)
288                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
289                 else
290                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
291                 if (retval) break;
292                 for (index = 0; index < al->al_count; index++) {
293                     ae = ATTR_ENTRY(attr_buffer, index);
294                     ent_size = strlen(ae->a_name) + sizeof("system.");
295                     if (left >= ent_size) {
296                         strncpy(bp, "system.", sizeof("system."));
297                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
298                         bp += ent_size;
299                         left -= ent_size;
300                     } else if (size) {
301                         errno = ERANGE;
302                         retval = -1;
303                         break;
304                     }
305                     total_size += ent_size;
306                 }
307                 if (al->al_more == 0) break;
308             }
309         }
310         return (ssize_t)(retval ? retval : total_size);
311 }
312
313 #endif
314
315 ssize_t rep_listxattr (const char *path, char *list, size_t size)
316 {
317 #if defined(HAVE_LISTXATTR)
318 #ifndef XATTR_ADDITIONAL_OPTIONS
319         return listxattr(path, list, size);
320 #else
321         int options = 0;
322         return listxattr(path, list, size, options);
323 #endif
324 #elif defined(HAVE_LISTEA)
325         return listea(path, list, size);
326 #elif defined(HAVE_EXTATTR_LIST_FILE)
327         extattr_arg arg;
328         arg.path = path;
329         return bsd_attr_list(0, arg, list, size);
330 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
331         return irix_attr_list(path, 0, list, size, 0);
332 #elif defined(HAVE_ATTROPEN)
333         ssize_t ret = -1;
334         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
335         if (attrdirfd >= 0) {
336                 ret = solaris_list_xattr(attrdirfd, list, size);
337                 close(attrdirfd);
338         }
339         return ret;
340 #else
341         errno = ENOSYS;
342         return -1;
343 #endif
344 }
345
346 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
347 {
348 #if defined(HAVE_FLISTXATTR)
349 #ifndef XATTR_ADDITIONAL_OPTIONS
350         return flistxattr(filedes, list, size);
351 #else
352         int options = 0;
353         return flistxattr(filedes, list, size, options);
354 #endif
355 #elif defined(HAVE_FLISTEA)
356         return flistea(filedes, list, size);
357 #elif defined(HAVE_EXTATTR_LIST_FD)
358         extattr_arg arg;
359         arg.filedes = filedes;
360         return bsd_attr_list(2, arg, list, size);
361 #elif defined(HAVE_ATTR_LISTF)
362         return irix_attr_list(NULL, filedes, list, size, 0);
363 #elif defined(HAVE_ATTROPEN)
364         ssize_t ret = -1;
365         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
366         if (attrdirfd >= 0) {
367                 ret = solaris_list_xattr(attrdirfd, list, size);
368                 close(attrdirfd);
369         }
370         return ret;
371 #else
372         errno = ENOSYS;
373         return -1;
374 #endif
375 }
376
377 int rep_removexattr (const char *path, const char *name)
378 {
379 #if defined(HAVE_REMOVEXATTR)
380 #ifndef XATTR_ADDITIONAL_OPTIONS
381         return removexattr(path, name);
382 #else
383         int options = 0;
384         return removexattr(path, name, options);
385 #endif
386 #elif defined(HAVE_REMOVEEA)
387         return removeea(path, name);
388 #elif defined(HAVE_EXTATTR_DELETE_FILE)
389         char *s;
390         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
391                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
392         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
393
394         return extattr_delete_file(path, attrnamespace, attrname);
395 #elif defined(HAVE_ATTR_REMOVE)
396         int flags = 0;
397         char *attrname = strchr(name,'.') + 1;
398
399         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
400
401         return attr_remove(path, attrname, flags);
402 #elif defined(HAVE_ATTROPEN)
403         int ret = -1;
404         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
405         if (attrdirfd >= 0) {
406                 ret = solaris_unlinkat(attrdirfd, name);
407                 close(attrdirfd);
408         }
409         return ret;
410 #else
411         errno = ENOSYS;
412         return -1;
413 #endif
414 }
415
416 int rep_fremovexattr (int filedes, const char *name)
417 {
418 #if defined(HAVE_FREMOVEXATTR)
419 #ifndef XATTR_ADDITIONAL_OPTIONS
420         return fremovexattr(filedes, name);
421 #else
422         int options = 0;
423         return fremovexattr(filedes, name, options);
424 #endif
425 #elif defined(HAVE_FREMOVEEA)
426         return fremoveea(filedes, name);
427 #elif defined(HAVE_EXTATTR_DELETE_FD)
428         char *s;
429         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
430                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
431         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
432
433         return extattr_delete_fd(filedes, attrnamespace, attrname);
434 #elif defined(HAVE_ATTR_REMOVEF)
435         int flags = 0;
436         char *attrname = strchr(name,'.') + 1;
437
438         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
439
440         return attr_removef(filedes, attrname, flags);
441 #elif defined(HAVE_ATTROPEN)
442         int ret = -1;
443         int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
444         if (attrdirfd >= 0) {
445                 ret = solaris_unlinkat(attrdirfd, name);
446                 close(attrdirfd);
447         }
448         return ret;
449 #else
450         errno = ENOSYS;
451         return -1;
452 #endif
453 }
454
455 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
456 {
457 #if defined(HAVE_SETXATTR)
458 #ifndef XATTR_ADDITIONAL_OPTIONS
459         return setxattr(path, name, value, size, flags);
460 #else
461         int options = 0;
462         return setxattr(path, name, value, size, 0, options);
463 #endif
464 #elif defined(HAVE_SETEA)
465         return setea(path, name, value, size, flags);
466 #elif defined(HAVE_EXTATTR_SET_FILE)
467         char *s;
468         int retval = 0;
469         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
470                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
471         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
472         if (flags) {
473                 /* Check attribute existence */
474                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
475                 if (retval < 0) {
476                         /* REPLACE attribute, that doesn't exist */
477                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
478                                 errno = ENOATTR;
479                                 return -1;
480                         }
481                         /* Ignore other errors */
482                 }
483                 else {
484                         /* CREATE attribute, that already exists */
485                         if (flags & XATTR_CREATE) {
486                                 errno = EEXIST;
487                                 return -1;
488                         }
489                 }
490         }
491         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
492         return (retval < 0) ? -1 : 0;
493 #elif defined(HAVE_ATTR_SET)
494         int myflags = 0;
495         char *attrname = strchr(name,'.') + 1;
496
497         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
498         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
499         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
500
501         return attr_set(path, attrname, (const char *)value, size, myflags);
502 #elif defined(HAVE_ATTROPEN)
503         int ret = -1;
504         int myflags = O_RDWR;
505         int attrfd;
506         if (flags & XATTR_CREATE) myflags |= O_EXCL;
507         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
508         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
509         if (attrfd >= 0) {
510                 ret = solaris_write_xattr(attrfd, value, size);
511                 close(attrfd);
512         }
513         return ret;
514 #else
515         errno = ENOSYS;
516         return -1;
517 #endif
518 }
519
520 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
521 {
522 #if defined(HAVE_FSETXATTR)
523 #ifndef XATTR_ADDITIONAL_OPTIONS
524         return fsetxattr(filedes, name, value, size, flags);
525 #else
526         int options = 0;
527         return fsetxattr(filedes, name, value, size, 0, options);
528 #endif
529 #elif defined(HAVE_FSETEA)
530         return fsetea(filedes, name, value, size, flags);
531 #elif defined(HAVE_EXTATTR_SET_FD)
532         char *s;
533         int retval = 0;
534         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
535                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
536         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
537         if (flags) {
538                 /* Check attribute existence */
539                 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
540                 if (retval < 0) {
541                         /* REPLACE attribute, that doesn't exist */
542                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
543                                 errno = ENOATTR;
544                                 return -1;
545                         }
546                         /* Ignore other errors */
547                 }
548                 else {
549                         /* CREATE attribute, that already exists */
550                         if (flags & XATTR_CREATE) {
551                                 errno = EEXIST;
552                                 return -1;
553                         }
554                 }
555         }
556         retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
557         return (retval < 0) ? -1 : 0;
558 #elif defined(HAVE_ATTR_SETF)
559         int myflags = 0;
560         char *attrname = strchr(name,'.') + 1;
561
562         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
563         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
564         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
565
566         return attr_setf(filedes, attrname, (const char *)value, size, myflags);
567 #elif defined(HAVE_ATTROPEN)
568         int ret = -1;
569         int myflags = O_RDWR | O_XATTR;
570         int attrfd;
571         if (flags & XATTR_CREATE) myflags |= O_EXCL;
572         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
573         attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
574         if (attrfd >= 0) {
575                 ret = solaris_write_xattr(attrfd, value, size);
576                 close(attrfd);
577         }
578         return ret;
579 #else
580         errno = ENOSYS;
581         return -1;
582 #endif
583 }
584
585 /**************************************************************************
586  helper functions for Solaris' EA support
587 ****************************************************************************/
588 #ifdef HAVE_ATTROPEN
589 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
590 {
591         struct stat sbuf;
592
593         if (fstat(attrfd, &sbuf) == -1) {
594                 errno = ENOATTR;
595                 return -1;
596         }
597
598         /* This is to return the current size of the named extended attribute */
599         if (size == 0) {
600                 return sbuf.st_size;
601         }
602
603         /* check size and read xattr */
604         if (sbuf.st_size > size) {
605                 errno = ERANGE;
606                 return -1;
607         }
608
609         return read(attrfd, value, sbuf.st_size);
610 }
611
612 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
613 {
614         ssize_t len = 0;
615         DIR *dirp;
616         struct dirent *de;
617         int newfd = dup(attrdirfd);
618         /* CAUTION: The originating file descriptor should not be
619                     used again following the call to fdopendir().
620                     For that reason we dup() the file descriptor
621                     here to make things more clear. */
622         dirp = fdopendir(newfd);
623
624         while ((de = readdir(dirp))) {
625                 size_t listlen = strlen(de->d_name) + 1;
626                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
627                         /* we don't want "." and ".." here: */
628                         continue;
629                 }
630
631                 if (size == 0) {
632                         /* return the current size of the list of extended attribute names*/
633                         len += listlen;
634                 } else {
635                         /* check size and copy entrieŃ• + nul into list. */
636                         if ((len + listlen) > size) {
637                                 errno = ERANGE;
638                                 len = -1;
639                                 break;
640                         } else {
641                                 strlcpy(list + len, de->d_name, listlen);
642                                 len += listlen;
643                         }
644                 }
645         }
646
647         if (closedir(dirp) == -1) {
648                 return -1;
649         }
650         return len;
651 }
652
653 static int solaris_unlinkat(int attrdirfd, const char *name)
654 {
655         if (unlinkat(attrdirfd, name, 0) == -1) {
656                 if (errno == ENOENT) {
657                         errno = ENOATTR;
658                 }
659                 return -1;
660         }
661         return 0;
662 }
663
664 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
665 {
666         int filedes = attropen(path, attrpath, oflag, mode);
667         if (filedes == -1) {
668                 if (errno == EINVAL) {
669                         errno = ENOTSUP;
670                 } else {
671                         errno = ENOATTR;
672                 }
673         }
674         return filedes;
675 }
676
677 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
678 {
679         int filedes = openat(fildes, path, oflag, mode);
680         if (filedes == -1) {
681                 if (errno == EINVAL) {
682                         errno = ENOTSUP;
683                 } else {
684                         errno = ENOATTR;
685                 }
686         }
687         return filedes;
688 }
689
690 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
691 {
692         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
693                 return 0;
694         } else {
695                 return -1;
696         }
697 }
698 #endif /*HAVE_ATTROPEN*/
699
700