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