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