libreplace: Use true rather than True in xattr.c
[Samba.git] / lib / replace / xattr.c
blob6518f31dcd1e681e85817f593a94be1880939e7f
1 /*
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
10 ** under the LGPL
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/>.
26 #include "replace.h"
27 #include "system/filesys.h"
28 #include "system/dir.h"
30 /******** Solaris EA helper function prototypes ********/
31 #ifdef HAVE_ATTROPEN
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);
39 #endif
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);
51 #else
52 int options = 0;
53 return getxattr(path, name, value, size, 0, options);
54 #endif
55 #elif defined(HAVE_GETEA)
56 return getea(path, name, value, size);
57 #elif defined(HAVE_EXTATTR_GET_FILE)
58 char *s;
59 ssize_t retval;
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) {
69 if(retval > size) {
70 errno = ERANGE;
71 return -1;
73 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0)
74 return retval;
77 return -1;
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)
89 ssize_t ret = -1;
90 int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
91 if (attrfd >= 0) {
92 ret = solaris_read_xattr(attrfd, value, size);
93 close(attrfd);
95 return ret;
96 #else
97 errno = ENOSYS;
98 return -1;
99 #endif
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);
107 #else
108 int options = 0;
109 return fgetxattr(filedes, name, value, size, 0, options);
110 #endif
111 #elif defined(HAVE_FGETEA)
112 return fgetea(filedes, name, value, size);
113 #elif defined(HAVE_EXTATTR_GET_FD)
114 char *s;
115 ssize_t retval;
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) {
121 if(retval > size) {
122 errno = ERANGE;
123 return -1;
125 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
126 return retval;
129 return -1;
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)
141 ssize_t ret = -1;
142 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
143 if (attrfd >= 0) {
144 ret = solaris_read_xattr(attrfd, value, size);
145 close(attrfd);
147 return ret;
148 #else
149 errno = ENOSYS;
150 return -1;
151 #endif
154 #if defined(HAVE_EXTATTR_LIST_FILE)
156 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
158 static struct {
159 int space;
160 const char *name;
161 size_t len;
163 extattr[] = {
164 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") },
165 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") },
168 typedef union {
169 const char *path;
170 int filedes;
171 } extattr_arg;
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;
176 int i, t, len;
177 char *buf;
178 /* Iterate through extattr(2) namespaces */
179 for(t = 0; t < ARRAY_SIZE(extattr); t++) {
180 switch(type) {
181 #if defined(HAVE_EXTATTR_LIST_FILE)
182 case 0:
183 list_size = extattr_list_file(arg.path, extattr[t].space, list, size);
184 break;
185 #endif
186 #if defined(HAVE_EXTATTR_LIST_LINK)
187 case 1:
188 list_size = extattr_list_link(arg.path, extattr[t].space, list, size);
189 break;
190 #endif
191 #if defined(HAVE_EXTATTR_LIST_FD)
192 case 2:
193 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size);
194 break;
195 #endif
196 default:
197 errno = ENOSYS;
198 return -1;
200 /* Some error happend. Errno should be set by the previous call */
201 if(list_size < 0)
202 return -1;
203 /* No attributes */
204 if(list_size == 0)
205 continue;
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.
211 if(list == NULL) {
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;
216 continue;
218 /* Count necessary offset to fit namespace prefixes */
219 len = 0;
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) {
226 errno = ERANGE;
227 return -1;
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) {
233 len = buf[i];
234 strncpy(list, extattr[t].name, extattr[t].len + 1);
235 list += extattr[t].len;
236 strncpy(list, buf + i + 1, len);
237 list[len] = '\0';
238 list += len + 1;
240 size -= total_size;
242 return total_size;
245 #endif
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;
254 int total_size = 0;
255 attrlist_t * al = (attrlist_t *)attr_buffer;
256 attrlist_ent_t *ae;
257 size_t ent_size, left = size;
258 char *bp = list;
260 while (true) {
261 if (filedes)
262 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
263 else
264 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
265 if (retval) break;
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."));
272 bp += ent_size;
273 left -= ent_size;
274 } else if (size) {
275 errno = ERANGE;
276 retval = -1;
277 break;
279 total_size += ent_size;
281 if (al->al_more == 0) break;
283 if (retval == 0) {
284 flags |= ATTR_ROOT;
285 cursor = 0;
286 while (true) {
287 if (filedes)
288 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
289 else
290 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
291 if (retval) break;
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."));
298 bp += ent_size;
299 left -= ent_size;
300 } else if (size) {
301 errno = ERANGE;
302 retval = -1;
303 break;
305 total_size += ent_size;
307 if (al->al_more == 0) break;
310 return (ssize_t)(retval ? retval : total_size);
313 #endif
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);
320 #else
321 int options = 0;
322 return listxattr(path, list, size, options);
323 #endif
324 #elif defined(HAVE_LISTEA)
325 return listea(path, list, size);
326 #elif defined(HAVE_EXTATTR_LIST_FILE)
327 extattr_arg arg;
328 arg.path = path;
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)
333 ssize_t ret = -1;
334 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
335 if (attrdirfd >= 0) {
336 ret = solaris_list_xattr(attrdirfd, list, size);
337 close(attrdirfd);
339 return ret;
340 #else
341 errno = ENOSYS;
342 return -1;
343 #endif
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);
351 #else
352 int options = 0;
353 return flistxattr(filedes, list, size, options);
354 #endif
355 #elif defined(HAVE_FLISTEA)
356 return flistea(filedes, list, size);
357 #elif defined(HAVE_EXTATTR_LIST_FD)
358 extattr_arg arg;
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)
364 ssize_t ret = -1;
365 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
366 if (attrdirfd >= 0) {
367 ret = solaris_list_xattr(attrdirfd, list, size);
368 close(attrdirfd);
370 return ret;
371 #else
372 errno = ENOSYS;
373 return -1;
374 #endif
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);
382 #else
383 int options = 0;
384 return removexattr(path, name, options);
385 #endif
386 #elif defined(HAVE_REMOVEEA)
387 return removeea(path, name);
388 #elif defined(HAVE_EXTATTR_DELETE_FILE)
389 char *s;
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)
396 int flags = 0;
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)
403 int ret = -1;
404 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
405 if (attrdirfd >= 0) {
406 ret = solaris_unlinkat(attrdirfd, name);
407 close(attrdirfd);
409 return ret;
410 #else
411 errno = ENOSYS;
412 return -1;
413 #endif
416 int rep_fremovexattr (int filedes, const char *name)
418 #if defined(HAVE_FREMOVEXATTR)
419 #ifndef XATTR_ADDITIONAL_OPTIONS
420 return fremovexattr(filedes, name);
421 #else
422 int options = 0;
423 return fremovexattr(filedes, name, options);
424 #endif
425 #elif defined(HAVE_FREMOVEEA)
426 return fremoveea(filedes, name);
427 #elif defined(HAVE_EXTATTR_DELETE_FD)
428 char *s;
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)
435 int flags = 0;
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)
442 int ret = -1;
443 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0);
444 if (attrdirfd >= 0) {
445 ret = solaris_unlinkat(attrdirfd, name);
446 close(attrdirfd);
448 return ret;
449 #else
450 errno = ENOSYS;
451 return -1;
452 #endif
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);
460 #else
461 int options = 0;
462 return setxattr(path, name, value, size, 0, options);
463 #endif
464 #elif defined(HAVE_SETEA)
465 return setea(path, name, value, size, flags);
466 #elif defined(HAVE_EXTATTR_SET_FILE)
467 char *s;
468 int retval = 0;
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;
472 if (flags) {
473 /* Check attribute existence */
474 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0);
475 if (retval < 0) {
476 /* REPLACE attribute, that doesn't exist */
477 if (flags & XATTR_REPLACE && errno == ENOATTR) {
478 errno = ENOATTR;
479 return -1;
481 /* Ignore other errors */
483 else {
484 /* CREATE attribute, that already exists */
485 if (flags & XATTR_CREATE) {
486 errno = EEXIST;
487 return -1;
491 retval = extattr_set_file(path, attrnamespace, attrname, value, size);
492 return (retval < 0) ? -1 : 0;
493 #elif defined(HAVE_ATTR_SET)
494 int myflags = 0;
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)
503 int ret = -1;
504 int myflags = O_RDWR;
505 int attrfd;
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);
509 if (attrfd >= 0) {
510 ret = solaris_write_xattr(attrfd, value, size);
511 close(attrfd);
513 return ret;
514 #else
515 errno = ENOSYS;
516 return -1;
517 #endif
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);
525 #else
526 int options = 0;
527 return fsetxattr(filedes, name, value, size, 0, options);
528 #endif
529 #elif defined(HAVE_FSETEA)
530 return fsetea(filedes, name, value, size, flags);
531 #elif defined(HAVE_EXTATTR_SET_FD)
532 char *s;
533 int retval = 0;
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;
537 if (flags) {
538 /* Check attribute existence */
539 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
540 if (retval < 0) {
541 /* REPLACE attribute, that doesn't exist */
542 if (flags & XATTR_REPLACE && errno == ENOATTR) {
543 errno = ENOATTR;
544 return -1;
546 /* Ignore other errors */
548 else {
549 /* CREATE attribute, that already exists */
550 if (flags & XATTR_CREATE) {
551 errno = EEXIST;
552 return -1;
556 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
557 return (retval < 0) ? -1 : 0;
558 #elif defined(HAVE_ATTR_SETF)
559 int myflags = 0;
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)
568 int ret = -1;
569 int myflags = O_RDWR | O_XATTR;
570 int attrfd;
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);
574 if (attrfd >= 0) {
575 ret = solaris_write_xattr(attrfd, value, size);
576 close(attrfd);
578 return ret;
579 #else
580 errno = ENOSYS;
581 return -1;
582 #endif
585 /**************************************************************************
586 helper functions for Solaris' EA support
587 ****************************************************************************/
588 #ifdef HAVE_ATTROPEN
589 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
591 struct stat sbuf;
593 if (fstat(attrfd, &sbuf) == -1) {
594 errno = ENOATTR;
595 return -1;
598 /* This is to return the current size of the named extended attribute */
599 if (size == 0) {
600 return sbuf.st_size;
603 /* check size and read xattr */
604 if (sbuf.st_size > size) {
605 errno = ERANGE;
606 return -1;
609 return read(attrfd, value, sbuf.st_size);
612 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
614 ssize_t len = 0;
615 DIR *dirp;
616 struct dirent *de;
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: */
628 continue;
631 if (size == 0) {
632 /* return the current size of the list of extended attribute names*/
633 len += listlen;
634 } else {
635 /* check size and copy entrieѕ + nul into list. */
636 if ((len + listlen) > size) {
637 errno = ERANGE;
638 len = -1;
639 break;
640 } else {
641 strlcpy(list + len, de->d_name, listlen);
642 len += listlen;
647 if (closedir(dirp) == -1) {
648 return -1;
650 return len;
653 static int solaris_unlinkat(int attrdirfd, const char *name)
655 if (unlinkat(attrdirfd, name, 0) == -1) {
656 if (errno == ENOENT) {
657 errno = ENOATTR;
659 return -1;
661 return 0;
664 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
666 int filedes = attropen(path, attrpath, oflag, mode);
667 if (filedes == -1) {
668 if (errno == EINVAL) {
669 errno = ENOTSUP;
670 } else {
671 errno = ENOATTR;
674 return filedes;
677 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
679 int filedes = openat(fildes, path, oflag, mode);
680 if (filedes == -1) {
681 if (errno == EINVAL) {
682 errno = ENOTSUP;
683 } else {
684 errno = ENOATTR;
687 return filedes;
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)) {
693 return 0;
694 } else {
695 return -1;
698 #endif /*HAVE_ATTROPEN*/