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