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/9.0/sys/kern/vfs_extattr.c 225617 2011-09-16 13:58:51Z kmacy $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capability.h>
35 #include <sys/lock.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sysproto.h>
39 #include <sys/fcntl.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 sys_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);
111 if (error) {
112 NDFREE(&nd, 0);
113 mp = NULL;
114 goto out;
115 }
116 VOP_UNLOCK(nd.ni_vp, 0);
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);
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);
136
137 vn_finished_write(mp_writable);
138 out:
139 if (mp != NULL)
140 vfs_unbusy(mp);
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 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
178
179 aiov.iov_base = data;
180 aiov.iov_len = nbytes;
181 auio.uio_iov = &aiov;
182 auio.uio_iovcnt = 1;
183 auio.uio_offset = 0;
184 if (nbytes > INT_MAX) {
185 error = EINVAL;
186 goto done;
187 }
188 auio.uio_resid = nbytes;
189 auio.uio_rw = UIO_WRITE;
190 auio.uio_segflg = UIO_USERSPACE;
191 auio.uio_td = td;
192 cnt = nbytes;
193
194 #ifdef MAC
195 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
196 attrname);
197 if (error)
198 goto done;
199 #endif
200
201 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
202 td->td_ucred, td);
203 cnt -= auio.uio_resid;
204 td->td_retval[0] = cnt;
205
206 done:
207 VOP_UNLOCK(vp, 0);
208 vn_finished_write(mp);
209 return (error);
210 }
211
212 int
213 sys_extattr_set_fd(td, uap)
214 struct thread *td;
215 struct extattr_set_fd_args /* {
216 int fd;
217 int attrnamespace;
218 const char *attrname;
219 void *data;
220 size_t nbytes;
221 } */ *uap;
222 {
223 struct file *fp;
224 char attrname[EXTATTR_MAXNAMELEN];
225 int vfslocked, error;
226
227 AUDIT_ARG_FD(uap->fd);
228 AUDIT_ARG_VALUE(uap->attrnamespace);
229 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
230 if (error)
231 return (error);
232 AUDIT_ARG_TEXT(attrname);
233
234 error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp);
235 if (error)
236 return (error);
237
238 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
239 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
240 attrname, uap->data, uap->nbytes, td);
241 fdrop(fp, td);
242 VFS_UNLOCK_GIANT(vfslocked);
243
244 return (error);
245 }
246
247 int
248 sys_extattr_set_file(td, uap)
249 struct thread *td;
250 struct extattr_set_file_args /* {
251 const char *path;
252 int attrnamespace;
253 const char *attrname;
254 void *data;
255 size_t nbytes;
256 } */ *uap;
257 {
258 struct nameidata nd;
259 char attrname[EXTATTR_MAXNAMELEN];
260 int vfslocked, error;
261
262 AUDIT_ARG_VALUE(uap->attrnamespace);
263 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
264 if (error)
265 return (error);
266 AUDIT_ARG_TEXT(attrname);
267
268 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
269 uap->path, td);
270 error = namei(&nd);
271 if (error)
272 return (error);
273 NDFREE(&nd, NDF_ONLY_PNBUF);
274
275 vfslocked = NDHASGIANT(&nd);
276 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
277 uap->data, uap->nbytes, td);
278
279 vrele(nd.ni_vp);
280 VFS_UNLOCK_GIANT(vfslocked);
281 return (error);
282 }
283
284 int
285 sys_extattr_set_link(td, uap)
286 struct thread *td;
287 struct extattr_set_link_args /* {
288 const char *path;
289 int attrnamespace;
290 const char *attrname;
291 void *data;
292 size_t nbytes;
293 } */ *uap;
294 {
295 struct nameidata nd;
296 char attrname[EXTATTR_MAXNAMELEN];
297 int vfslocked, error;
298
299 AUDIT_ARG_VALUE(uap->attrnamespace);
300 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
301 if (error)
302 return (error);
303 AUDIT_ARG_TEXT(attrname);
304
305 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
306 uap->path, td);
307 error = namei(&nd);
308 if (error)
309 return (error);
310 NDFREE(&nd, NDF_ONLY_PNBUF);
311
312 vfslocked = NDHASGIANT(&nd);
313 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
314 uap->data, uap->nbytes, td);
315
316 vrele(nd.ni_vp);
317 VFS_UNLOCK_GIANT(vfslocked);
318 return (error);
319 }
320
321 /*-
322 * Get a named extended attribute on a file or directory
323 *
324 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
325 * kernelspace string pointer "attrname", userspace buffer
326 * pointer "data", buffer length "nbytes", thread "td".
327 * Returns: 0 on success, an error number otherwise
328 * Locks: none
329 * References: vp must be a valid reference for the duration of the call
330 */
331 static int
332 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
333 void *data, size_t nbytes, struct thread *td)
334 {
335 struct uio auio, *auiop;
336 struct iovec aiov;
337 ssize_t cnt;
338 size_t size, *sizep;
339 int error;
340
341 VFS_ASSERT_GIANT(vp->v_mount);
342 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
343
344 /*
345 * Slightly unusual semantics: if the user provides a NULL data
346 * pointer, they don't want to receive the data, just the maximum
347 * read length.
348 */
349 auiop = NULL;
350 sizep = NULL;
351 cnt = 0;
352 if (data != NULL) {
353 aiov.iov_base = data;
354 aiov.iov_len = nbytes;
355 auio.uio_iov = &aiov;
356 auio.uio_iovcnt = 1;
357 auio.uio_offset = 0;
358 if (nbytes > INT_MAX) {
359 error = EINVAL;
360 goto done;
361 }
362 auio.uio_resid = nbytes;
363 auio.uio_rw = UIO_READ;
364 auio.uio_segflg = UIO_USERSPACE;
365 auio.uio_td = td;
366 auiop = &auio;
367 cnt = nbytes;
368 } else
369 sizep = &size;
370
371 #ifdef MAC
372 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
373 attrname);
374 if (error)
375 goto done;
376 #endif
377
378 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
379 td->td_ucred, td);
380
381 if (auiop != NULL) {
382 cnt -= auio.uio_resid;
383 td->td_retval[0] = cnt;
384 } else
385 td->td_retval[0] = size;
386
387 done:
388 VOP_UNLOCK(vp, 0);
389 return (error);
390 }
391
392 int
393 sys_extattr_get_fd(td, uap)
394 struct thread *td;
395 struct extattr_get_fd_args /* {
396 int fd;
397 int attrnamespace;
398 const char *attrname;
399 void *data;
400 size_t nbytes;
401 } */ *uap;
402 {
403 struct file *fp;
404 char attrname[EXTATTR_MAXNAMELEN];
405 int vfslocked, error;
406
407 AUDIT_ARG_FD(uap->fd);
408 AUDIT_ARG_VALUE(uap->attrnamespace);
409 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
410 if (error)
411 return (error);
412 AUDIT_ARG_TEXT(attrname);
413
414 error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp);
415 if (error)
416 return (error);
417
418 vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
419 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
420 attrname, uap->data, uap->nbytes, td);
421
422 fdrop(fp, td);
423 VFS_UNLOCK_GIANT(vfslocked);
424 return (error);
425 }
426
427 int
428 sys_extattr_get_file(td, uap)
429 struct thread *td;
430 struct extattr_get_file_args /* {
431 const char *path;
432 int attrnamespace;
433 const char *attrname;
434 void *data;
435 size_t nbytes;
436 } */ *uap;
437 {
438 struct nameidata nd;
439 char attrname[EXTATTR_MAXNAMELEN];
440 int vfslocked, error;
441
442 AUDIT_ARG_VALUE(uap->attrnamespace);
443 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
444 if (error)
445 return (error);
446 AUDIT_ARG_TEXT(attrname);
447
448 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
449 uap->path, td);
450 error = namei(&nd);
451 if (error)
452 return (error);
453 NDFREE(&nd, NDF_ONLY_PNBUF);
454
455 vfslocked = NDHASGIANT(&nd);
456 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
457 uap->data, uap->nbytes, td);
458
459 vrele(nd.ni_vp);
460 VFS_UNLOCK_GIANT(vfslocked);
461 return (error);
462 }
463
464 int
465 sys_extattr_get_link(td, uap)
466 struct thread *td;
467 struct extattr_get_link_args /* {
468 const char *path;
469 int attrnamespace;
470 const char *attrname;
471 void *data;
472 size_t nbytes;
473 } */ *uap;
474 {
475 struct nameidata nd;
476 char attrname[EXTATTR_MAXNAMELEN];
477 int vfslocked, error;
478
479 AUDIT_ARG_VALUE(uap->attrnamespace);
480 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
481 if (error)
482 return (error);
483 AUDIT_ARG_TEXT(attrname);
484
485 NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
486 uap->path, td);
487 error = namei(&nd);
488 if (error)
489 return (error);
490 NDFREE(&nd, NDF_ONLY_PNBUF);
491
492 vfslocked = NDHASGIANT(&nd);
493 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
494 uap->data, uap->nbytes, td);
495
496 vrele(nd.ni_vp);
497 VFS_UNLOCK_GIANT(vfslocked);
498 return (error);
499 }
500
501 /*
502 * extattr_delete_vp(): Delete a named extended attribute on a file or
503 * directory
504 *
505 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
506 * kernelspace string pointer "attrname", proc "p"
507 * Returns: 0 on success, an error number otherwise
508 * Locks: none
509 * References: vp must be a valid reference for the duration of the call
510 */
511 static int
512 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
513 struct thread *td)
514 {
515 struct mount *mp;
516 int error;
517
518 VFS_ASSERT_GIANT(vp->v_mount);
519 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
520 if (error)
521 return (error);
522 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
523
524 #ifdef MAC
525 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
526 attrname);
527 if (error)
528 goto done;
529 #endif
530
531 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
532 td);
533 if (error == EOPNOTSUPP)
534 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
535 td->td_ucred, td);
536 #ifdef MAC
537 done:
538 #endif
539 VOP_UNLOCK(vp, 0);
540 vn_finished_write(mp);
541 return (error);
542 }
543
544 int
545 sys_extattr_delete_fd(td, uap)
546 struct thread *td;
547 struct extattr_delete_fd_args /* {
548 int fd;
549 int attrnamespace;
550 const char *attrname;
551 } */ *uap;
552 {
553 struct file *fp;
554 char attrname[EXTATTR_MAXNAMELEN];
555 int vfslocked, error;
556
557 AUDIT_ARG_FD(uap->fd);
558 AUDIT_ARG_VALUE(uap->attrnamespace);
559 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
560 if (error)
561 return (error);
562 AUDIT_ARG_TEXT(attrname);
563
564 error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE,
565 &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
577 int
578 sys_extattr_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
610 int
611 sys_extattr_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 */
653 static int
654 extattr_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
703 done:
704 VOP_UNLOCK(vp, 0);
705 return (error);
706 }
707
708
709 int
710 sys_extattr_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, CAP_EXTATTR_LIST, &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
737 int
738 sys_extattr_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
767 int
768 sys_extattr_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 }
Cache object: d64d43e426099ccfa4183085cc1adeb8
|