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