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