]> arthur.barton.de Git - netatalk.git/blob - libatalk/vfs/sys_ea.c
Ignore object files
[netatalk.git] / libatalk / vfs / sys_ea.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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23    sys_copyxattr modified from LGPL2.1 libattr copyright
24    Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
25    Copyright (C) 2001 Andreas Gruenbacher.
26       
27    Samba 3.0.28, modified for netatalk.
28    $Id: sys_ea.c,v 1.6 2009-12-04 10:26:10 franklahm Exp $
29    
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <errno.h>
40
41 #if HAVE_ATTR_XATTR_H
42 #include <attr/xattr.h>
43 #elif HAVE_SYS_XATTR_H
44 #include <sys/xattr.h>
45 #endif
46
47 #ifdef HAVE_SYS_EA_H
48 #include <sys/ea.h>
49 #endif
50
51 #ifdef HAVE_ATTROPEN
52
53 #include <dirent.h>
54 #endif
55
56 #ifdef HAVE_SYS_EXTATTR_H
57 #include <sys/extattr.h>
58 #endif
59
60 #include <atalk/adouble.h>
61 #include <atalk/util.h>
62 #include <atalk/logger.h>
63 #include <atalk/ea.h>
64
65 #ifndef ENOATTR
66 #define ENOATTR ENODATA
67 #endif
68
69 /******** Solaris EA helper function prototypes ********/
70 #ifdef HAVE_ATTROPEN
71 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
72 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
73 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
74 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
75 static int solaris_unlinkat(int attrdirfd, const char *name);
76 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
77 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
78 #endif
79
80 /**************************************************************************
81  Wrappers for extented attribute calls. Based on the Linux package with
82  support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
83 ****************************************************************************/
84 static char attr_name[256 +5] = "user.";
85
86 static const char *prefix(const char *uname)
87 {
88 #if defined(HAVE_ATTROPEN)
89         return uname;
90 #else
91         strlcpy(attr_name +5, uname, 256);
92         return attr_name;
93 #endif
94 }
95
96 ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
97 {
98         const char *name = prefix(uname);
99
100 #if defined(HAVE_GETXATTR)
101 #ifndef XATTR_ADD_OPT
102         return getxattr(path, name, value, size);
103 #else
104         int options = 0;
105         return getxattr(path, name, value, size, 0, options);
106 #endif
107 #elif defined(HAVE_GETEA)
108         return getea(path, name, value, size);
109 #elif defined(HAVE_EXTATTR_GET_FILE)
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          * The BSD implementation has a nasty habit of silently truncating
117          * the returned value to the size of the buffer, so we have to check
118          * that the buffer is large enough to fit the returned value.
119          */
120         if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
121                 if(retval > size) {
122                         errno = ERANGE;
123                         return -1;
124                 }
125                 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
126                         return retval;
127         }
128
129         LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
130         return -1;
131 #elif defined(HAVE_ATTR_GET)
132         int retval, flags = 0;
133         int valuelength = (int)size;
134         char *attrname = strchr(name,'.') + 1;
135         
136         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
137
138         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
139
140         return retval ? retval : valuelength;
141 #elif defined(HAVE_ATTROPEN)
142         ssize_t ret = -1;
143         int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
144         if (attrfd >= 0) {
145                 ret = solaris_read_xattr(attrfd, value, size);
146                 close(attrfd);
147         }
148         return ret;
149 #else
150         errno = ENOSYS;
151         return -1;
152 #endif
153 }
154
155 ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
156 {
157         const char *name = prefix(uname);
158
159 #if defined(HAVE_LGETXATTR)
160         return lgetxattr(path, name, value, size);
161 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
162         int options = XATTR_NOFOLLOW;
163         return getxattr(path, name, value, size, 0, options);
164 #elif defined(HAVE_LGETEA)
165         return lgetea(path, name, value, size);
166 #elif defined(HAVE_EXTATTR_GET_LINK)
167         char *s;
168         ssize_t retval;
169         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
170                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
171         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
172
173         if((retval=extattr_get_link(path, attrnamespace, attrname, NULL, 0)) >= 0) {
174                 if(retval > size) {
175                         errno = ERANGE;
176                         return -1;
177                 }
178                 if((retval=extattr_get_link(path, attrnamespace, attrname, value, size)) >= 0)
179                         return retval;
180         }
181         
182         LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
183         return -1;
184 #elif defined(HAVE_ATTR_GET)
185         int retval, flags = ATTR_DONTFOLLOW;
186         int valuelength = (int)size;
187         char *attrname = strchr(name,'.') + 1;
188         
189         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
190
191         retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
192
193         return retval ? retval : valuelength;
194 #elif defined(HAVE_ATTROPEN)
195         ssize_t ret = -1;
196         int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
197         if (attrfd >= 0) {
198                 ret = solaris_read_xattr(attrfd, value, size);
199                 close(attrfd);
200         }
201         return ret;
202 #else
203         errno = ENOSYS;
204         return -1;
205 #endif
206 }
207
208 #if defined(HAVE_EXTATTR_LIST_FILE)
209
210 #define EXTATTR_PREFIX(s)       (s), (sizeof((s))-1)
211
212 static struct {
213         int space;
214         const char *name;
215         size_t len;
216
217 extattr[] = {
218         { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
219         { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
220 };
221
222 typedef union {
223         const char *path;
224         int filedes;
225 } extattr_arg;
226
227 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
228 {
229         ssize_t list_size, total_size = 0;
230         int i, t, len;
231         char *buf;
232         /* Iterate through extattr(2) namespaces */
233         for(t = 0; t < (sizeof(extattr)/sizeof(extattr[0])); t++) {
234                 switch(type) {
235 #if defined(HAVE_EXTATTR_LIST_FILE)
236                         case 0:
237                                 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
238                                 break;
239 #endif
240 #if defined(HAVE_EXTATTR_LIST_LINK)
241                         case 1:
242                                 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
243                                 break;
244 #endif
245 #if defined(HAVE_EXTATTR_LIST_FD)
246                         case 2:
247                                 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
248                                 break;
249 #endif
250                         default:
251                                 errno = ENOSYS;
252                                 return -1;
253                 }
254                 /* Some error happend. Errno should be set by the previous call */
255                 if(list_size < 0)
256                         return -1;
257                 /* No attributes */
258                 if(list_size == 0)
259                         continue;
260                 /* XXX: Call with an empty buffer may be used to calculate
261                    necessary buffer size. Unfortunately, we can't say, how
262                    many attributes were returned, so here is the potential
263                    problem with the emulation.
264                 */
265                 if(list == NULL) {
266                         /* Take the worse case of one char attribute names - 
267                            two bytes per name plus one more for sanity.
268                         */
269                         total_size += list_size + (list_size/2 + 1)*extattr[t].len;
270                         continue;
271                 }
272                 /* Count necessary offset to fit namespace prefixes */
273                 len = 0;
274                 for(i = 0; i < list_size; i += list[i] + 1)
275                         len += extattr[t].len;
276
277                 total_size += list_size + len;
278                 /* Buffer is too small to fit the results */
279                 if(total_size > size) {
280                         errno = ERANGE;
281                         return -1;
282                 }
283                 /* Shift results back, so we can prepend prefixes */
284                 buf = memmove(list + len, list, list_size);
285
286                 for(i = 0; i < list_size; i += len + 1) {
287                         len = buf[i];
288                         strncpy(list, extattr[t].name, extattr[t].len + 1);
289                         list += extattr[t].len;
290                         strncpy(list, buf + i + 1, len);
291                         list[len] = '\0';
292                         list += len + 1;
293                 }
294                 size -= total_size;
295         }
296         return total_size;
297 }
298
299 #endif
300
301 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
302 static char attr_buffer[ATTR_MAX_VALUELEN];
303
304 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
305 {
306         int retval = 0, index;
307         attrlist_cursor_t *cursor = 0;
308         int total_size = 0;
309         attrlist_t * al = (attrlist_t *)attr_buffer;
310         attrlist_ent_t *ae;
311         size_t ent_size, left = size;
312         char *bp = list;
313
314         while (True) {
315             if (filedes)
316                 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
317             else
318                 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
319             if (retval) break;
320             for (index = 0; index < al->al_count; index++) {
321                 ae = ATTR_ENTRY(attr_buffer, index);
322                 ent_size = strlen(ae->a_name) + sizeof("user.");
323                 if (left >= ent_size) {
324                     strncpy(bp, "user.", sizeof("user."));
325                     strncat(bp, ae->a_name, ent_size - sizeof("user."));
326                     bp += ent_size;
327                     left -= ent_size;
328                 } else if (size) {
329                     errno = ERANGE;
330                     retval = -1;
331                     break;
332                 }
333                 total_size += ent_size;
334             }
335             if (al->al_more == 0) break;
336         }
337         if (retval == 0) {
338             flags |= ATTR_ROOT;
339             cursor = 0;
340             while (True) {
341                 if (filedes)
342                     retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
343                 else
344                     retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
345                 if (retval) break;
346                 for (index = 0; index < al->al_count; index++) {
347                     ae = ATTR_ENTRY(attr_buffer, index);
348                     ent_size = strlen(ae->a_name) + sizeof("system.");
349                     if (left >= ent_size) {
350                         strncpy(bp, "system.", sizeof("system."));
351                         strncat(bp, ae->a_name, ent_size - sizeof("system."));
352                         bp += ent_size;
353                         left -= ent_size;
354                     } else if (size) {
355                         errno = ERANGE;
356                         retval = -1;
357                         break;
358                     }
359                     total_size += ent_size;
360                 }
361                 if (al->al_more == 0) break;
362             }
363         }
364         return (ssize_t)(retval ? retval : total_size);
365 }
366
367 #endif
368
369 #if defined(HAVE_LISTXATTR)
370 static ssize_t remove_user(ssize_t ret, char *list, size_t size)
371 {
372         size_t len;
373         char *ptr;
374         char *ptr1;
375         ssize_t ptrsize;
376         
377         if (ret <= 0 || size == 0)
378                 return ret;
379         ptrsize = ret;
380         ptr = ptr1 = list;
381         while (ptrsize > 0) {
382                 len = strlen(ptr1) +1;
383                 ptrsize -= len;
384                 if (strncmp(ptr1, "user.",5)) {
385                         ptr1 += len;
386                         continue;
387                 }
388                 memmove(ptr, ptr1 +5, len -5);
389                 ptr += len -5;
390                 ptr1 += len;
391         }
392         return ptr -list;
393 }
394 #endif
395
396 ssize_t sys_listxattr (const char *path, char *list, size_t size)
397 {
398 #if defined(HAVE_LISTXATTR)
399         ssize_t ret;
400
401 #ifndef XATTR_ADD_OPT
402         ret = listxattr(path, list, size);
403 #else
404         int options = 0;
405         ret = listxattr(path, list, size, options);
406 #endif
407         return remove_user(ret, list, size);
408
409 #elif defined(HAVE_LISTEA)
410         return listea(path, list, size);
411 #elif defined(HAVE_EXTATTR_LIST_FILE)
412         extattr_arg arg;
413         arg.path = path;
414         return bsd_attr_list(0, arg, list, size);
415 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
416         return irix_attr_list(path, 0, list, size, 0);
417 #elif defined(HAVE_ATTROPEN)
418         ssize_t ret = -1;
419         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
420         if (attrdirfd >= 0) {
421                 ret = solaris_list_xattr(attrdirfd, list, size);
422                 close(attrdirfd);
423         }
424         return ret;
425 #else
426         errno = ENOSYS;
427         return -1;
428 #endif
429 }
430
431 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
432 {
433 #if defined(HAVE_LLISTXATTR)
434         ssize_t ret;
435
436         ret = llistxattr(path, list, size);
437         return remove_user(ret, list, size);
438 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
439         ssize_t ret;
440         int options = XATTR_NOFOLLOW;
441
442         ret = listxattr(path, list, size, options);
443         return remove_user(ret, list, size);
444
445 #elif defined(HAVE_LLISTEA)
446         return llistea(path, list, size);
447 #elif defined(HAVE_EXTATTR_LIST_LINK)
448         extattr_arg arg;
449         arg.path = path;
450         return bsd_attr_list(1, arg, list, size);
451 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
452         return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
453 #elif defined(HAVE_ATTROPEN)
454         ssize_t ret = -1;
455         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
456         if (attrdirfd >= 0) {
457                 ret = solaris_list_xattr(attrdirfd, list, size);
458                 close(attrdirfd);
459         }
460         return ret;
461 #else
462         errno = ENOSYS;
463         return -1;
464 #endif
465 }
466
467 int sys_removexattr (const char *path, const char *uname)
468 {
469         const char *name = prefix(uname);
470 #if defined(HAVE_REMOVEXATTR)
471 #ifndef XATTR_ADD_OPT
472         return removexattr(path, name);
473 #else
474         int options = 0;
475         return removexattr(path, name, options);
476 #endif
477 #elif defined(HAVE_REMOVEEA)
478         return removeea(path, name);
479 #elif defined(HAVE_EXTATTR_DELETE_FILE)
480         char *s;
481         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
482                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
483         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
484
485         return extattr_delete_file(path, attrnamespace, attrname);
486 #elif defined(HAVE_ATTR_REMOVE)
487         int flags = 0;
488         char *attrname = strchr(name,'.') + 1;
489         
490         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
491
492         return attr_remove(path, attrname, flags);
493 #elif defined(HAVE_ATTROPEN)
494         int ret = -1;
495         int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
496         if (attrdirfd >= 0) {
497                 ret = solaris_unlinkat(attrdirfd, name);
498                 close(attrdirfd);
499         }
500         return ret;
501 #else
502         errno = ENOSYS;
503         return -1;
504 #endif
505 }
506
507 int sys_lremovexattr (const char *path, const char *uname)
508 {
509         const char *name = prefix(uname);
510 #if defined(HAVE_LREMOVEXATTR)
511         return lremovexattr(path, name);
512 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
513         int options = XATTR_NOFOLLOW;
514         return removexattr(path, name, options);
515 #elif defined(HAVE_LREMOVEEA)
516         return lremoveea(path, name);
517 #elif defined(HAVE_EXTATTR_DELETE_LINK)
518         char *s;
519         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
520                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
521         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
522
523         return extattr_delete_link(path, attrnamespace, attrname);
524 #elif defined(HAVE_ATTR_REMOVE)
525         int flags = ATTR_DONTFOLLOW;
526         char *attrname = strchr(name,'.') + 1;
527         
528         if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
529
530         return attr_remove(path, attrname, flags);
531 #elif defined(HAVE_ATTROPEN)
532         int ret = -1;
533         int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
534         if (attrdirfd >= 0) {
535                 ret = solaris_unlinkat(attrdirfd, name);
536                 close(attrdirfd);
537         }
538         return ret;
539 #else
540         errno = ENOSYS;
541         return -1;
542 #endif
543 }
544
545 int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
546 {
547         const char *name = prefix(uname);
548 #if defined(HAVE_SETXATTR)
549 #ifndef XATTR_ADD_OPT
550         return setxattr(path, name, value, size, flags);
551 #else
552         int options = 0;
553         return setxattr(path, name, value, size, 0, options);
554 #endif
555 #elif defined(HAVE_SETEA)
556         return setea(path, name, value, size, flags);
557 #elif defined(HAVE_EXTATTR_SET_FILE)
558         char *s;
559         int retval = 0;
560         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
561                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
562         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
563         if (flags) {
564                 /* Check attribute existence */
565                 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
566                 if (retval < 0) {
567                         /* REPLACE attribute, that doesn't exist */
568                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
569                                 errno = ENOATTR;
570                                 return -1;
571                         }
572                         /* Ignore other errors */
573                 }
574                 else {
575                         /* CREATE attribute, that already exists */
576                         if (flags & XATTR_CREATE) {
577                                 errno = EEXIST;
578                                 return -1;
579                         }
580                 }
581         }
582         retval = extattr_set_file(path, attrnamespace, attrname, value, size);
583         return (retval < 0) ? -1 : 0;
584 #elif defined(HAVE_ATTR_SET)
585         int myflags = 0;
586         char *attrname = strchr(name,'.') + 1;
587         
588         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
589         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
590         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
591
592         return attr_set(path, attrname, (const char *)value, size, myflags);
593 #elif defined(HAVE_ATTROPEN)
594         int ret = -1;
595         int myflags = O_RDWR;
596         int attrfd;
597         if (flags & XATTR_CREATE) myflags |= O_EXCL;
598         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
599         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
600         if (attrfd >= 0) {
601                 ret = solaris_write_xattr(attrfd, value, size);
602                 close(attrfd);
603         }
604         return ret;
605 #else
606         errno = ENOSYS;
607         return -1;
608 #endif
609 }
610
611 int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
612 {
613         const char *name = prefix(uname);
614 #if defined(HAVE_LSETXATTR)
615         return lsetxattr(path, name, value, size, flags);
616 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
617         int options = XATTR_NOFOLLOW;
618         return setxattr(path, name, value, size, 0, options);
619 #elif defined(LSETEA)
620         return lsetea(path, name, value, size, flags);
621 #elif defined(HAVE_EXTATTR_SET_LINK)
622         char *s;
623         int retval = 0;
624         int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
625                 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
626         const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
627         if (flags) {
628                 /* Check attribute existence */
629                 retval = extattr_get_link(path, attrnamespace, attrname, NULL, 0);
630                 if (retval < 0) {
631                         /* REPLACE attribute, that doesn't exist */
632                         if (flags & XATTR_REPLACE && errno == ENOATTR) {
633                                 errno = ENOATTR;
634                                 return -1;
635                         }
636                         /* Ignore other errors */
637                 }
638                 else {
639                         /* CREATE attribute, that already exists */
640                         if (flags & XATTR_CREATE) {
641                                 errno = EEXIST;
642                                 return -1;
643                         }
644                 }
645         }
646
647         retval = extattr_set_link(path, attrnamespace, attrname, value, size);
648         return (retval < 0) ? -1 : 0;
649 #elif defined(HAVE_ATTR_SET)
650         int myflags = ATTR_DONTFOLLOW;
651         char *attrname = strchr(name,'.') + 1;
652         
653         if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
654         if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
655         if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
656
657         return attr_set(path, attrname, (const char *)value, size, myflags);
658 #elif defined(HAVE_ATTROPEN)
659         int ret = -1;
660         int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
661         int attrfd;
662         if (flags & XATTR_CREATE) myflags |= O_EXCL;
663         if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
664         attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
665         if (attrfd >= 0) {
666                 ret = solaris_write_xattr(attrfd, value, size);
667                 close(attrfd);
668         }
669         return ret;
670 #else
671         errno = ENOSYS;
672         return -1;
673 #endif
674 }
675
676 /**************************************************************************
677  helper functions for Solaris' EA support
678 ****************************************************************************/
679 #ifdef HAVE_ATTROPEN
680 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
681 {
682         struct stat sbuf;
683
684         if (fstat(attrfd, &sbuf) == -1) {
685                 return -1;
686         }
687
688         /* This is to return the current size of the named extended attribute */
689         if (size == 0) {
690                 return sbuf.st_size;
691         }
692
693         /* check size and read xattr */
694         if (sbuf.st_size > size) {
695                 return -1;
696         }
697
698         return read(attrfd, value, sbuf.st_size);
699 }
700
701 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
702 {
703         ssize_t len = 0;
704         DIR *dirp;
705         struct dirent *de;
706         int newfd = dup(attrdirfd);
707         /* CAUTION: The originating file descriptor should not be
708                     used again following the call to fdopendir().
709                     For that reason we dup() the file descriptor
710                     here to make things more clear. */
711         dirp = fdopendir(newfd);
712
713         while ((de = readdir(dirp))) {
714                 size_t listlen;
715                 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
716                      !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw")) 
717                 {
718                         /* we don't want "." and ".." here: */
719                         LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
720                         continue;
721                 }
722
723                 listlen = strlen(de->d_name);
724                 if (size == 0) {
725                         /* return the current size of the list of extended attribute names*/
726                         len += listlen + 1;
727                 } else {
728                         /* check size and copy entry + nul into list. */
729                         if ((len + listlen + 1) > size) {
730                                 errno = ERANGE;
731                                 len = -1;
732                                 break;
733                         } else {
734                                 strcpy(list + len, de->d_name);
735                                 len += listlen;
736                                 list[len] = '\0';
737                                 ++len;
738                         }
739                 }
740         }
741
742         if (closedir(dirp) == -1) {
743                 LOG(log_debug, logtype_default, "closedir dirp failed: %s\n",strerror(errno));
744                 return -1;
745         }
746         return len;
747 }
748
749 static int solaris_unlinkat(int attrdirfd, const char *name)
750 {
751         if (unlinkat(attrdirfd, name, 0) == -1) {
752                 return -1;
753         }
754         return 0;
755 }
756
757 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
758 {
759         int filedes = attropen(path, attrpath, oflag, mode);
760         if (filedes == -1) {
761                 LOG(log_maxdebug, logtype_default, "attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno));
762         errno = ENOATTR;
763         }
764         return filedes;
765 }
766
767 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
768 {
769         int filedes = openat(fildes, path, oflag, mode);
770         if (filedes == -1) {
771                 LOG(log_maxdebug, logtype_default, "openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno));
772         }
773         return filedes;
774 }
775
776 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
777 {
778         if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
779                 return 0;
780         } else {
781                 LOG(log_maxdebug, logtype_default, "solaris_write_xattr FAILED!\n");
782                 return -1;
783         }
784 }
785
786 #endif /*HAVE_ATTROPEN*/
787