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"
29 /******** Solaris EA helper function prototypes ********/
31 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
32 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
33 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
34 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
35 static int solaris_unlinkat(int attrdirfd, const char *name);
36 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
37 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
40 /**************************************************************************
41 Wrappers for extented attribute calls. Based on the Linux package with
42 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
43 ****************************************************************************/
45 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
47 #if defined(HAVE_GETXATTR)
48 #ifndef XATTR_ADDITIONAL_OPTIONS
49 return getxattr(path, name, value, size);
52 return getxattr(path, name, value, size, 0, options);
54 #elif defined(HAVE_GETEA)
55 return getea(path, name, value, size);
56 #elif defined(HAVE_EXTATTR_GET_FILE)
59 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
60 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
61 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
63 * The BSD implementation has a nasty habit of silently truncating
64 * the returned value to the size of the buffer, so we have to check
65 * that the buffer is large enough to fit the returned value.
67 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
72 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
77 #elif defined(HAVE_ATTR_GET)
78 int retval, flags = 0;
79 int valuelength = (int)size;
80 char *attrname = strchr(name,'.') + 1;
82 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
84 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
86 return retval ? retval : valuelength;
87 #elif defined(HAVE_ATTROPEN)
89 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
91 ret = solaris_read_xattr(attrfd, value, size);
101 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
103 #if defined(HAVE_FGETXATTR)
104 #ifndef XATTR_ADDITIONAL_OPTIONS
105 return fgetxattr(filedes, name, value, size);
108 return fgetxattr(filedes, name, value, size, 0, options);
110 #elif defined(HAVE_FGETEA)
111 return fgetea(filedes, name, value, size);
112 #elif defined(HAVE_EXTATTR_GET_FD)
115 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
116 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
117 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
119 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
124 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
129 #elif defined(HAVE_ATTR_GETF)
130 int retval, flags = 0;
131 int valuelength = (int)size;
132 char *attrname = strchr(name,'.') + 1;
134 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
136 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
138 return retval ? retval : valuelength;
139 #elif defined(HAVE_ATTROPEN)
141 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
143 ret = solaris_read_xattr(attrfd, value, size);
153 #if defined(HAVE_EXTATTR_LIST_FILE)
155 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
163 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
164 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
172 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
174 ssize_t list_size, total_size = 0;
177 /* Iterate through extattr(2) namespaces */
178 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
180 #if defined(HAVE_EXTATTR_LIST_FILE)
182 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
185 #if defined(HAVE_EXTATTR_LIST_LINK)
187 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
190 #if defined(HAVE_EXTATTR_LIST_FD)
192 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
199 /* Some error happend. Errno should be set by the previous call */
205 /* XXX: Call with an empty buffer may be used to calculate
206 necessary buffer size. Unfortunately, we can't say, how
207 many attributes were returned, so here is the potential
208 problem with the emulation.
211 /* Take the worse case of one char attribute names -
212 two bytes per name plus one more for sanity.
214 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
217 /* Count necessary offset to fit namespace prefixes */
219 for(i = 0; i < list_size; i += list[i] + 1)
220 len += extattr[t].len;
222 total_size += list_size + len;
223 /* Buffer is too small to fit the results */
224 if(total_size > size) {
228 /* Shift results back, so we can prepend prefixes */
229 buf = (char *)memmove(list + len, list, list_size);
231 for(i = 0; i < list_size; i += len + 1) {
233 strncpy(list, extattr[t].name, extattr[t].len + 1);
234 list += extattr[t].len;
235 strncpy(list, buf + i + 1, len);
246 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
247 static char attr_buffer[ATTR_MAX_VALUELEN];
249 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
251 int retval = 0, index;
252 attrlist_cursor_t *cursor = 0;
254 attrlist_t * al = (attrlist_t *)attr_buffer;
256 size_t ent_size, left = size;
261 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
263 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
265 for (index = 0; index < al->al_count; index++) {
266 ae = ATTR_ENTRY(attr_buffer, index);
267 ent_size = strlen(ae->a_name) + sizeof("user.");
268 if (left >= ent_size) {
269 strncpy(bp, "user.", sizeof("user."));
270 strncat(bp, ae->a_name, ent_size - sizeof("user."));
278 total_size += ent_size;
280 if (al->al_more == 0) break;
287 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
289 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
291 for (index = 0; index < al->al_count; index++) {
292 ae = ATTR_ENTRY(attr_buffer, index);
293 ent_size = strlen(ae->a_name) + sizeof("system.");
294 if (left >= ent_size) {
295 strncpy(bp, "system.", sizeof("system."));
296 strncat(bp, ae->a_name, ent_size - sizeof("system."));
304 total_size += ent_size;
306 if (al->al_more == 0) break;
309 return (ssize_t)(retval ? retval : total_size);
314 ssize_t rep_listxattr (const char *path, char *list, size_t size)
316 #if defined(HAVE_LISTXATTR)
317 #ifndef XATTR_ADDITIONAL_OPTIONS
318 return listxattr(path, list, size);
321 return listxattr(path, list, size, options);
323 #elif defined(HAVE_LISTEA)
324 return listea(path, list, size);
325 #elif defined(HAVE_EXTATTR_LIST_FILE)
328 return bsd_attr_list(0, arg, list, size);
329 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
330 return irix_attr_list(path, 0, list, size, 0);
331 #elif defined(HAVE_ATTROPEN)
333 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
334 if (attrdirfd >= 0) {
335 ret = solaris_list_xattr(attrdirfd, list, size);
345 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
347 #if defined(HAVE_FLISTXATTR)
348 #ifndef XATTR_ADDITIONAL_OPTIONS
349 return flistxattr(filedes, list, size);
352 return flistxattr(filedes, list, size, options);
354 #elif defined(HAVE_FLISTEA)
355 return flistea(filedes, list, size);
356 #elif defined(HAVE_EXTATTR_LIST_FD)
358 arg.filedes = filedes;
359 return bsd_attr_list(2, arg, list, size);
360 #elif defined(HAVE_ATTR_LISTF)
361 return irix_attr_list(NULL, filedes, list, size, 0);
362 #elif defined(HAVE_ATTROPEN)
364 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
365 if (attrdirfd >= 0) {
366 ret = solaris_list_xattr(attrdirfd, list, size);
376 int rep_removexattr (const char *path, const char *name)
378 #if defined(HAVE_REMOVEXATTR)
379 #ifndef XATTR_ADDITIONAL_OPTIONS
380 return removexattr(path, name);
383 return removexattr(path, name, options);
385 #elif defined(HAVE_REMOVEEA)
386 return removeea(path, name);
387 #elif defined(HAVE_EXTATTR_DELETE_FILE)
389 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
390 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
391 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
393 return extattr_delete_file(path, attrnamespace, attrname);
394 #elif defined(HAVE_ATTR_REMOVE)
396 char *attrname = strchr(name,'.') + 1;
398 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
400 return attr_remove(path, attrname, flags);
401 #elif defined(HAVE_ATTROPEN)
403 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
404 if (attrdirfd >= 0) {
405 ret = solaris_unlinkat(attrdirfd, name);
415 int rep_fremovexattr (int filedes, const char *name)
417 #if defined(HAVE_FREMOVEXATTR)
418 #ifndef XATTR_ADDITIONAL_OPTIONS
419 return fremovexattr(filedes, name);
422 return fremovexattr(filedes, name, options);
424 #elif defined(HAVE_FREMOVEEA)
425 return fremoveea(filedes, name);
426 #elif defined(HAVE_EXTATTR_DELETE_FD)
428 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
429 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
430 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
432 return extattr_delete_fd(filedes, attrnamespace, attrname);
433 #elif defined(HAVE_ATTR_REMOVEF)
435 char *attrname = strchr(name,'.') + 1;
437 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
439 return attr_removef(filedes, attrname, flags);
440 #elif defined(HAVE_ATTROPEN)
442 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
443 if (attrdirfd >= 0) {
444 ret = solaris_unlinkat(attrdirfd, name);
454 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
456 #if defined(HAVE_SETXATTR)
457 #ifndef XATTR_ADDITIONAL_OPTIONS
458 return setxattr(path, name, value, size, flags);
461 return setxattr(path, name, value, size, 0, options);
463 #elif defined(HAVE_SETEA)
464 return setea(path, name, value, size, flags);
465 #elif defined(HAVE_EXTATTR_SET_FILE)
468 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
469 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
470 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
472 /* Check attribute existence */
473 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
475 /* REPLACE attribute, that doesn't exist */
476 if (flags & XATTR_REPLACE && errno == ENOATTR) {
480 /* Ignore other errors */
483 /* CREATE attribute, that already exists */
484 if (flags & XATTR_CREATE) {
490 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
491 return (retval < 0) ? -1 : 0;
492 #elif defined(HAVE_ATTR_SET)
494 char *attrname = strchr(name,'.') + 1;
496 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
497 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
498 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
500 return attr_set(path, attrname, (const char *)value, size, myflags);
501 #elif defined(HAVE_ATTROPEN)
503 int myflags = O_RDWR;
505 if (flags & XATTR_CREATE) myflags |= O_EXCL;
506 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
507 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
509 ret = solaris_write_xattr(attrfd, value, size);
519 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
521 #if defined(HAVE_FSETXATTR)
522 #ifndef XATTR_ADDITIONAL_OPTIONS
523 return fsetxattr(filedes, name, value, size, flags);
526 return fsetxattr(filedes, name, value, size, 0, options);
528 #elif defined(HAVE_FSETEA)
529 return fsetea(filedes, name, value, size, flags);
530 #elif defined(HAVE_EXTATTR_SET_FD)
533 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
534 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
535 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
537 /* Check attribute existence */
538 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
540 /* REPLACE attribute, that doesn't exist */
541 if (flags & XATTR_REPLACE && errno == ENOATTR) {
545 /* Ignore other errors */
548 /* CREATE attribute, that already exists */
549 if (flags & XATTR_CREATE) {
555 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
556 return (retval < 0) ? -1 : 0;
557 #elif defined(HAVE_ATTR_SETF)
559 char *attrname = strchr(name,'.') + 1;
561 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
562 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
563 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
565 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
566 #elif defined(HAVE_ATTROPEN)
568 int myflags = O_RDWR | O_XATTR;
570 if (flags & XATTR_CREATE) myflags |= O_EXCL;
571 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
572 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
574 ret = solaris_write_xattr(attrfd, value, size);
584 /**************************************************************************
585 helper functions for Solaris' EA support
586 ****************************************************************************/
588 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
592 if (fstat(attrfd, &sbuf) == -1) {
597 /* This is to return the current size of the named extended attribute */
602 /* check size and read xattr */
603 if (sbuf.st_size > size) {
608 return read(attrfd, value, sbuf.st_size);
611 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
616 int newfd = dup(attrdirfd);
617 /* CAUTION: The originating file descriptor should not be
618 used again following the call to fdopendir().
619 For that reason we dup() the file descriptor
620 here to make things more clear. */
621 dirp = fdopendir(newfd);
623 while ((de = readdir(dirp))) {
624 size_t listlen = strlen(de->d_name) + 1;
625 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
626 /* we don't want "." and ".." here: */
631 /* return the current size of the list of extended attribute names*/
634 /* check size and copy entrieѕ + nul into list. */
635 if ((len + listlen) > size) {
640 strlcpy(list + len, de->d_name, listlen);
646 if (closedir(dirp) == -1) {
652 static int solaris_unlinkat(int attrdirfd, const char *name)
654 if (unlinkat(attrdirfd, name, 0) == -1) {
655 if (errno == ENOENT) {
663 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
665 int filedes = attropen(path, attrpath, oflag, mode);
667 if (errno == EINVAL) {
676 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
678 int filedes = openat(fildes, path, oflag, mode);
680 if (errno == EINVAL) {
689 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
691 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
697 #endif /*HAVE_ATTROPEN*/