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