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 f()6 Copyright (C) Bjoern Jacke 2006-2007 7 Copyright (C) Herb Lewis 2003 8 Copyright (C) Andrew Bartlett 2012 9 10 ** NOTE! The following LGPL license applies to the replace 11 ** library. This does NOT imply that all of Samba is released 12 ** under the LGPL 13 14 This library is free software; you can redistribute it and/or 15 modify it under the terms of the GNU Lesser General Public 16 License as published by the Free Software Foundation; either 17 version 3 of the License, or (at your option) any later version. 18 19 This library is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 Lesser General Public License for more details. 23 24 You should have received a copy of the GNU Lesser General Public 25 License along with this library; if not, see <http://www.gnu.org/licenses/>. 26 */ 27 28 #define UID_WRAPPER_NOT_REPLACE 29 #include "replace.h" 30 #include "system/filesys.h" 31 #include "system/dir.h" 32 33 /******** Solaris EA helper function prototypes ********/ 34 #ifdef HAVE_ATTROPEN 35 #define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP 36 static int solaris_write_xattr(int attrfd, const char *value, size_t size); 37 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size); 38 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size); 39 static int solaris_unlinkat(int attrdirfd, const char *name); 40 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode); 41 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode); 42 #endif 43 44 /************************************************************************** 45 Wrappers for extented attribute calls. Based on the Linux package with 46 support for IRIX and (Net|Free)BSD also. Expand as other systems have them. 47 ****************************************************************************/ 48 49 ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size) 50 { 51 #if defined(HAVE_XATTR_XATTR) 52 #ifndef XATTR_ADDITIONAL_OPTIONS 53 return getxattr(path, name, value, size); 54 #else 55 56 /* So that we do not recursivly call this function */ 57 #undef getxattr 58 int options = 0; 59 return getxattr(path, name, value, size, 0, options); 60 #endif 61 #elif defined(HAVE_XATTR_EA) 62 return getea(path, name, value, size); 63 #elif defined(HAVE_XATTR_EXTATTR) 64 ssize_t retval; 65 int attrnamespace; 66 const char *attrname; 67 68 if (strncmp(name, "system.", 7) == 0) { 69 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 70 attrname = name + 7; 71 } else if (strncmp(name, "user.", 5) == 0) { 72 attrnamespace = EXTATTR_NAMESPACE_USER; 73 attrname = name + 5; 74 } else { 75 errno = EINVAL; 76 return -1; 77 } 78 79 /* 80 * The BSD implementation has a nasty habit of silently truncating 81 * the returned value to the size of the buffer, so we have to check 82 * that the buffer is large enough to fit the returned value. 83 */ 84 if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) { 85 if (size == 0) { 86 return retval; 87 } else if (retval > size) { 88 errno = ERANGE; 89 return -1; 90 } 91 if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0) 92 return retval; 93 } 94 95 return -1; 96 #elif defined(HAVE_XATTR_ATTR) 97 int retval, flags = 0; 98 int valuelength = (int)size; 99 char *attrname = strchr(name,'.') + 1; 100 101 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; 102 103 retval = attr_get(path, attrname, (char *)value, &valuelength, flags); 104 if (size == 0 && retval == -1 && errno == E2BIG) { 105 return valuelength; 106 } 107 108 return retval ? retval : valuelength; 109 #elif defined(HAVE_ATTROPEN) 110 ssize_t ret = -1; 111 int attrfd = solaris_attropen(path, name, O_RDONLY, 0); 112 if (attrfd >= 0) { 113 ret = solaris_read_xattr(attrfd, value, size); 114 close(attrfd); 115 } 116 return ret; 117 #else 118 errno = ENOSYS; 119 return -1; 120 #endif 121 } 122 123 ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size) 124 { 125 #if defined(HAVE_XATTR_XATTR) 126 #ifndef XATTR_ADDITIONAL_OPTIONS 127 return fgetxattr(filedes, name, value, size); 128 #else 129 130 /* So that we do not recursivly call this function */ 131 #undef fgetxattr 132 int options = 0; 133 return fgetxattr(filedes, name, value, size, 0, options); 134 #endif 135 #elif defined(HAVE_XATTR_EA) 136 return fgetea(filedes, name, value, size); 137 #elif defined(HAVE_XATTR_EXTATTR) 138 ssize_t retval; 139 int attrnamespace; 140 const char *attrname; 141 142 if (strncmp(name, "system.", 7) == 0) { 143 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 144 attrname = name + 7; 145 } else if (strncmp(name, "user.", 5) == 0) { 146 attrnamespace = EXTATTR_NAMESPACE_USER; 147 attrname = name + 5; 148 } else { 149 errno = EINVAL; 150 return -1; 151 } 152 153 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) { 154 if (size == 0) { 155 return retval; 156 } else if (retval > size) { 157 errno = ERANGE; 158 return -1; 159 } 160 if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0) 161 return retval; 162 } 163 164 return -1; 165 #elif defined(HAVE_XATTR_ATTR) 166 int retval, flags = 0; 167 int valuelength = (int)size; 168 char *attrname = strchr(name,'.') + 1; 169 170 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; 171 172 retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags); 173 if (size == 0 && retval == -1 && errno == E2BIG) { 174 return valuelength; 175 } 176 return retval ? retval : valuelength; 177 #elif defined(HAVE_ATTROPEN) 178 ssize_t ret = -1; 179 int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0); 180 if (attrfd >= 0) { 181 ret = solaris_read_xattr(attrfd, value, size); 182 close(attrfd); 183 } 184 return ret; 185 #else 186 errno = ENOSYS; 187 return -1; 188 #endif 189 } 190 191 #if defined(HAVE_XATTR_EXTATTR) 192 193 #define EXTATTR_PREFIX(s) (s), (sizeof((s))-1) 194 195 static struct { 196 int space; 197 const char *name; 198 size_t len; 199 } 200 extattr[] = { 201 { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") }, 202 { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") }, 203 }; 204 205 typedef union { 206 const char *path; 207 int filedes; 208 } extattr_arg; 209 210 static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size) 211 { 212 ssize_t list_size, total_size = 0; 213 int i, t, len; 214 char *buf; 215 /* Iterate through extattr(2) namespaces */ 216 for(t = 0; t < ARRAY_SIZE(extattr); t++) { 217 if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) { 218 /* ignore all but user namespace when we are not root, see bug 10247 */ 219 continue; 220 } 221 switch(type) { 222 case 0: 223 list_size = extattr_list_file(arg.path, extattr[t].space, list, size); 224 break; 225 case 1: 226 list_size = extattr_list_link(arg.path, extattr[t].space, list, size); 227 break; 228 case 2: 229 list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size); 230 break; 231 default: 232 errno = ENOSYS; 233 return -1; 234 } 235 /* Some error happend. Errno should be set by the previous call */ 236 if(list_size < 0) 237 return -1; 238 /* No attributes */ 239 if(list_size == 0) 240 continue; 241 /* XXX: Call with an empty buffer may be used to calculate 242 necessary buffer size. Unfortunately, we can't say, how 243 many attributes were returned, so here is the potential 244 problem with the emulation. 245 */ 246 if(list == NULL) { 247 /* Take the worse case of one char attribute names - 248 two bytes per name plus one more for sanity. 249 */ 250 total_size += list_size + (list_size/2 + 1)*extattr[t].len; 251 continue; 252 } 253 /* Count necessary offset to fit namespace prefixes */ 254 len = 0; 255 for(i = 0; i < list_size; i += list[i] + 1) 256 len += extattr[t].len; 257 258 total_size += list_size + len; 259 /* Buffer is too small to fit the results */ 260 if(total_size > size) { 261 errno = ERANGE; 262 return -1; 263 } 264 /* Shift results back, so we can prepend prefixes */ 265 buf = (char *)memmove(list + len, list, list_size); 266 267 for(i = 0; i < list_size; i += len + 1) { 268 len = buf[i]; 269 strncpy(list, extattr[t].name, extattr[t].len + 1); 270 list += extattr[t].len; 271 strncpy(list, buf + i + 1, len); 272 list[len] = '\0'; 273 list += len + 1; 274 } 275 size -= total_size; 276 } 277 return total_size; 278 } 279 280 #endif 281 282 #if defined(HAVE_XATTR_ATTR) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H)) 283 static char attr_buffer[ATTR_MAX_VALUELEN]; 284 285 static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags) 286 { 287 int retval = 0, index; 288 attrlist_cursor_t *cursor = 0; 289 int total_size = 0; 290 attrlist_t * al = (attrlist_t *)attr_buffer; 291 attrlist_ent_t *ae; 292 size_t ent_size, left = size; 293 char *bp = list; 294 295 while (true) { 296 if (filedes) 297 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); 298 else 299 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); 300 if (retval) break; 301 for (index = 0; index < al->al_count; index++) { 302 ae = ATTR_ENTRY(attr_buffer, index); 303 ent_size = strlen(ae->a_name) + sizeof("user."); 304 if (left >= ent_size) { 305 strncpy(bp, "user.", sizeof("user.")); 306 strncat(bp, ae->a_name, ent_size - sizeof("user.")); 307 bp += ent_size; 308 left -= ent_size; 309 } else if (size) { 310 errno = ERANGE; 311 retval = -1; 312 break; 313 } 314 total_size += ent_size; 315 } 316 if (al->al_more == 0) break; 317 } 318 if (retval == 0) { 319 flags |= ATTR_ROOT; 320 cursor = 0; 321 while (true) { 322 if (filedes) 323 retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); 324 else 325 retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); 326 if (retval) break; 327 for (index = 0; index < al->al_count; index++) { 328 ae = ATTR_ENTRY(attr_buffer, index); 329 ent_size = strlen(ae->a_name) + sizeof("system."); 330 if (left >= ent_size) { 331 strncpy(bp, "system.", sizeof("system.")); 332 strncat(bp, ae->a_name, ent_size - sizeof("system.")); 333 bp += ent_size; 334 left -= ent_size; 335 } else if (size) { 336 errno = ERANGE; 337 retval = -1; 338 break; 339 } 340 total_size += ent_size; 341 } 342 if (al->al_more == 0) break; 343 } 344 } 345 return (ssize_t)(retval ? retval : total_size); 346 } 347 348 #endif 349 350 ssize_t rep_listxattr (const char *path, char *list, size_t size) 351 { 352 #if defined(HAVE_XATTR_XATTR) 353 #ifndef XATTR_ADDITIONAL_OPTIONS 354 return listxattr(path, list, size); 355 #else 356 /* So that we do not recursivly call this function */ 357 #undef listxattr 358 int options = 0; 359 return listxattr(path, list, size, options); 360 #endif 361 #elif defined(HAVE_XATTR_EA) 362 return listea(path, list, size); 363 #elif defined(HAVE_XATTR_EXTATTR) 364 extattr_arg arg; 365 arg.path = path; 366 return bsd_attr_list(0, arg, list, size); 367 #elif defined(HAVE_XATTR_ATTR) && defined(HAVE_SYS_ATTRIBUTES_H) 368 return irix_attr_list(path, 0, list, size, 0); 369 #elif defined(HAVE_ATTROPEN) 370 ssize_t ret = -1; 371 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); 372 if (attrdirfd >= 0) { 373 ret = solaris_list_xattr(attrdirfd, list, size); 374 close(attrdirfd); 375 } 376 return ret; 377 #else 378 errno = ENOSYS; 379 return -1; 380 #endif 381 } 382 383 ssize_t rep_flistxattr (int filedes, char *list, size_t size) 384 { 385 #if defined(HAVE_XATTR_XATTR) 386 #ifndef XATTR_ADDITIONAL_OPTIONS 387 return flistxattr(filedes, list, size); 388 #else 389 /* So that we do not recursivly call this function */ 390 #undef flistxattr 391 int options = 0; 392 return flistxattr(filedes, list, size, options); 393 #endif 394 #elif defined(HAVE_XATTR_EA) 395 return flistea(filedes, list, size); 396 #elif defined(HAVE_XATTR_EXTATTR) 397 extattr_arg arg; 398 arg.filedes = filedes; 399 return bsd_attr_list(2, arg, list, size); 400 #elif defined(HAVE_XATTR_ATTR) 401 return irix_attr_list(NULL, filedes, list, size, 0); 402 #elif defined(HAVE_ATTROPEN) 403 ssize_t ret = -1; 404 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); 405 if (attrdirfd >= 0) { 406 ret = solaris_list_xattr(attrdirfd, list, size); 407 close(attrdirfd); 408 } 409 return ret; 410 #else 411 errno = ENOSYS; 412 return -1; 413 #endif 414 } 415 416 int rep_removexattr (const char *path, const char *name) 417 { 418 #if defined(HAVE_XATTR_XATTR) 419 #ifndef XATTR_ADDITIONAL_OPTIONS 420 return removexattr(path, name); 421 #else 422 /* So that we do not recursivly call this function */ 423 #undef removexattr 424 int options = 0; 425 return removexattr(path, name, options); 426 #endif 427 #elif defined(HAVE_XATTR_EA) 428 return removeea(path, name); 429 #elif defined(HAVE_XATTR_EXTATTR) 430 int attrnamespace; 431 const char *attrname; 432 433 if (strncmp(name, "system.", 7) == 0) { 434 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 435 attrname = name + 7; 436 } else if (strncmp(name, "user.", 5) == 0) { 437 attrnamespace = EXTATTR_NAMESPACE_USER; 438 attrname = name + 5; 439 } else { 440 errno = EINVAL; 441 return -1; 442 } 443 444 return extattr_delete_file(path, attrnamespace, attrname); 445 #elif defined(HAVE_XATTR_ATTR) 446 int flags = 0; 447 char *attrname = strchr(name,'.') + 1; 448 449 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; 450 451 return attr_remove(path, attrname, flags); 452 #elif defined(HAVE_ATTROPEN) 453 int ret = -1; 454 int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); 455 if (attrdirfd >= 0) { 456 ret = solaris_unlinkat(attrdirfd, name); 457 close(attrdirfd); 458 } 459 return ret; 460 #else 461 errno = ENOSYS; 462 return -1; 463 #endif 464 } 465 466 int rep_fremovexattr (int filedes, const char *name) 467 { 468 #if defined(HAVE_XATTR_XATTR) 469 #ifndef XATTR_ADDITIONAL_OPTIONS 470 return fremovexattr(filedes, name); 471 #else 472 /* So that we do not recursivly call this function */ 473 #undef fremovexattr 474 int options = 0; 475 return fremovexattr(filedes, name, options); 476 #endif 477 #elif defined(HAVE_XATTR_EA) 478 return fremoveea(filedes, name); 479 #elif defined(HAVE_XATTR_EXTATTR) 480 int attrnamespace; 481 const char *attrname; 482 483 if (strncmp(name, "system.", 7) == 0) { 484 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 485 attrname = name + 7; 486 } else if (strncmp(name, "user.", 5) == 0) { 487 attrnamespace = EXTATTR_NAMESPACE_USER; 488 attrname = name + 5; 489 } else { 490 errno = EINVAL; 491 return -1; 492 } 493 494 return extattr_delete_fd(filedes, attrnamespace, attrname); 495 #elif defined(HAVE_XATTR_ATTR) 496 int flags = 0; 497 char *attrname = strchr(name,'.') + 1; 498 499 if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; 500 501 return attr_removef(filedes, attrname, flags); 502 #elif defined(HAVE_ATTROPEN) 503 int ret = -1; 504 int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); 505 if (attrdirfd >= 0) { 506 ret = solaris_unlinkat(attrdirfd, name); 507 close(attrdirfd); 508 } 509 return ret; 510 #else 511 errno = ENOSYS; 512 return -1; 513 #endif 514 } 515 516 int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags) 517 { 518 #if defined(HAVE_XATTR_XATTR) 519 #ifndef XATTR_ADDITIONAL_OPTIONS 520 return setxattr(path, name, value, size, flags); 521 #else 522 /* So that we do not recursivly call this function */ 523 #undef setxattr 524 int options = 0; 525 return setxattr(path, name, value, size, 0, options); 526 #endif 527 #elif defined(HAVE_XATTR_EA) 528 return setea(path, name, value, size, flags); 529 #elif defined(HAVE_XATTR_EXTATTR) 530 int retval = 0; 531 int attrnamespace; 532 const char *attrname; 533 534 if (strncmp(name, "system.", 7) == 0) { 535 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 536 attrname = name + 7; 537 } else if (strncmp(name, "user.", 5) == 0) { 538 attrnamespace = EXTATTR_NAMESPACE_USER; 539 attrname = name + 5; 540 } else { 541 errno = EINVAL; 542 return -1; 543 } 544 545 if (flags) { 546 /* Check attribute existence */ 547 retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0); 548 if (retval < 0) { 549 /* REPLACE attribute, that doesn't exist */ 550 if (flags & XATTR_REPLACE && errno == ENOATTR) { 551 errno = ENOATTR; 552 return -1; 553 } 554 /* Ignore other errors */ 555 } 556 else { 557 /* CREATE attribute, that already exists */ 558 if (flags & XATTR_CREATE) { 559 errno = EEXIST; 560 return -1; 561 } 562 } 563 } 564 retval = extattr_set_file(path, attrnamespace, attrname, value, size); 565 return (retval < 0) ? -1 : 0; 566 #elif defined(HAVE_XATTR_ATTR) 567 int myflags = 0; 568 char *attrname = strchr(name,'.') + 1; 569 570 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; 571 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; 572 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; 573 574 return attr_set(path, attrname, (const char *)value, size, myflags); 575 #elif defined(HAVE_ATTROPEN) 576 int ret = -1; 577 int myflags = O_RDWR; 578 int attrfd; 579 if (flags & XATTR_CREATE) myflags |= O_EXCL; 580 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; 581 attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); 582 if (attrfd >= 0) { 583 ret = solaris_write_xattr(attrfd, value, size); 584 close(attrfd); 585 } 586 return ret; 587 #else 588 errno = ENOSYS; 589 return -1; 590 #endif 591 } 592 593 int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags) 594 { 595 #if defined(HAVE_XATTR_XATTR) 596 #ifndef XATTR_ADDITIONAL_OPTIONS 597 return fsetxattr(filedes, name, value, size, flags); 598 #else 599 /* So that we do not recursivly call this function */ 600 #undef fsetxattr 601 int options = 0; 602 return fsetxattr(filedes, name, value, size, 0, options); 603 #endif 604 #elif defined(HAVE_XATTR_EA) 605 return fsetea(filedes, name, value, size, flags); 606 #elif defined(HAVE_XATTR_EXTATTR) 607 int retval = 0; 608 int attrnamespace; 609 const char *attrname; 610 611 if (strncmp(name, "system.", 7) == 0) { 612 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 613 attrname = name + 7; 614 } else if (strncmp(name, "user.", 5) == 0) { 615 attrnamespace = EXTATTR_NAMESPACE_USER; 616 attrname = name + 5; 617 } else { 618 errno = EINVAL; 619 return -1; 620 } 621 622 if (flags) { 623 /* Check attribute existence */ 624 retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0); 625 if (retval < 0) { 626 /* REPLACE attribute, that doesn't exist */ 627 if (flags & XATTR_REPLACE && errno == ENOATTR) { 628 errno = ENOATTR; 629 return -1; 630 } 631 /* Ignore other errors */ 632 } 633 else { 634 /* CREATE attribute, that already exists */ 635 if (flags & XATTR_CREATE) { 636 errno = EEXIST; 637 return -1; 638 } 639 } 640 } 641 retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size); 642 return (retval < 0) ? -1 : 0; 643 #elif defined(HAVE_XATTR_ATTR) 644 int myflags = 0; 645 char *attrname = strchr(name,'.') + 1; 646 647 if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; 648 if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; 649 if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; 650 651 return attr_setf(filedes, attrname, (const char *)value, size, myflags); 652 #elif defined(HAVE_ATTROPEN) 653 int ret = -1; 654 int myflags = O_RDWR | O_XATTR; 655 int attrfd; 656 if (flags & XATTR_CREATE) myflags |= O_EXCL; 657 if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; 658 attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE); 659 if (attrfd >= 0) { 660 ret = solaris_write_xattr(attrfd, value, size); 661 close(attrfd); 662 } 663 return ret; 664 #else 665 errno = ENOSYS; 666 return -1; 667 #endif 668 } 669 670 /************************************************************************** 671 helper functions for Solaris' EA support 672 ****************************************************************************/ 673 #ifdef HAVE_ATTROPEN 674 static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size) 675 { 676 struct stat sbuf; 677 678 if (fstat(attrfd, &sbuf) == -1) { 679 errno = ENOATTR; 680 return -1; 681 } 682 683 /* This is to return the current size of the named extended attribute */ 684 if (size == 0) { 685 return sbuf.st_size; 686 } 687 688 /* check size and read xattr */ 689 if (sbuf.st_size > size) { 690 errno = ERANGE; 691 return -1; 692 } 693 694 return read(attrfd, value, sbuf.st_size); 695 } 696 697 static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size) 698 { 699 ssize_t len = 0; 700 DIR *dirp; 701 struct dirent *de; 702 int newfd = dup(attrdirfd); 703 /* CAUTION: The originating file descriptor should not be 704 used again following the call to fdopendir(). 705 For that reason we dup() the file descriptor 706 here to make things more clear. */ 707 dirp = fdopendir(newfd); 708 709 while ((de = readdir(dirp))) { 710 size_t listlen = strlen(de->d_name) + 1; 711 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { 712 /* we don't want "." and ".." here: */ 713 continue; 714 } 715 716 if (size == 0) { 717 /* return the current size of the list of extended attribute names*/ 718 len += listlen; 719 } else { 720 /* check size and copy entrieѕ + nul into list. */ 721 if ((len + listlen) > size) { 722 errno = ERANGE; 723 len = -1; 724 break; 725 } else { 726 strlcpy(list + len, de->d_name, listlen); 727 len += listlen; 728 } 729 } 730 } 731 732 if (closedir(dirp) == -1) { 733 return -1; 734 } 735 return len; 736 } 737 738 static int solaris_unlinkat(int attrdirfd, const char *name) 739 { 740 if (unlinkat(attrdirfd, name, 0) == -1) { 741 if (errno == ENOENT) { 742 errno = ENOATTR; 743 } 744 return -1; 745 } 746 return 0; 747 } 748 749 static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode) 750 { 751 int filedes = attropen(path, attrpath, oflag, mode); 752 if (filedes == -1) { 753 if (errno == EINVAL) { 754 errno = ENOTSUP; 755 } else { 756 errno = ENOATTR; 757 } 758 } 759 return filedes; 760 } 761 762 static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode) 763 { 764 int filedes = openat(fildes, path, oflag, mode); 765 if (filedes == -1) { 766 if (errno == EINVAL) { 767 errno = ENOTSUP; 768 } else { 769 errno = ENOATTR; 770 } 771 } 772 return filedes; 773 } 774 775 static int solaris_write_xattr(int attrfd, const char *value, size_t size) 776 { 777 if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) { 778 return 0; 779 } else { 780 return -1; 781 } 782 } 783 #endif /*HAVE_ATTROPEN*/ 784 785 786