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