]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/kern/vfs_extattr.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / kern / vfs_extattr.c
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 "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 }