2 Unix SMB/CIFS implementation.
3 replacement routines for xattr implementations
4 Copyright (C) Jeremy Allison 1998-2005
5 Copyright (C) Timur Bakeyev 2005
6 Copyright (C) Bjoern Jacke 2006-2007
8 ** NOTE! The following LGPL license applies to the replace
9 ** library. This does NOT imply that all of Samba is released
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
28 #include "system/dir.h"
30 /******** Solaris EA helper function prototypes ********/
32 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
33 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
34 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
35 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
36 static int solaris_unlinkat(int attrdirfd, const char *name);
37 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
38 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
41 /**************************************************************************
42 Wrappers for extented attribute calls. Based on the Linux package with
43 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
44 ****************************************************************************/
46 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
48 #if defined(HAVE_GETXATTR)
49 #ifndef XATTR_ADDITIONAL_OPTIONS
50 return getxattr(path, name, value, size);
53 return getxattr(path, name, value, size, 0, options);
55 #elif defined(HAVE_GETEA)
56 return getea(path, name, value, size);
57 #elif defined(HAVE_EXTATTR_GET_FILE)
60 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
61 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
62 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
64 * The BSD implementation has a nasty habit of silently truncating
65 * the returned value to the size of the buffer, so we have to check
66 * that the buffer is large enough to fit the returned value.
68 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
73 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
78 #elif defined(HAVE_ATTR_GET)
79 int retval, flags = 0;
80 int valuelength = (int)size;
81 char *attrname = strchr(name,'.') + 1;
83 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
85 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
87 return retval ? retval : valuelength;
88 #elif defined(HAVE_ATTROPEN)
90 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
92 ret = solaris_read_xattr(attrfd, value, size);
102 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
104 #if defined(HAVE_FGETXATTR)
105 #ifndef XATTR_ADDITIONAL_OPTIONS
106 return fgetxattr(filedes, name, value, size);
109 return fgetxattr(filedes, name, value, size, 0, options);
111 #elif defined(HAVE_FGETEA)
112 return fgetea(filedes, name, value, size);
113 #elif defined(HAVE_EXTATTR_GET_FD)
116 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
117 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
118 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
120 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
125 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
130 #elif defined(HAVE_ATTR_GETF)
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_getf(filedes, attrname, (char *)value, &valuelength, flags);
139 return retval ? retval : valuelength;
140 #elif defined(HAVE_ATTROPEN)
142 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
144 ret = solaris_read_xattr(attrfd, value, size);
154 #if defined(HAVE_EXTATTR_LIST_FILE)
156 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
164 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
165 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
173 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
175 ssize_t list_size, total_size = 0;
178 /* Iterate through extattr(2) namespaces */
179 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
181 #if defined(HAVE_EXTATTR_LIST_FILE)
183 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
186 #if defined(HAVE_EXTATTR_LIST_LINK)
188 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
191 #if defined(HAVE_EXTATTR_LIST_FD)
193 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
200 /* Some error happend. Errno should be set by the previous call */
206 /* XXX: Call with an empty buffer may be used to calculate
207 necessary buffer size. Unfortunately, we can't say, how
208 many attributes were returned, so here is the potential
209 problem with the emulation.
212 /* Take the worse case of one char attribute names -
213 two bytes per name plus one more for sanity.
215 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
218 /* Count necessary offset to fit namespace prefixes */
220 for(i = 0; i < list_size; i += list[i] + 1)
221 len += extattr[t].len;
223 total_size += list_size + len;
224 /* Buffer is too small to fit the results */
225 if(total_size > size) {
229 /* Shift results back, so we can prepend prefixes */
230 buf = (char *)memmove(list + len, list, list_size);
232 for(i = 0; i < list_size; i += len + 1) {
234 strncpy(list, extattr[t].name, extattr[t].len + 1);
235 list += extattr[t].len;
236 strncpy(list, buf + i + 1, len);
247 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
248 static char attr_buffer[ATTR_MAX_VALUELEN];
250 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
252 int retval = 0, index;
253 attrlist_cursor_t *cursor = 0;
255 attrlist_t * al = (attrlist_t *)attr_buffer;
257 size_t ent_size, left = size;
262 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
264 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
266 for (index = 0; index < al->al_count; index++) {
267 ae = ATTR_ENTRY(attr_buffer, index);
268 ent_size = strlen(ae->a_name) + sizeof("user.");
269 if (left >= ent_size) {
270 strncpy(bp, "user.", sizeof("user."));
271 strncat(bp, ae->a_name, ent_size - sizeof("user."));
279 total_size += ent_size;
281 if (al->al_more == 0) break;
288 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
290 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
292 for (index = 0; index < al->al_count; index++) {
293 ae = ATTR_ENTRY(attr_buffer, index);
294 ent_size = strlen(ae->a_name) + sizeof("system.");
295 if (left >= ent_size) {
296 strncpy(bp, "system.", sizeof("system."));
297 strncat(bp, ae->a_name, ent_size - sizeof("system."));
305 total_size += ent_size;
307 if (al->al_more == 0) break;
310 return (ssize_t)(retval ? retval : total_size);
315 ssize_t rep_listxattr (const char *path, char *list, size_t size)
317 #if defined(HAVE_LISTXATTR)
318 #ifndef XATTR_ADDITIONAL_OPTIONS
319 return listxattr(path, list, size);
322 return listxattr(path, list, size, options);
324 #elif defined(HAVE_LISTEA)
325 return listea(path, list, size);
326 #elif defined(HAVE_EXTATTR_LIST_FILE)
329 return bsd_attr_list(0, arg, list, size);
330 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
331 return irix_attr_list(path, 0, list, size, 0);
332 #elif defined(HAVE_ATTROPEN)
334 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
335 if (attrdirfd >= 0) {
336 ret = solaris_list_xattr(attrdirfd, list, size);
346 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
348 #if defined(HAVE_FLISTXATTR)
349 #ifndef XATTR_ADDITIONAL_OPTIONS
350 return flistxattr(filedes, list, size);
353 return flistxattr(filedes, list, size, options);
355 #elif defined(HAVE_FLISTEA)
356 return flistea(filedes, list, size);
357 #elif defined(HAVE_EXTATTR_LIST_FD)
359 arg.filedes = filedes;
360 return bsd_attr_list(2, arg, list, size);
361 #elif defined(HAVE_ATTR_LISTF)
362 return irix_attr_list(NULL, filedes, list, size, 0);
363 #elif defined(HAVE_ATTROPEN)
365 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
366 if (attrdirfd >= 0) {
367 ret = solaris_list_xattr(attrdirfd, list, size);
377 int rep_removexattr (const char *path, const char *name)
379 #if defined(HAVE_REMOVEXATTR)
380 #ifndef XATTR_ADDITIONAL_OPTIONS
381 return removexattr(path, name);
384 return removexattr(path, name, options);
386 #elif defined(HAVE_REMOVEEA)
387 return removeea(path, name);
388 #elif defined(HAVE_EXTATTR_DELETE_FILE)
390 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
391 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
392 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
394 return extattr_delete_file(path, attrnamespace, attrname);
395 #elif defined(HAVE_ATTR_REMOVE)
397 char *attrname = strchr(name,'.') + 1;
399 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
401 return attr_remove(path, attrname, flags);
402 #elif defined(HAVE_ATTROPEN)
404 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
405 if (attrdirfd >= 0) {
406 ret = solaris_unlinkat(attrdirfd, name);
416 int rep_fremovexattr (int filedes, const char *name)
418 #if defined(HAVE_FREMOVEXATTR)
419 #ifndef XATTR_ADDITIONAL_OPTIONS
420 return fremovexattr(filedes, name);
423 return fremovexattr(filedes, name, options);
425 #elif defined(HAVE_FREMOVEEA)
426 return fremoveea(filedes, name);
427 #elif defined(HAVE_EXTATTR_DELETE_FD)
429 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
430 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
431 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
433 return extattr_delete_fd(filedes, attrnamespace, attrname);
434 #elif defined(HAVE_ATTR_REMOVEF)
436 char *attrname = strchr(name,'.') + 1;
438 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
440 return attr_removef(filedes, attrname, flags);
441 #elif defined(HAVE_ATTROPEN)
443 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
444 if (attrdirfd >= 0) {
445 ret = solaris_unlinkat(attrdirfd, name);
455 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
457 #if defined(HAVE_SETXATTR)
458 #ifndef XATTR_ADDITIONAL_OPTIONS
459 return setxattr(path, name, value, size, flags);
462 return setxattr(path, name, value, size, 0, options);
464 #elif defined(HAVE_SETEA)
465 return setea(path, name, value, size, flags);
466 #elif defined(HAVE_EXTATTR_SET_FILE)
469 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
470 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
471 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
473 /* Check attribute existence */
474 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
476 /* REPLACE attribute, that doesn't exist */
477 if (flags & XATTR_REPLACE && errno == ENOATTR) {
481 /* Ignore other errors */
484 /* CREATE attribute, that already exists */
485 if (flags & XATTR_CREATE) {
491 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
492 return (retval < 0) ? -1 : 0;
493 #elif defined(HAVE_ATTR_SET)
495 char *attrname = strchr(name,'.') + 1;
497 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
498 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
499 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
501 return attr_set(path, attrname, (const char *)value, size, myflags);
502 #elif defined(HAVE_ATTROPEN)
504 int myflags = O_RDWR;
506 if (flags & XATTR_CREATE) myflags |= O_EXCL;
507 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
508 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
510 ret = solaris_write_xattr(attrfd, value, size);
520 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
522 #if defined(HAVE_FSETXATTR)
523 #ifndef XATTR_ADDITIONAL_OPTIONS
524 return fsetxattr(filedes, name, value, size, flags);
527 return fsetxattr(filedes, name, value, size, 0, options);
529 #elif defined(HAVE_FSETEA)
530 return fsetea(filedes, name, value, size, flags);
531 #elif defined(HAVE_EXTATTR_SET_FD)
534 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
535 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
536 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
538 /* Check attribute existence */
539 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
541 /* REPLACE attribute, that doesn't exist */
542 if (flags & XATTR_REPLACE && errno == ENOATTR) {
546 /* Ignore other errors */
549 /* CREATE attribute, that already exists */
550 if (flags & XATTR_CREATE) {
556 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
557 return (retval < 0) ? -1 : 0;
558 #elif defined(HAVE_ATTR_SETF)
560 char *attrname = strchr(name,'.') + 1;
562 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
563 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
564 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
566 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
567 #elif defined(HAVE_ATTROPEN)
569 int myflags = O_RDWR | O_XATTR;
571 if (flags & XATTR_CREATE) myflags |= O_EXCL;
572 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
573 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
575 ret = solaris_write_xattr(attrfd, value, size);
585 /**************************************************************************
586 helper functions for Solaris' EA support
587 ****************************************************************************/
589 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
593 if (fstat(attrfd, &sbuf) == -1) {
598 /* This is to return the current size of the named extended attribute */
603 /* check size and read xattr */
604 if (sbuf.st_size > size) {
609 return read(attrfd, value, sbuf.st_size);
612 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
617 int newfd = dup(attrdirfd);
618 /* CAUTION: The originating file descriptor should not be
619 used again following the call to fdopendir().
620 For that reason we dup() the file descriptor
621 here to make things more clear. */
622 dirp = fdopendir(newfd);
624 while ((de = readdir(dirp))) {
625 size_t listlen = strlen(de->d_name) + 1;
626 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
627 /* we don't want "." and ".." here: */
632 /* return the current size of the list of extended attribute names*/
635 /* check size and copy entrieѕ + nul into list. */
636 if ((len + listlen) > size) {
641 strlcpy(list + len, de->d_name, listlen);
647 if (closedir(dirp) == -1) {
653 static int solaris_unlinkat(int attrdirfd, const char *name)
655 if (unlinkat(attrdirfd, name, 0) == -1) {
656 if (errno == ENOENT) {
664 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
666 int filedes = attropen(path, attrpath, oflag, mode);
668 if (errno == EINVAL) {
677 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
679 int filedes = openat(fildes, path, oflag, mode);
681 if (errno == EINVAL) {
690 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
692 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
698 #endif /*HAVE_ATTROPEN*/