1 /*- 2 * Copyright (c) 1999-2001 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/lock.h> 35 #include <sys/mount.h> 36 #include <sys/mutex.h> 37 #include <sys/sysproto.h> 38 #include <sys/fcntl.h> 39 #include <sys/namei.h> 40 #include <sys/filedesc.h> 41 #include <sys/limits.h> 42 #include <sys/vnode.h> 43 #include <sys/proc.h> 44 #include <sys/extattr.h> 45 46 #include <security/audit/audit.h> 47 #include <security/mac/mac_framework.h> 48 49 /* 50 * Syscall to push extended attribute configuration information into the VFS. 51 * Accepts a path, which it converts to a mountpoint, as well as a command 52 * (int cmd), and attribute name and misc data. 53 * 54 * Currently this is used only by UFS1 extended attributes. 55 */ 56 int 57 extattrctl(td, uap) 58 struct thread *td; 59 struct extattrctl_args /* { 60 const char *path; 61 int cmd; 62 const char *filename; 63 int attrnamespace; 64 const char *attrname; 65 } */ *uap; 66 { 67 struct vnode *filename_vp; 68 struct nameidata nd; 69 struct mount *mp, *mp_writable; 70 char attrname[EXTATTR_MAXNAMELEN]; 71 int vfslocked, fnvfslocked, error; 72 73 AUDIT_ARG_CMD(uap->cmd); 74 AUDIT_ARG_VALUE(uap->attrnamespace); 75 /* 76 * uap->attrname is not always defined. We check again later when we 77 * invoke the VFS call so as to pass in NULL there if needed. 78 */ 79 if (uap->attrname != NULL) { 80 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, 81 NULL); 82 if (error) 83 return (error); 84 } 85 AUDIT_ARG_TEXT(attrname); 86 87 vfslocked = fnvfslocked = 0; 88 mp = NULL; 89 filename_vp = NULL; 90 if (uap->filename != NULL) { 91 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE2, 92 UIO_USERSPACE, uap->filename, td); 93 error = namei(&nd); 94 if (error) 95 return (error); 96 fnvfslocked = NDHASGIANT(&nd); 97 filename_vp = nd.ni_vp; 98 NDFREE(&nd, NDF_NO_VP_RELE); 99 } 100 101 /* uap->path is always defined. */ 102 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | AUDITVNODE1, 103 UIO_USERSPACE, uap->path, td); 104 error = namei(&nd); 105 if (error) 106 goto out; 107 vfslocked = NDHASGIANT(&nd); 108 mp = nd.ni_vp->v_mount; 109 error = vfs_busy(mp, 0); 110 if (error) { 111 NDFREE(&nd, 0); 112 mp = NULL; 113 goto out; 114 } 115 VOP_UNLOCK(nd.ni_vp, 0); 116 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH); 117 NDFREE(&nd, NDF_NO_VP_UNLOCK); 118 if (error) 119 goto out; 120 if (filename_vp != NULL) { 121 /* 122 * uap->filename is not always defined. If it is, 123 * grab a vnode lock, which VFS_EXTATTRCTL() will 124 * later release. 125 */ 126 error = vn_lock(filename_vp, LK_EXCLUSIVE); 127 if (error) { 128 vn_finished_write(mp_writable); 129 goto out; 130 } 131 } 132 133 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace, 134 uap->attrname != NULL ? attrname : NULL); 135 136 vn_finished_write(mp_writable); 137 out: 138 if (mp != NULL) 139 vfs_unbusy(mp); 140 141 /* 142 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp, 143 * so vrele it if it is defined. 144 */ 145 if (filename_vp != NULL) 146 vrele(filename_vp); 147 VFS_UNLOCK_GIANT(fnvfslocked); 148 VFS_UNLOCK_GIANT(vfslocked); 149 return (error); 150 } 151 152 /*- 153 * Set a named extended attribute on a file or directory 154 * 155 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 156 * kernelspace string pointer "attrname", userspace buffer 157 * pointer "data", buffer length "nbytes", thread "td". 158 * Returns: 0 on success, an error number otherwise 159 * Locks: none 160 * References: vp must be a valid reference for the duration of the call 161 */ 162 static int 163 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 164 void *data, size_t nbytes, struct thread *td) 165 { 166 struct mount *mp; 167 struct uio auio; 168 struct iovec aiov; 169 ssize_t cnt; 170 int error; 171 172 VFS_ASSERT_GIANT(vp->v_mount); 173 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 174 if (error) 175 return (error); 176 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 177 178 aiov.iov_base = data; 179 aiov.iov_len = nbytes; 180 auio.uio_iov = &aiov; 181 auio.uio_iovcnt = 1; 182 auio.uio_offset = 0; 183 if (nbytes > INT_MAX) { 184 error = EINVAL; 185 goto done; 186 } 187 auio.uio_resid = nbytes; 188 auio.uio_rw = UIO_WRITE; 189 auio.uio_segflg = UIO_USERSPACE; 190 auio.uio_td = td; 191 cnt = nbytes; 192 193 #ifdef MAC 194 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace, 195 attrname); 196 if (error) 197 goto done; 198 #endif 199 200 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 201 td->td_ucred, td); 202 cnt -= auio.uio_resid; 203 td->td_retval[0] = cnt; 204 205 done: 206 VOP_UNLOCK(vp, 0); 207 vn_finished_write(mp); 208 return (error); 209 } 210 211 int 212 extattr_set_fd(td, uap) 213 struct thread *td; 214 struct extattr_set_fd_args /* { 215 int fd; 216 int attrnamespace; 217 const char *attrname; 218 void *data; 219 size_t nbytes; 220 } */ *uap; 221 { 222 struct file *fp; 223 char attrname[EXTATTR_MAXNAMELEN]; 224 int vfslocked, error; 225 226 AUDIT_ARG_FD(uap->fd); 227 AUDIT_ARG_VALUE(uap->attrnamespace); 228 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 229 if (error) 230 return (error); 231 AUDIT_ARG_TEXT(attrname); 232 233 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 234 if (error) 235 return (error); 236 237 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 238 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace, 239 attrname, uap->data, uap->nbytes, td); 240 fdrop(fp, td); 241 VFS_UNLOCK_GIANT(vfslocked); 242 243 return (error); 244 } 245 246 int 247 extattr_set_file(td, uap) 248 struct thread *td; 249 struct extattr_set_file_args /* { 250 const char *path; 251 int attrnamespace; 252 const char *attrname; 253 void *data; 254 size_t nbytes; 255 } */ *uap; 256 { 257 struct nameidata nd; 258 char attrname[EXTATTR_MAXNAMELEN]; 259 int vfslocked, error; 260 261 AUDIT_ARG_VALUE(uap->attrnamespace); 262 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 263 if (error) 264 return (error); 265 AUDIT_ARG_TEXT(attrname); 266 267 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 268 uap->path, td); 269 error = namei(&nd); 270 if (error) 271 return (error); 272 NDFREE(&nd, NDF_ONLY_PNBUF); 273 274 vfslocked = NDHASGIANT(&nd); 275 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 276 uap->data, uap->nbytes, td); 277 278 vrele(nd.ni_vp); 279 VFS_UNLOCK_GIANT(vfslocked); 280 return (error); 281 } 282 283 int 284 extattr_set_link(td, uap) 285 struct thread *td; 286 struct extattr_set_link_args /* { 287 const char *path; 288 int attrnamespace; 289 const char *attrname; 290 void *data; 291 size_t nbytes; 292 } */ *uap; 293 { 294 struct nameidata nd; 295 char attrname[EXTATTR_MAXNAMELEN]; 296 int vfslocked, error; 297 298 AUDIT_ARG_VALUE(uap->attrnamespace); 299 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 300 if (error) 301 return (error); 302 AUDIT_ARG_TEXT(attrname); 303 304 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 305 uap->path, td); 306 error = namei(&nd); 307 if (error) 308 return (error); 309 NDFREE(&nd, NDF_ONLY_PNBUF); 310 311 vfslocked = NDHASGIANT(&nd); 312 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname, 313 uap->data, uap->nbytes, td); 314 315 vrele(nd.ni_vp); 316 VFS_UNLOCK_GIANT(vfslocked); 317 return (error); 318 } 319 320 /*- 321 * Get a named extended attribute on a file or directory 322 * 323 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 324 * kernelspace string pointer "attrname", userspace buffer 325 * pointer "data", buffer length "nbytes", thread "td". 326 * Returns: 0 on success, an error number otherwise 327 * Locks: none 328 * References: vp must be a valid reference for the duration of the call 329 */ 330 static int 331 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 332 void *data, size_t nbytes, struct thread *td) 333 { 334 struct uio auio, *auiop; 335 struct iovec aiov; 336 ssize_t cnt; 337 size_t size, *sizep; 338 int error; 339 340 VFS_ASSERT_GIANT(vp->v_mount); 341 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 342 343 /* 344 * Slightly unusual semantics: if the user provides a NULL data 345 * pointer, they don't want to receive the data, just the maximum 346 * read length. 347 */ 348 auiop = NULL; 349 sizep = NULL; 350 cnt = 0; 351 if (data != NULL) { 352 aiov.iov_base = data; 353 aiov.iov_len = nbytes; 354 auio.uio_iov = &aiov; 355 auio.uio_iovcnt = 1; 356 auio.uio_offset = 0; 357 if (nbytes > INT_MAX) { 358 error = EINVAL; 359 goto done; 360 } 361 auio.uio_resid = nbytes; 362 auio.uio_rw = UIO_READ; 363 auio.uio_segflg = UIO_USERSPACE; 364 auio.uio_td = td; 365 auiop = &auio; 366 cnt = nbytes; 367 } else 368 sizep = &size; 369 370 #ifdef MAC 371 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace, 372 attrname); 373 if (error) 374 goto done; 375 #endif 376 377 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep, 378 td->td_ucred, td); 379 380 if (auiop != NULL) { 381 cnt -= auio.uio_resid; 382 td->td_retval[0] = cnt; 383 } else 384 td->td_retval[0] = size; 385 386 done: 387 VOP_UNLOCK(vp, 0); 388 return (error); 389 } 390 391 int 392 extattr_get_fd(td, uap) 393 struct thread *td; 394 struct extattr_get_fd_args /* { 395 int fd; 396 int attrnamespace; 397 const char *attrname; 398 void *data; 399 size_t nbytes; 400 } */ *uap; 401 { 402 struct file *fp; 403 char attrname[EXTATTR_MAXNAMELEN]; 404 int vfslocked, error; 405 406 AUDIT_ARG_FD(uap->fd); 407 AUDIT_ARG_VALUE(uap->attrnamespace); 408 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 409 if (error) 410 return (error); 411 AUDIT_ARG_TEXT(attrname); 412 413 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 414 if (error) 415 return (error); 416 417 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 418 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace, 419 attrname, uap->data, uap->nbytes, td); 420 421 fdrop(fp, td); 422 VFS_UNLOCK_GIANT(vfslocked); 423 return (error); 424 } 425 426 int 427 extattr_get_file(td, uap) 428 struct thread *td; 429 struct extattr_get_file_args /* { 430 const char *path; 431 int attrnamespace; 432 const char *attrname; 433 void *data; 434 size_t nbytes; 435 } */ *uap; 436 { 437 struct nameidata nd; 438 char attrname[EXTATTR_MAXNAMELEN]; 439 int vfslocked, error; 440 441 AUDIT_ARG_VALUE(uap->attrnamespace); 442 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 443 if (error) 444 return (error); 445 AUDIT_ARG_TEXT(attrname); 446 447 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 448 uap->path, td); 449 error = namei(&nd); 450 if (error) 451 return (error); 452 NDFREE(&nd, NDF_ONLY_PNBUF); 453 454 vfslocked = NDHASGIANT(&nd); 455 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 456 uap->data, uap->nbytes, td); 457 458 vrele(nd.ni_vp); 459 VFS_UNLOCK_GIANT(vfslocked); 460 return (error); 461 } 462 463 int 464 extattr_get_link(td, uap) 465 struct thread *td; 466 struct extattr_get_link_args /* { 467 const char *path; 468 int attrnamespace; 469 const char *attrname; 470 void *data; 471 size_t nbytes; 472 } */ *uap; 473 { 474 struct nameidata nd; 475 char attrname[EXTATTR_MAXNAMELEN]; 476 int vfslocked, error; 477 478 AUDIT_ARG_VALUE(uap->attrnamespace); 479 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 480 if (error) 481 return (error); 482 AUDIT_ARG_TEXT(attrname); 483 484 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 485 uap->path, td); 486 error = namei(&nd); 487 if (error) 488 return (error); 489 NDFREE(&nd, NDF_ONLY_PNBUF); 490 491 vfslocked = NDHASGIANT(&nd); 492 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname, 493 uap->data, uap->nbytes, td); 494 495 vrele(nd.ni_vp); 496 VFS_UNLOCK_GIANT(vfslocked); 497 return (error); 498 } 499 500 /* 501 * extattr_delete_vp(): Delete a named extended attribute on a file or 502 * directory 503 * 504 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 505 * kernelspace string pointer "attrname", proc "p" 506 * Returns: 0 on success, an error number otherwise 507 * Locks: none 508 * References: vp must be a valid reference for the duration of the call 509 */ 510 static int 511 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 512 struct thread *td) 513 { 514 struct mount *mp; 515 int error; 516 517 VFS_ASSERT_GIANT(vp->v_mount); 518 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 519 if (error) 520 return (error); 521 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 522 523 #ifdef MAC 524 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace, 525 attrname); 526 if (error) 527 goto done; 528 #endif 529 530 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred, 531 td); 532 if (error == EOPNOTSUPP) 533 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 534 td->td_ucred, td); 535 #ifdef MAC 536 done: 537 #endif 538 VOP_UNLOCK(vp, 0); 539 vn_finished_write(mp); 540 return (error); 541 } 542 543 int 544 extattr_delete_fd(td, uap) 545 struct thread *td; 546 struct extattr_delete_fd_args /* { 547 int fd; 548 int attrnamespace; 549 const char *attrname; 550 } */ *uap; 551 { 552 struct file *fp; 553 char attrname[EXTATTR_MAXNAMELEN]; 554 int vfslocked, error; 555 556 AUDIT_ARG_FD(uap->fd); 557 AUDIT_ARG_VALUE(uap->attrnamespace); 558 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 559 if (error) 560 return (error); 561 AUDIT_ARG_TEXT(attrname); 562 563 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 564 if (error) 565 return (error); 566 567 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 568 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace, 569 attrname, td); 570 fdrop(fp, td); 571 VFS_UNLOCK_GIANT(vfslocked); 572 return (error); 573 } 574 575 int 576 extattr_delete_file(td, uap) 577 struct thread *td; 578 struct extattr_delete_file_args /* { 579 const char *path; 580 int attrnamespace; 581 const char *attrname; 582 } */ *uap; 583 { 584 struct nameidata nd; 585 char attrname[EXTATTR_MAXNAMELEN]; 586 int vfslocked, error; 587 588 AUDIT_ARG_VALUE(uap->attrnamespace); 589 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 590 if (error) 591 return(error); 592 AUDIT_ARG_TEXT(attrname); 593 594 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 595 uap->path, td); 596 error = namei(&nd); 597 if (error) 598 return(error); 599 NDFREE(&nd, NDF_ONLY_PNBUF); 600 601 vfslocked = NDHASGIANT(&nd); 602 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 603 vrele(nd.ni_vp); 604 VFS_UNLOCK_GIANT(vfslocked); 605 return(error); 606 } 607 608 int 609 extattr_delete_link(td, uap) 610 struct thread *td; 611 struct extattr_delete_link_args /* { 612 const char *path; 613 int attrnamespace; 614 const char *attrname; 615 } */ *uap; 616 { 617 struct nameidata nd; 618 char attrname[EXTATTR_MAXNAMELEN]; 619 int vfslocked, error; 620 621 AUDIT_ARG_VALUE(uap->attrnamespace); 622 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL); 623 if (error) 624 return(error); 625 AUDIT_ARG_TEXT(attrname); 626 627 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 628 uap->path, td); 629 error = namei(&nd); 630 if (error) 631 return(error); 632 NDFREE(&nd, NDF_ONLY_PNBUF); 633 634 vfslocked = NDHASGIANT(&nd); 635 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td); 636 vrele(nd.ni_vp); 637 VFS_UNLOCK_GIANT(vfslocked); 638 return(error); 639 } 640 641 /*- 642 * Retrieve a list of extended attributes on a file or directory. 643 * 644 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace", 645 * userspace buffer pointer "data", buffer length "nbytes", 646 * thread "td". 647 * Returns: 0 on success, an error number otherwise 648 * Locks: none 649 * References: vp must be a valid reference for the duration of the call 650 */ 651 static int 652 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, 653 size_t nbytes, struct thread *td) 654 { 655 struct uio auio, *auiop; 656 size_t size, *sizep; 657 struct iovec aiov; 658 ssize_t cnt; 659 int error; 660 661 VFS_ASSERT_GIANT(vp->v_mount); 662 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 663 664 auiop = NULL; 665 sizep = NULL; 666 cnt = 0; 667 if (data != NULL) { 668 aiov.iov_base = data; 669 aiov.iov_len = nbytes; 670 auio.uio_iov = &aiov; 671 auio.uio_iovcnt = 1; 672 auio.uio_offset = 0; 673 if (nbytes > INT_MAX) { 674 error = EINVAL; 675 goto done; 676 } 677 auio.uio_resid = nbytes; 678 auio.uio_rw = UIO_READ; 679 auio.uio_segflg = UIO_USERSPACE; 680 auio.uio_td = td; 681 auiop = &auio; 682 cnt = nbytes; 683 } else 684 sizep = &size; 685 686 #ifdef MAC 687 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace); 688 if (error) 689 goto done; 690 #endif 691 692 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, 693 td->td_ucred, td); 694 695 if (auiop != NULL) { 696 cnt -= auio.uio_resid; 697 td->td_retval[0] = cnt; 698 } else 699 td->td_retval[0] = size; 700 701 done: 702 VOP_UNLOCK(vp, 0); 703 return (error); 704 } 705 706 707 int 708 extattr_list_fd(td, uap) 709 struct thread *td; 710 struct extattr_list_fd_args /* { 711 int fd; 712 int attrnamespace; 713 void *data; 714 size_t nbytes; 715 } */ *uap; 716 { 717 struct file *fp; 718 int vfslocked, error; 719 720 AUDIT_ARG_FD(uap->fd); 721 AUDIT_ARG_VALUE(uap->attrnamespace); 722 error = getvnode(td->td_proc->p_fd, uap->fd, &fp); 723 if (error) 724 return (error); 725 726 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); 727 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data, 728 uap->nbytes, td); 729 730 fdrop(fp, td); 731 VFS_UNLOCK_GIANT(vfslocked); 732 return (error); 733 } 734 735 int 736 extattr_list_file(td, uap) 737 struct thread*td; 738 struct extattr_list_file_args /* { 739 const char *path; 740 int attrnamespace; 741 void *data; 742 size_t nbytes; 743 } */ *uap; 744 { 745 struct nameidata nd; 746 int vfslocked, error; 747 748 AUDIT_ARG_VALUE(uap->attrnamespace); 749 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE, 750 uap->path, td); 751 error = namei(&nd); 752 if (error) 753 return (error); 754 NDFREE(&nd, NDF_ONLY_PNBUF); 755 756 vfslocked = NDHASGIANT(&nd); 757 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 758 uap->nbytes, td); 759 760 vrele(nd.ni_vp); 761 VFS_UNLOCK_GIANT(vfslocked); 762 return (error); 763 } 764 765 int 766 extattr_list_link(td, uap) 767 struct thread*td; 768 struct extattr_list_link_args /* { 769 const char *path; 770 int attrnamespace; 771 void *data; 772 size_t nbytes; 773 } */ *uap; 774 { 775 struct nameidata nd; 776 int vfslocked, error; 777 778 AUDIT_ARG_VALUE(uap->attrnamespace); 779 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, 780 uap->path, td); 781 error = namei(&nd); 782 if (error) 783 return (error); 784 NDFREE(&nd, NDF_ONLY_PNBUF); 785 786 vfslocked = NDHASGIANT(&nd); 787 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data, 788 uap->nbytes, td); 789 790 vrele(nd.ni_vp); 791 VFS_UNLOCK_GIANT(vfslocked); 792 return (error); 793 } 794