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