2 Unix SMB/CIFS implementation.
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
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.
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.
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.
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.
27 Samba 3.0.28, modified for netatalk.
28 $Id: sys_ea.c,v 1.6 2009-12-04 10:26:10 franklahm Exp $
38 #include <sys/types.h>
42 #include <attr/xattr.h>
43 #elif HAVE_SYS_XATTR_H
44 #include <sys/xattr.h>
56 #ifdef HAVE_SYS_EXTATTR_H
57 #include <sys/extattr.h>
60 #include <atalk/adouble.h>
61 #include <atalk/util.h>
62 #include <atalk/logger.h>
66 #define ENOATTR ENODATA
69 /******** Solaris EA helper function prototypes ********/
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);
80 /**************************************************************************
81 Wrappers for extented attribute calls. Based on the Linux package with
82 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
83 ****************************************************************************/
84 static char attr_name[256 +5] = "user.";
86 static const char *prefix(const char *uname)
88 #if defined(HAVE_ATTROPEN)
91 strlcpy(attr_name +5, uname, 256);
96 ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
98 const char *name = prefix(uname);
100 #if defined(HAVE_GETXATTR)
101 #ifndef XATTR_ADD_OPT
102 return getxattr(path, name, value, size);
105 return getxattr(path, name, value, size, 0, options);
107 #elif defined(HAVE_GETEA)
108 return getea(path, name, value, size);
109 #elif defined(HAVE_EXTATTR_GET_FILE)
112 * The BSD implementation has a nasty habit of silently truncating
113 * the returned value to the size of the buffer, so we have to check
114 * that the buffer is large enough to fit the returned value.
116 if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
118 /* size == 0 means only return size */
124 if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
128 LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
130 #elif defined(HAVE_ATTR_GET)
131 int retval, flags = 0;
132 int valuelength = (int)size;
133 char *attrname = strchr(name,'.') + 1;
135 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
137 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
139 return retval ? retval : valuelength;
140 #elif defined(HAVE_ATTROPEN)
142 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
144 ret = solaris_read_xattr(attrfd, value, size);
154 ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
156 const char *name = prefix(uname);
158 #if defined(HAVE_LGETXATTR)
159 return lgetxattr(path, name, value, size);
160 #elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
161 int options = XATTR_NOFOLLOW;
162 return getxattr(path, name, value, size, 0, options);
163 #elif defined(HAVE_LGETEA)
164 return lgetea(path, name, value, size);
165 #elif defined(HAVE_EXTATTR_GET_LINK)
167 if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
172 if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
176 LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
178 #elif defined(HAVE_ATTR_GET)
179 int retval, flags = ATTR_DONTFOLLOW;
180 int valuelength = (int)size;
181 char *attrname = strchr(name,'.') + 1;
183 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
185 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
187 return retval ? retval : valuelength;
188 #elif defined(HAVE_ATTROPEN)
190 int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
192 ret = solaris_read_xattr(attrfd, value, size);
202 #if defined(HAVE_EXTATTR_LIST_FILE)
204 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
212 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
213 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
221 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
227 #if defined(HAVE_EXTATTR_LIST_FILE)
229 list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
232 #if defined(HAVE_EXTATTR_LIST_LINK)
234 list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
237 #if defined(HAVE_EXTATTR_LIST_FD)
239 list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
247 /* Some error happend. Errno should be set by the previous call */
255 /* XXX: Call with an empty buffer may be used to calculate
256 necessary buffer size. Unfortunately, we can't say, how
257 many attributes were returned, so here is the potential
258 problem with the emulation.
263 /* Buffer is too small to fit the results */
264 if(list_size > size) {
269 /* Convert from pascal strings to C strings */
271 memmove(list, list + 1, list_size);
273 for(i = len; i < list_size; ) {
274 LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
286 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
287 static char attr_buffer[ATTR_MAX_VALUELEN];
289 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
291 int retval = 0, index;
292 attrlist_cursor_t *cursor = 0;
294 attrlist_t * al = (attrlist_t *)attr_buffer;
296 size_t ent_size, left = size;
301 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
303 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
305 for (index = 0; index < al->al_count; index++) {
306 ae = ATTR_ENTRY(attr_buffer, index);
307 ent_size = strlen(ae->a_name) + sizeof("user.");
308 if (left >= ent_size) {
309 strncpy(bp, "user.", sizeof("user."));
310 strncat(bp, ae->a_name, ent_size - sizeof("user."));
318 total_size += ent_size;
320 if (al->al_more == 0) break;
327 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
329 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
331 for (index = 0; index < al->al_count; index++) {
332 ae = ATTR_ENTRY(attr_buffer, index);
333 ent_size = strlen(ae->a_name) + sizeof("system.");
334 if (left >= ent_size) {
335 strncpy(bp, "system.", sizeof("system."));
336 strncat(bp, ae->a_name, ent_size - sizeof("system."));
344 total_size += ent_size;
346 if (al->al_more == 0) break;
349 return (ssize_t)(retval ? retval : total_size);
354 #if defined(HAVE_LISTXATTR)
355 static ssize_t remove_user(ssize_t ret, char *list, size_t size)
362 if (ret <= 0 || size == 0)
366 while (ptrsize > 0) {
367 len = strlen(ptr1) +1;
369 if (strncmp(ptr1, "user.",5)) {
373 memmove(ptr, ptr1 +5, len -5);
381 ssize_t sys_listxattr (const char *path, char *list, size_t size)
383 #if defined(HAVE_LISTXATTR)
386 #ifndef XATTR_ADD_OPT
387 ret = listxattr(path, list, size);
390 ret = listxattr(path, list, size, options);
392 return remove_user(ret, list, size);
394 #elif defined(HAVE_LISTEA)
395 return listea(path, list, size);
396 #elif defined(HAVE_EXTATTR_LIST_FILE)
399 return bsd_attr_list(0, arg, list, size);
400 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
401 return irix_attr_list(path, 0, list, size, 0);
402 #elif defined(HAVE_ATTROPEN)
404 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
405 if (attrdirfd >= 0) {
406 ret = solaris_list_xattr(attrdirfd, list, size);
416 ssize_t sys_llistxattr (const char *path, char *list, size_t size)
418 #if defined(HAVE_LLISTXATTR)
421 ret = llistxattr(path, list, size);
422 return remove_user(ret, list, size);
423 #elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
425 int options = XATTR_NOFOLLOW;
427 ret = listxattr(path, list, size, options);
428 return remove_user(ret, list, size);
430 #elif defined(HAVE_LLISTEA)
431 return llistea(path, list, size);
432 #elif defined(HAVE_EXTATTR_LIST_LINK)
435 return bsd_attr_list(1, arg, list, size);
436 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
437 return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
438 #elif defined(HAVE_ATTROPEN)
440 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
441 if (attrdirfd >= 0) {
442 ret = solaris_list_xattr(attrdirfd, list, size);
452 int sys_removexattr (const char *path, const char *uname)
454 const char *name = prefix(uname);
455 #if defined(HAVE_REMOVEXATTR)
456 #ifndef XATTR_ADD_OPT
457 return removexattr(path, name);
460 return removexattr(path, name, options);
462 #elif defined(HAVE_REMOVEEA)
463 return removeea(path, name);
464 #elif defined(HAVE_EXTATTR_DELETE_FILE)
465 return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
466 #elif defined(HAVE_ATTR_REMOVE)
468 char *attrname = strchr(name,'.') + 1;
470 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
472 return attr_remove(path, attrname, flags);
473 #elif defined(HAVE_ATTROPEN)
475 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
476 if (attrdirfd >= 0) {
477 ret = solaris_unlinkat(attrdirfd, name);
487 int sys_lremovexattr (const char *path, const char *uname)
489 const char *name = prefix(uname);
490 #if defined(HAVE_LREMOVEXATTR)
491 return lremovexattr(path, name);
492 #elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
493 int options = XATTR_NOFOLLOW;
494 return removexattr(path, name, options);
495 #elif defined(HAVE_LREMOVEEA)
496 return lremoveea(path, name);
497 #elif defined(HAVE_EXTATTR_DELETE_LINK)
498 return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
499 #elif defined(HAVE_ATTR_REMOVE)
500 int flags = ATTR_DONTFOLLOW;
501 char *attrname = strchr(name,'.') + 1;
503 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
505 return attr_remove(path, attrname, flags);
506 #elif defined(HAVE_ATTROPEN)
508 int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
509 if (attrdirfd >= 0) {
510 ret = solaris_unlinkat(attrdirfd, name);
520 int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
522 const char *name = prefix(uname);
523 #if defined(HAVE_SETXATTR)
524 #ifndef XATTR_ADD_OPT
525 return setxattr(path, name, value, size, flags);
528 return setxattr(path, name, value, size, 0, options);
530 #elif defined(HAVE_SETEA)
531 return setea(path, name, value, size, flags);
532 #elif defined(HAVE_EXTATTR_SET_FILE)
535 /* Check attribute existence */
536 retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
538 /* REPLACE attribute, that doesn't exist */
539 if (flags & XATTR_REPLACE && errno == ENOATTR) {
543 /* Ignore other errors */
546 /* CREATE attribute, that already exists */
547 if (flags & XATTR_CREATE) {
553 retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
554 return (retval < 0) ? -1 : 0;
555 #elif defined(HAVE_ATTR_SET)
557 char *attrname = strchr(name,'.') + 1;
559 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
560 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
561 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
563 return attr_set(path, attrname, (const char *)value, size, myflags);
564 #elif defined(HAVE_ATTROPEN)
566 int myflags = O_RDWR;
568 if (flags & XATTR_CREATE) myflags |= O_EXCL;
569 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
570 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
572 ret = solaris_write_xattr(attrfd, value, size);
582 int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
584 const char *name = prefix(uname);
585 #if defined(HAVE_LSETXATTR)
586 return lsetxattr(path, name, value, size, flags);
587 #elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
588 int options = XATTR_NOFOLLOW;
589 return setxattr(path, name, value, size, 0, options);
590 #elif defined(LSETEA)
591 return lsetea(path, name, value, size, flags);
592 #elif defined(HAVE_EXTATTR_SET_LINK)
595 /* Check attribute existence */
596 retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
598 /* REPLACE attribute, that doesn't exist */
599 if (flags & XATTR_REPLACE && errno == ENOATTR) {
603 /* Ignore other errors */
606 /* CREATE attribute, that already exists */
607 if (flags & XATTR_CREATE) {
614 retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
615 return (retval < 0) ? -1 : 0;
616 #elif defined(HAVE_ATTR_SET)
617 int myflags = ATTR_DONTFOLLOW;
618 char *attrname = strchr(name,'.') + 1;
620 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
621 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
622 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
624 return attr_set(path, attrname, (const char *)value, size, myflags);
625 #elif defined(HAVE_ATTROPEN)
627 int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
629 if (flags & XATTR_CREATE) myflags |= O_EXCL;
630 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
631 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
633 ret = solaris_write_xattr(attrfd, value, size);
643 /**************************************************************************
644 helper functions for Solaris' EA support
645 ****************************************************************************/
647 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
651 if (fstat(attrfd, &sbuf) == -1) {
655 /* This is to return the current size of the named extended attribute */
660 /* check size and read xattr */
661 if (sbuf.st_size > size) {
665 return read(attrfd, value, sbuf.st_size);
668 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
673 int newfd = dup(attrdirfd);
674 /* CAUTION: The originating file descriptor should not be
675 used again following the call to fdopendir().
676 For that reason we dup() the file descriptor
677 here to make things more clear. */
678 dirp = fdopendir(newfd);
680 while ((de = readdir(dirp))) {
682 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
683 !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw"))
685 /* we don't want "." and ".." here: */
686 LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
690 listlen = strlen(de->d_name);
692 /* return the current size of the list of extended attribute names*/
695 /* check size and copy entry + nul into list. */
696 if ((len + listlen + 1) > size) {
701 strcpy(list + len, de->d_name);
709 if (closedir(dirp) == -1) {
710 LOG(log_error, logtype_default, "closedir dirp: %s",strerror(errno));
716 static int solaris_unlinkat(int attrdirfd, const char *name)
718 if (unlinkat(attrdirfd, name, 0) == -1) {
724 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
726 int filedes = attropen(path, attrpath, oflag, mode);
729 LOG(log_error, logtype_default, "attropen(\"%s\", ea:'%s'): %s",
730 path, attrpath, strerror(errno));
736 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
738 int filedes = openat(fildes, path, oflag, mode);
740 LOG(log_error, logtype_default, "openat(\"%s\"): %s",
741 path, strerror(errno));
746 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
748 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
751 LOG(log_error, logtype_default, "solaris_write_xattr: %s",
757 #endif /*HAVE_ATTROPEN*/