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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
26 /******** Solaris EA helper function prototypes ********/
28 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
29 static int solaris_write_xattr(int attrfd, const char *value, size_t size);
30 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
31 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
32 static int solaris_unlinkat(int attrdirfd, const char *name);
33 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
34 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
37 /**************************************************************************
38 Wrappers for extented attribute calls. Based on the Linux package with
39 support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
40 ****************************************************************************/
42 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size)
44 #if defined(HAVE_GETXATTR)
46 return getxattr(path, name, value, size);
49 return getxattr(path, name, value, size, 0, options);
51 #elif defined(HAVE_GETEA)
52 return getea(path, name, value, size);
53 #elif defined(HAVE_EXTATTR_GET_FILE)
56 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
57 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
58 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
60 * The BSD implementation has a nasty habit of silently truncating
61 * the returned value to the size of the buffer, so we have to check
62 * that the buffer is large enough to fit the returned value.
64 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) {
69 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
74 #elif defined(HAVE_ATTR_GET)
75 int retval, flags = 0;
76 int valuelength = (int)size;
77 char *attrname = strchr(name,'.') + 1;
79 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
81 retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
83 return retval ? retval : valuelength;
84 #elif defined(HAVE_ATTROPEN)
86 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
88 ret = solaris_read_xattr(attrfd, value, size);
98 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size)
100 #if defined(HAVE_FGETXATTR)
101 #ifndef XATTR_ADD_OPT
102 return fgetxattr(filedes, name, value, size);
105 return fgetxattr(filedes, name, value, size, 0, options);
107 #elif defined(HAVE_FGETEA)
108 return fgetea(filedes, name, value, size);
109 #elif defined(HAVE_EXTATTR_GET_FD)
112 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
113 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
114 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
116 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
121 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
126 #elif defined(HAVE_ATTR_GETF)
127 int retval, flags = 0;
128 int valuelength = (int)size;
129 char *attrname = strchr(name,'.') + 1;
131 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
133 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
135 return retval ? retval : valuelength;
136 #elif defined(HAVE_ATTROPEN)
138 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
140 ret = solaris_read_xattr(attrfd, value, size);
150 #if defined(HAVE_EXTATTR_LIST_FILE)
152 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
160 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
161 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
169 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
171 ssize_t list_size, total_size = 0;
174 /* Iterate through extattr(2) namespaces */
175 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
177 #if defined(HAVE_EXTATTR_LIST_FILE)
179 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
182 #if defined(HAVE_EXTATTR_LIST_LINK)
184 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
187 #if defined(HAVE_EXTATTR_LIST_FD)
189 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
196 /* Some error happend. Errno should be set by the previous call */
202 /* XXX: Call with an empty buffer may be used to calculate
203 necessary buffer size. Unfortunately, we can't say, how
204 many attributes were returned, so here is the potential
205 problem with the emulation.
208 /* Take the worse case of one char attribute names -
209 two bytes per name plus one more for sanity.
211 total_size += list_size + (list_size/2 + 1)*extattr[t].len;
214 /* Count necessary offset to fit namespace prefixes */
216 for(i = 0; i < list_size; i += list[i] + 1)
217 len += extattr[t].len;
219 total_size += list_size + len;
220 /* Buffer is too small to fit the results */
221 if(total_size > size) {
225 /* Shift results back, so we can prepend prefixes */
226 buf = (char *)memmove(list + len, list, list_size);
228 for(i = 0; i < list_size; i += len + 1) {
230 strncpy(list, extattr[t].name, extattr[t].len + 1);
231 list += extattr[t].len;
232 strncpy(list, buf + i + 1, len);
243 #if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
244 static char attr_buffer[ATTR_MAX_VALUELEN];
246 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
248 int retval = 0, index;
249 attrlist_cursor_t *cursor = 0;
251 attrlist_t * al = (attrlist_t *)attr_buffer;
253 size_t ent_size, left = size;
258 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
260 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
262 for (index = 0; index < al->al_count; index++) {
263 ae = ATTR_ENTRY(attr_buffer, index);
264 ent_size = strlen(ae->a_name) + sizeof("user.");
265 if (left >= ent_size) {
266 strncpy(bp, "user.", sizeof("user."));
267 strncat(bp, ae->a_name, ent_size - sizeof("user."));
275 total_size += ent_size;
277 if (al->al_more == 0) break;
284 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
286 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
288 for (index = 0; index < al->al_count; index++) {
289 ae = ATTR_ENTRY(attr_buffer, index);
290 ent_size = strlen(ae->a_name) + sizeof("system.");
291 if (left >= ent_size) {
292 strncpy(bp, "system.", sizeof("system."));
293 strncat(bp, ae->a_name, ent_size - sizeof("system."));
301 total_size += ent_size;
303 if (al->al_more == 0) break;
306 return (ssize_t)(retval ? retval : total_size);
311 ssize_t rep_listxattr (const char *path, char *list, size_t size)
313 #if defined(HAVE_LISTXATTR)
314 #ifndef XATTR_ADD_OPT
315 return listxattr(path, list, size);
318 return listxattr(path, list, size, options);
320 #elif defined(HAVE_LISTEA)
321 return listea(path, list, size);
322 #elif defined(HAVE_EXTATTR_LIST_FILE)
325 return bsd_attr_list(0, arg, list, size);
326 #elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
327 return irix_attr_list(path, 0, list, size, 0);
328 #elif defined(HAVE_ATTROPEN)
330 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
331 if (attrdirfd >= 0) {
332 ret = solaris_list_xattr(attrdirfd, list, size);
342 ssize_t rep_flistxattr (int filedes, char *list, size_t size)
344 #if defined(HAVE_FLISTXATTR)
345 #ifndef XATTR_ADD_OPT
346 return flistxattr(filedes, list, size);
349 return flistxattr(filedes, list, size, options);
351 #elif defined(HAVE_FLISTEA)
352 return flistea(filedes, list, size);
353 #elif defined(HAVE_EXTATTR_LIST_FD)
355 arg.filedes = filedes;
356 return bsd_attr_list(2, arg, list, size);
357 #elif defined(HAVE_ATTR_LISTF)
358 return irix_attr_list(NULL, filedes, list, size, 0);
359 #elif defined(HAVE_ATTROPEN)
361 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
362 if (attrdirfd >= 0) {
363 ret = solaris_list_xattr(attrdirfd, list, size);
373 int rep_removexattr (const char *path, const char *name)
375 #if defined(HAVE_REMOVEXATTR)
376 #ifndef XATTR_ADD_OPT
377 return removexattr(path, name);
380 return removexattr(path, name, options);
382 #elif defined(HAVE_REMOVEEA)
383 return removeea(path, name);
384 #elif defined(HAVE_EXTATTR_DELETE_FILE)
386 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
387 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
388 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
390 return extattr_delete_file(path, attrnamespace, attrname);
391 #elif defined(HAVE_ATTR_REMOVE)
393 char *attrname = strchr(name,'.') + 1;
395 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
397 return attr_remove(path, attrname, flags);
398 #elif defined(HAVE_ATTROPEN)
400 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
401 if (attrdirfd >= 0) {
402 ret = solaris_unlinkat(attrdirfd, name);
412 int rep_fremovexattr (int filedes, const char *name)
414 #if defined(HAVE_FREMOVEXATTR)
415 #ifndef XATTR_ADD_OPT
416 return fremovexattr(filedes, name);
419 return fremovexattr(filedes, name, options);
421 #elif defined(HAVE_FREMOVEEA)
422 return fremoveea(filedes, name);
423 #elif defined(HAVE_EXTATTR_DELETE_FD)
425 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
426 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
427 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
429 return extattr_delete_fd(filedes, attrnamespace, attrname);
430 #elif defined(HAVE_ATTR_REMOVEF)
432 char *attrname = strchr(name,'.') + 1;
434 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
436 return attr_removef(filedes, attrname, flags);
437 #elif defined(HAVE_ATTROPEN)
439 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
440 if (attrdirfd >= 0) {
441 ret = solaris_unlinkat(attrdirfd, name);
451 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
453 #if defined(HAVE_SETXATTR)
454 #ifndef XATTR_ADD_OPT
455 return setxattr(path, name, value, size, flags);
458 return setxattr(path, name, value, size, 0, options);
460 #elif defined(HAVE_SETEA)
461 return setea(path, name, value, size, flags);
462 #elif defined(HAVE_EXTATTR_SET_FILE)
465 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
466 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
467 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
469 /* Check attribute existence */
470 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
472 /* REPLACE attribute, that doesn't exist */
473 if (flags & XATTR_REPLACE && errno == ENOATTR) {
477 /* Ignore other errors */
480 /* CREATE attribute, that already exists */
481 if (flags & XATTR_CREATE) {
487 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
488 return (retval < 0) ? -1 : 0;
489 #elif defined(HAVE_ATTR_SET)
491 char *attrname = strchr(name,'.') + 1;
493 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
494 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
495 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
497 return attr_set(path, attrname, (const char *)value, size, myflags);
498 #elif defined(HAVE_ATTROPEN)
500 int myflags = O_RDWR;
502 if (flags & XATTR_CREATE) myflags |= O_EXCL;
503 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
504 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
506 ret = solaris_write_xattr(attrfd, value, size);
516 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags)
518 #if defined(HAVE_FSETXATTR)
519 #ifndef XATTR_ADD_OPT
520 return fsetxattr(filedes, name, value, size, flags);
523 return fsetxattr(filedes, name, value, size, 0, options);
525 #elif defined(HAVE_FSETEA)
526 return fsetea(filedes, name, value, size, flags);
527 #elif defined(HAVE_EXTATTR_SET_FD)
530 int attrnamespace = (strncmp(name, "system", 6) == 0) ?
531 EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
532 const char *attrname = ((s=strchr(name, '.')) == NULL) ? name : s + 1;
534 /* Check attribute existence */
535 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
537 /* REPLACE attribute, that doesn't exist */
538 if (flags & XATTR_REPLACE && errno == ENOATTR) {
542 /* Ignore other errors */
545 /* CREATE attribute, that already exists */
546 if (flags & XATTR_CREATE) {
552 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
553 return (retval < 0) ? -1 : 0;
554 #elif defined(HAVE_ATTR_SETF)
556 char *attrname = strchr(name,'.') + 1;
558 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
559 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
560 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
562 return attr_setf(filedes, attrname, (const char *)value, size, myflags);
563 #elif defined(HAVE_ATTROPEN)
565 int myflags = O_RDWR | O_XATTR;
567 if (flags & XATTR_CREATE) myflags |= O_EXCL;
568 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
569 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
571 ret = solaris_write_xattr(attrfd, value, size);
581 /**************************************************************************
582 helper functions for Solaris' EA support
583 ****************************************************************************/
585 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
589 if (fstat(attrfd, &sbuf) == -1) {
594 /* This is to return the current size of the named extended attribute */
599 /* check size and read xattr */
600 if (sbuf.st_size > size) {
605 return read(attrfd, value, sbuf.st_size);
608 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
613 int newfd = dup(attrdirfd);
614 /* CAUTION: The originating file descriptor should not be
615 used again following the call to fdopendir().
616 For that reason we dup() the file descriptor
617 here to make things more clear. */
618 dirp = fdopendir(newfd);
620 while ((de = readdir(dirp))) {
621 size_t listlen = strlen(de->d_name) + 1;
622 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
623 /* we don't want "." and ".." here: */
628 /* return the current size of the list of extended attribute names*/
631 /* check size and copy entrieѕ + nul into list. */
632 if ((len + listlen) > size) {
637 strlcpy(list + len, de->d_name, listlen);
643 if (closedir(dirp) == -1) {
649 static int solaris_unlinkat(int attrdirfd, const char *name)
651 if (unlinkat(attrdirfd, name, 0) == -1) {
652 if (errno == ENOENT) {
660 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
662 int filedes = attropen(path, attrpath, oflag, mode);
664 if (errno == EINVAL) {
673 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
675 int filedes = openat(fildes, path, oflag, mode);
677 if (errno == EINVAL) {
686 static int solaris_write_xattr(int attrfd, const char *value, size_t size)
688 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
694 #endif /*HAVE_ATTROPEN*/