2 * Copyright (c) 1995-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
69 #include <sys/vnode.h>
70 #include <sys/mount.h>
73 #include <sys/malloc.h>
74 #include <sys/dirent.h>
76 #include <sys/sysctl.h>
78 #include <sys/quota.h>
79 #include <machine/cons.h>
80 #include <miscfs/specfs/specdev.h>
82 struct lock__bsd__ exchangelock
;
85 * The currently logged-in user, for ownership of files/directories whose on-disk
86 * permissions are ignored:
90 static int change_dir
__P((struct nameidata
*ndp
, struct proc
*p
));
91 static void checkdirs
__P((struct vnode
*olddp
));
92 static void enablequotas
__P((struct proc
*p
, struct mount
*mp
));
94 /* counts number of mount and unmount operations */
95 unsigned int vfs_nummntops
=0;
98 * Virtual File System System Calls
102 * Mount a file system.
112 mount(p
, uap
, retval
)
114 register struct mount_args
*uap
;
119 struct vfsconf
*vfsp
;
120 int error
, flag
, err2
;
124 char fstypename
[MFSNAMELEN
];
128 * Get vnode to be covered
130 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
132 if (error
= namei(&nd
))
136 if ((vp
->v_flag
& VROOT
) &&
137 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
138 uap
->flags
|= MNT_UPDATE
;
140 if (uap
->flags
& MNT_UPDATE
) {
141 if ((vp
->v_flag
& VROOT
) == 0) {
147 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
152 * We only allow the filesystem to be reloaded if it
153 * is currently mounted read-only.
155 if ((uap
->flags
& MNT_RELOAD
) &&
156 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
159 return (EOPNOTSUPP
); /* Needs translation */
162 * Only root, or the user that did the original mount is
163 * permitted to update it.
165 if (mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
&&
166 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
172 * Do not allow NFS export by non-root users. FOr non-root
173 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
174 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
176 if (p
->p_ucred
->cr_uid
!= 0) {
177 if (uap
->flags
& MNT_EXPORTED
) {
182 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
183 if (mp
->mnt_flag
& MNT_NOEXEC
)
184 uap
->flags
|= MNT_NOEXEC
;
189 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
191 VOP_UNLOCK(vp
, 0, p
);
196 * If the user is not root, ensure that they own the directory
197 * onto which we are attempting to mount.
199 if ((error
= VOP_GETATTR(vp
, &va
, p
->p_ucred
, p
)) ||
200 (va
.va_uid
!= p
->p_ucred
->cr_uid
&&
201 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))) {
206 * Do not allow NFS export by non-root users. FOr non-root
207 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
208 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
210 if (p
->p_ucred
->cr_uid
!= 0) {
211 if (uap
->flags
& MNT_EXPORTED
) {
215 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
216 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
217 uap
->flags
|= MNT_NOEXEC
;
219 if (error
= vinvalbuf(vp
, V_SAVE
, p
->p_ucred
, p
, 0, 0)) {
223 if (vp
->v_type
!= VDIR
) {
229 * Historically filesystem types were identified by number. If we
230 * get an integer for the filesystem type instead of a string, we
231 * check to see if it matches one of the historic filesystem types.
233 fstypenum
= (u_long
)uap
->type
;
234 if (fstypenum
< maxvfsconf
) {
235 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
236 if (vfsp
->vfc_typenum
== fstypenum
)
242 strncpy(fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
244 #endif /* COMPAT_43 */
245 if (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) {
249 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
250 if (!strcmp(vfsp
->vfc_name
, fstypename
))
256 simple_lock(&vp
->v_interlock
);
257 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
258 simple_unlock(&vp
->v_interlock
);
262 SET(vp
->v_flag
, VMOUNT
);
263 simple_unlock(&vp
->v_interlock
);
266 * Allocate and initialize the filesystem.
268 mp
= (struct mount
*)_MALLOC_ZONE((u_long
)sizeof(struct mount
),
270 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
272 /* Initialize the default IO constraints */
273 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
274 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
276 lockinit(&mp
->mnt_lock
, PVFS
, "vfslock", 0, 0);
277 (void)vfs_busy(mp
, LK_NOWAIT
, 0, p
);
278 mp
->mnt_op
= vfsp
->vfc_vfsops
;
280 vfsp
->vfc_refcount
++;
281 mp
->mnt_stat
.f_type
= vfsp
->vfc_typenum
;
282 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
283 strncpy(mp
->mnt_stat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
284 mp
->mnt_vnodecovered
= vp
;
285 mp
->mnt_stat
.f_owner
= p
->p_ucred
->cr_uid
;
286 VOP_UNLOCK(vp
, 0, p
);
290 * Set the mount level flags.
292 if (uap
->flags
& MNT_RDONLY
)
293 mp
->mnt_flag
|= MNT_RDONLY
;
294 else if (mp
->mnt_flag
& MNT_RDONLY
)
295 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
296 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
297 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
298 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
299 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
300 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
301 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
303 * Mount the filesystem.
305 error
= VFS_MOUNT(mp
, uap
->path
, uap
->data
, &nd
, p
);
307 if (uap
->flags
& MNT_UPDATE
) {
309 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
310 mp
->mnt_flag
&= ~MNT_RDONLY
;
312 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
313 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
322 /* get the vnode lock */
323 err2
= vn_lock(vp
, LK_EXCLUSIVE
|LK_RETRY
, p
);
326 * Put the new filesystem on the mount list after root.
329 if (!error
&& !err2
) {
330 simple_lock(&vp
->v_interlock
);
331 CLR(vp
->v_flag
, VMOUNT
);
332 vp
->v_mountedhere
=mp
;
333 simple_unlock(&vp
->v_interlock
);
334 simple_lock(&mountlist_slock
);
336 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
337 simple_unlock(&mountlist_slock
);
339 VOP_UNLOCK(vp
, 0, p
);
341 if (error
= VFS_START(mp
, 0, p
))
344 /* increment the operations count */
350 simple_lock(&vp
->v_interlock
);
351 CLR(vp
->v_flag
, VMOUNT
);
352 simple_unlock(&vp
->v_interlock
);
353 mp
->mnt_vfc
->vfc_refcount
--;
355 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
370 struct nameidata qnd
;
372 char qfpath
[MAXPATHLEN
];
373 char *qfname
= QUOTAFILENAME
;
374 char *qfopsname
= QUOTAOPSNAME
;
375 char *qfextension
[] = INITQFNAMES
;
378 if ((strcmp(mp
->mnt_stat
.f_fstypename
, "hfs") != 0 )
379 && (strcmp( mp
->mnt_stat
.f_fstypename
, "ufs") != 0))
383 * Enable filesystem disk quotas if necessary.
384 * We ignore errors as this should not interfere with final mount
386 for (type
=0; type
< MAXQUOTAS
; type
++) {
387 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfopsname
, qfextension
[type
]);
388 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, qfpath
, p
);
389 if (namei(&qnd
) != 0)
390 continue; /* option file to trigger quotas is not present */
392 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfname
, qfextension
[type
]);
393 if (vp
->v_tag
== VT_HFS
) {
395 (void)hfs_quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
396 } else if (vp
->v_tag
== VT_UFS
) {
398 (void)quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
407 * Scan all active processes to see if any of them have a current
408 * or root directory onto which the new filesystem has just been
409 * mounted. If so, replace them with the new mount point.
415 struct filedesc
*fdp
;
420 if (olddp
->v_usecount
== 1)
422 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
423 panic("mount: lost mount");
424 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
426 if (fdp
->fd_cdir
== olddp
) {
429 fdp
->fd_cdir
= newdp
;
432 if (fdp
->fd_rdir
== olddp
) {
435 fdp
->fd_rdir
= newdp
;
439 if (rootvnode
== olddp
) {
449 * Unmount a file system.
451 * Note: unmount takes a path to the vnode mounted on as argument,
452 * not special file (as before).
454 struct unmount_args
{
460 unmount(p
, uap
, retval
)
462 register struct unmount_args
*uap
;
465 register struct vnode
*vp
;
470 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
472 if (error
= namei(&nd
))
478 * Only root, or the user that did the original mount is
479 * permitted to unmount this filesystem.
481 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
482 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
488 * Don't allow unmounting the root file system.
490 if (mp
->mnt_flag
& MNT_ROOTFS
) {
492 return (EBUSY
); /* the root is always busy */
496 * Must be the root of the filesystem
498 if ((vp
->v_flag
& VROOT
) == 0) {
503 return (dounmount(mp
, uap
->flags
, p
));
507 * Do the actual file system unmount.
510 dounmount(mp
, flags
, p
)
511 register struct mount
*mp
;
515 struct vnode
*coveredvp
;
518 simple_lock(&mountlist_slock
);
519 /* XXX post jaguar fix LK_DRAIN - then clean this up */
520 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
521 simple_unlock(&mountlist_slock
);
522 mp
->mnt_kern_flag
|= MNTK_MWAIT
;
523 if ((error
= tsleep((void *)mp
, PRIBIO
, "dounmount", 0)))
526 * The prior unmount attempt has probably succeeded.
527 * Do not dereference mp here - returning EBUSY is safest.
531 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
532 error
= lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
,
533 &mountlist_slock
, p
);
535 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
538 mp
->mnt_flag
&=~ MNT_ASYNC
;
539 ubc_umount(mp
); /* release cached vnodes */
540 cache_purgevfs(mp
); /* remove cache entries for this file sys */
541 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
542 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
544 error
= VFS_UNMOUNT(mp
, flags
, p
);
545 simple_lock(&mountlist_slock
);
547 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
548 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
549 &mountlist_slock
, p
);
553 /* increment the operations count */
557 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
558 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
559 coveredvp
->v_mountedhere
= (struct mount
*)0;
560 simple_unlock(&mountlist_slock
);
562 simple_lock(&mountlist_slock
);
564 mp
->mnt_vfc
->vfc_refcount
--;
565 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
566 panic("unmount: dangling vnode");
568 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
570 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
573 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
578 * Sync each mounted filesystem.
582 struct ctldebug debug0
= { "syncprt", &syncprt
};
588 int print_vmpage_stat
=0;
594 struct sync_args
*uap
;
597 register struct mount
*mp
, *nmp
;
600 simple_lock(&mountlist_slock
);
601 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
602 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
603 nmp
= mp
->mnt_list
.cqe_next
;
606 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
607 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
608 mp
->mnt_flag
&= ~MNT_ASYNC
;
609 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
611 mp
->mnt_flag
|= MNT_ASYNC
;
613 simple_lock(&mountlist_slock
);
614 nmp
= mp
->mnt_list
.cqe_next
;
617 simple_unlock(&mountlist_slock
);
620 extern void vm_countdirtypages(void);
621 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
622 extern unsigned int dp_pgins
, dp_pgouts
;
623 if(print_vmpage_stat
) {
624 vm_countdirtypages();
625 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
626 dp_pgins
, dp_pgouts
);
632 #endif /* DIAGNOSTIC */
637 * Change filesystem quotas.
639 struct quotactl_args
{
647 quotactl(p
, uap
, retval
)
649 register struct quotactl_args
*uap
;
652 register struct mount
*mp
;
656 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
657 if (error
= namei(&nd
))
659 mp
= nd
.ni_vp
->v_mount
;
661 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
666 * Get filesystem statistics.
674 statfs(p
, uap
, retval
)
676 register struct statfs_args
*uap
;
679 register struct mount
*mp
;
680 register struct statfs
*sp
;
684 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
685 if (error
= namei(&nd
))
687 mp
= nd
.ni_vp
->v_mount
;
690 if (error
= VFS_STATFS(mp
, sp
, p
))
692 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
693 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
694 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
698 * Get filesystem statistics.
700 struct fstatfs_args
{
706 fstatfs(p
, uap
, retval
)
708 register struct fstatfs_args
*uap
;
713 register struct statfs
*sp
;
716 if (error
= getvnode(p
, uap
->fd
, &fp
))
718 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
722 if (error
= VFS_STATFS(mp
, sp
, p
))
724 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
725 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
726 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
730 * Get statistics on all filesystems.
732 struct getfsstat_args
{
738 getfsstat(p
, uap
, retval
)
740 register struct getfsstat_args
*uap
;
743 register struct mount
*mp
, *nmp
;
744 register struct statfs
*sp
;
746 long count
, maxcount
, error
;
748 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
749 sfsp
= (caddr_t
)uap
->buf
;
751 simple_lock(&mountlist_slock
);
752 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
753 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
754 nmp
= mp
->mnt_list
.cqe_next
;
757 if (sfsp
&& count
< maxcount
) {
760 * If MNT_NOWAIT is specified, do not refresh the
761 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
763 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
764 (uap
->flags
& MNT_WAIT
)) &&
765 (error
= VFS_STATFS(mp
, sp
, p
))) {
766 simple_lock(&mountlist_slock
);
767 nmp
= mp
->mnt_list
.cqe_next
;
771 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
772 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
777 simple_lock(&mountlist_slock
);
778 nmp
= mp
->mnt_list
.cqe_next
;
781 simple_unlock(&mountlist_slock
);
782 if (sfsp
&& count
> maxcount
)
790 ogetfsstat(p
, uap
, retval
)
792 register struct getfsstat_args
*uap
;
795 register struct mount
*mp
, *nmp
;
796 register struct statfs
*sp
;
798 long count
, maxcount
, error
;
800 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
801 sfsp
= (caddr_t
)uap
->buf
;
803 simple_lock(&mountlist_slock
);
804 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
805 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
806 nmp
= mp
->mnt_list
.cqe_next
;
809 if (sfsp
&& count
< maxcount
) {
812 * If MNT_NOWAIT is specified, do not refresh the
813 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
815 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
816 (uap
->flags
& MNT_WAIT
)) &&
817 (error
= VFS_STATFS(mp
, sp
, p
))) {
818 simple_lock(&mountlist_slock
);
819 nmp
= mp
->mnt_list
.cqe_next
;
823 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
824 error
= copyout((caddr_t
)sp
, sfsp
,
825 sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
));
828 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
831 simple_lock(&mountlist_slock
);
832 nmp
= mp
->mnt_list
.cqe_next
;
835 simple_unlock(&mountlist_slock
);
836 if (sfsp
&& count
> maxcount
)
845 * Change current working directory to a given file descriptor.
852 fchdir(p
, uap
, retval
)
854 struct fchdir_args
*uap
;
857 register struct filedesc
*fdp
= p
->p_fd
;
858 struct vnode
*vp
, *tdp
, *tvp
;
863 if (error
= getvnode(p
, uap
->fd
, &fp
))
865 vp
= (struct vnode
*)fp
->f_data
;
867 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
868 if (vp
->v_type
!= VDIR
)
871 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
872 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
873 if (vfs_busy(mp
, 0, 0, p
))
875 error
= VFS_ROOT(mp
, &tdp
);
886 VOP_UNLOCK(vp
, 0, p
);
894 * Change current working directory (``.'').
901 chdir(p
, uap
, retval
)
903 struct chdir_args
*uap
;
906 register struct filedesc
*fdp
= p
->p_fd
;
911 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
913 if (error
= change_dir(&nd
, p
))
916 fdp
->fd_cdir
= nd
.ni_vp
;
922 * Change notion of root (``/'') directory.
929 chroot(p
, uap
, retval
)
931 struct chroot_args
*uap
;
934 register struct filedesc
*fdp
= p
->p_fd
;
937 boolean_t shared_regions_active
;
940 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
943 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
945 if (error
= change_dir(&nd
, p
))
948 if(p
->p_flag
& P_NOSHLIB
) {
949 shared_regions_active
= FALSE
;
951 shared_regions_active
= TRUE
;
954 if(error
= clone_system_shared_regions(shared_regions_active
)) {
960 fdp
->fd_rdir
= nd
.ni_vp
;
967 * Common routine for chroot and chdir.
971 register struct nameidata
*ndp
;
977 if (error
= namei(ndp
))
980 if (vp
->v_type
!= VDIR
)
983 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
987 VOP_UNLOCK(vp
, 0, p
);
992 * Check permissions, allocate an open file structure,
993 * and call the device open routine if any.
1001 open(p
, uap
, retval
)
1003 register struct open_args
*uap
;
1006 register struct filedesc
*fdp
= p
->p_fd
;
1007 register struct file
*fp
;
1008 register struct vnode
*vp
;
1009 int flags
, cmode
, oflags
;
1011 int type
, indx
, error
;
1013 struct nameidata nd
;
1014 extern struct fileops vnops
;
1016 oflags
= uap
->flags
;
1017 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1019 flags
= FFLAGS(uap
->flags
);
1020 if (error
= falloc(p
, &nfp
, &indx
))
1023 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
1024 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1025 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1026 if (error
= vn_open(&nd
, flags
, cmode
)) {
1028 if ((error
== ENODEV
|| error
== ENXIO
) &&
1029 p
->p_dupfd
>= 0 && /* XXX from fdopen */
1031 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1035 if (error
== ERESTART
)
1042 fp
->f_flag
= flags
& FMASK
;
1043 fp
->f_type
= DTYPE_VNODE
;
1045 fp
->f_data
= (caddr_t
)vp
;
1046 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1047 lf
.l_whence
= SEEK_SET
;
1050 if (flags
& O_EXLOCK
)
1051 lf
.l_type
= F_WRLCK
;
1053 lf
.l_type
= F_RDLCK
;
1055 if ((flags
& FNONBLOCK
) == 0)
1057 VOP_UNLOCK(vp
, 0, p
);
1058 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
1059 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
1064 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1065 fp
->f_flag
|= FHASLOCK
;
1067 VOP_UNLOCK(vp
, 0, p
);
1068 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1077 struct ocreat_args
{
1082 ocreat(p
, uap
, retval
)
1084 register struct ocreat_args
*uap
;
1087 struct open_args nuap
;
1089 nuap
.path
= uap
->path
;
1090 nuap
.mode
= uap
->mode
;
1091 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1092 return (open(p
, &nuap
, retval
));
1094 #endif /* COMPAT_43 */
1097 * Create a special file.
1106 mknod(p
, uap
, retval
)
1108 register struct mknod_args
*uap
;
1111 register struct vnode
*vp
;
1115 struct nameidata nd
;
1117 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1120 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1121 if (error
= namei(&nd
))
1128 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1129 vattr
.va_rdev
= uap
->dev
;
1132 switch (uap
->mode
& S_IFMT
) {
1133 case S_IFMT
: /* used by badsect to flag bad sectors */
1134 vattr
.va_type
= VBAD
;
1137 vattr
.va_type
= VCHR
;
1140 vattr
.va_type
= VBLK
;
1151 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1153 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1155 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1158 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1159 &nd
.ni_cnd
, &vattr
);
1162 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1163 if (nd
.ni_dvp
== vp
)
1174 * Create a named pipe.
1176 struct mkfifo_args
{
1182 mkfifo(p
, uap
, retval
)
1184 register struct mkfifo_args
*uap
;
1189 struct nameidata nd
;
1192 return (EOPNOTSUPP
);
1195 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1196 if (error
= namei(&nd
))
1198 if (nd
.ni_vp
!= NULL
) {
1199 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1200 if (nd
.ni_dvp
== nd
.ni_vp
)
1208 vattr
.va_type
= VFIFO
;
1209 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1210 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1211 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1216 * Make a hard file link.
1224 link(p
, uap
, retval
)
1226 register struct link_args
*uap
;
1229 register struct vnode
*vp
;
1230 struct nameidata nd
;
1234 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1235 if (error
= namei(&nd
))
1238 if (vp
->v_type
== VDIR
)
1239 error
= EPERM
; /* POSIX */
1241 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1242 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1243 nd
.ni_dirp
= uap
->link
;
1244 if ((error
= namei(&nd
)) == 0) {
1245 if (nd
.ni_vp
!= NULL
)
1248 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1250 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1251 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1253 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1254 if (nd
.ni_dvp
== nd
.ni_vp
)
1268 * Make a symbolic link.
1270 struct symlink_args
{
1276 symlink(p
, uap
, retval
)
1278 register struct symlink_args
*uap
;
1284 struct nameidata nd
;
1286 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1287 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1290 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1291 if (error
= namei(&nd
))
1294 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1295 if (nd
.ni_dvp
== nd
.ni_vp
)
1304 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1305 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1306 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1308 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1313 * Delete a whiteout from the filesystem.
1315 struct undelete_args
{
1320 undelete(p
, uap
, retval
)
1322 register struct undelete_args
*uap
;
1326 struct nameidata nd
;
1329 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1335 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1336 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1337 if (nd
.ni_dvp
== nd
.ni_vp
)
1346 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1347 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1348 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1354 * Delete a name from the filesystem.
1356 struct unlink_args
{
1361 _unlink(p
, uap
, retval
, nodelbusy
)
1363 struct unlink_args
*uap
;
1367 register struct vnode
*vp
;
1369 struct nameidata nd
;
1372 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1373 /* with Carbon semantics, busy files cannot be deleted */
1375 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1376 if (error
= namei(&nd
))
1379 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1380 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1382 if (vp
->v_type
== VDIR
)
1383 error
= EPERM
; /* POSIX */
1386 * The root of a mounted filesystem cannot be deleted.
1388 * XXX: can this only be a VDIR case?
1390 if (vp
->v_flag
& VROOT
)
1395 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1396 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1398 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1399 if (nd
.ni_dvp
== vp
)
1410 * Delete a name from the filesystem using POSIX semantics.
1413 unlink(p
, uap
, retval
)
1415 struct unlink_args
*uap
;
1418 return _unlink(p
, uap
, retval
, 0);
1422 * Delete a name from the filesystem using Carbon semantics.
1425 delete(p
, uap
, retval
)
1427 struct unlink_args
*uap
;
1430 return _unlink(p
, uap
, retval
, 1);
1434 * Reposition read/write file offset.
1438 #ifdef DOUBLE_ALIGN_PARAMS
1445 lseek(p
, uap
, retval
)
1447 register struct lseek_args
*uap
;
1450 struct ucred
*cred
= p
->p_ucred
;
1455 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1457 if (fp
->f_type
!= DTYPE_VNODE
)
1459 switch (uap
->whence
) {
1461 fp
->f_offset
+= uap
->offset
;
1465 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1467 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1470 fp
->f_offset
= uap
->offset
;
1475 *(off_t
*)retval
= fp
->f_offset
;
1481 * Reposition read/write file offset.
1483 struct olseek_args
{
1489 olseek(p
, uap
, retval
)
1491 register struct olseek_args
*uap
;
1494 struct lseek_args
/* {
1496 #ifdef DOUBLE_ALIGN_PARAMS
1497 syscallarg(int) pad;
1499 syscallarg(off_t) offset;
1500 syscallarg(int) whence;
1506 nuap
.offset
= uap
->offset
;
1507 nuap
.whence
= uap
->whence
;
1508 error
= lseek(p
, &nuap
, &qret
);
1509 *(long *)retval
= qret
;
1512 #endif /* COMPAT_43 */
1515 * Check access permissions.
1517 struct access_args
{
1522 access(p
, uap
, retval
)
1524 register struct access_args
*uap
;
1527 register struct ucred
*cred
= p
->p_ucred
;
1528 register struct vnode
*vp
;
1529 int error
, flags
, t_gid
, t_uid
;
1530 struct nameidata nd
;
1532 t_uid
= cred
->cr_uid
;
1533 t_gid
= cred
->cr_groups
[0];
1534 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1535 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1536 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1538 if (error
= namei(&nd
))
1542 /* Flags == 0 means only check for existence. */
1545 if (uap
->flags
& R_OK
)
1547 if (uap
->flags
& W_OK
)
1549 if (uap
->flags
& X_OK
)
1551 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1552 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1556 cred
->cr_uid
= t_uid
;
1557 cred
->cr_groups
[0] = t_gid
;
1563 * Get file status; this version follows links.
1571 ostat(p
, uap
, retval
)
1573 register struct ostat_args
*uap
;
1579 struct nameidata nd
;
1581 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1583 if (error
= namei(&nd
))
1585 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1590 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1595 * Get file status; this version does not follow links.
1597 struct olstat_args
{
1603 olstat(p
, uap
, retval
)
1605 register struct olstat_args
*uap
;
1608 struct vnode
*vp
, *dvp
;
1609 struct stat sb
, sb1
;
1612 struct nameidata nd
;
1614 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1616 if (error
= namei(&nd
))
1619 * For symbolic links, always return the attributes of its
1620 * containing directory, except for mode, size, and links.
1624 if (vp
->v_type
!= VLNK
) {
1629 error
= vn_stat(vp
, &sb
, p
);
1634 error
= vn_stat(dvp
, &sb
, p
);
1640 error
= vn_stat(vp
, &sb1
, p
);
1644 sb
.st_mode
&= ~S_IFDIR
;
1645 sb
.st_mode
|= S_IFLNK
;
1646 sb
.st_nlink
= sb1
.st_nlink
;
1647 sb
.st_size
= sb1
.st_size
;
1648 sb
.st_blocks
= sb1
.st_blocks
;
1651 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1656 * Convert from an old to a new stat structure.
1664 ost
->st_dev
= st
->st_dev
;
1665 ost
->st_ino
= st
->st_ino
;
1666 ost
->st_mode
= st
->st_mode
;
1667 ost
->st_nlink
= st
->st_nlink
;
1668 ost
->st_uid
= st
->st_uid
;
1669 ost
->st_gid
= st
->st_gid
;
1670 ost
->st_rdev
= st
->st_rdev
;
1671 if (st
->st_size
< (quad_t
)1 << 32)
1672 ost
->st_size
= st
->st_size
;
1675 ost
->st_atime
= st
->st_atime
;
1676 ost
->st_mtime
= st
->st_mtime
;
1677 ost
->st_ctime
= st
->st_ctime
;
1678 ost
->st_blksize
= st
->st_blksize
;
1679 ost
->st_blocks
= st
->st_blocks
;
1680 ost
->st_flags
= st
->st_flags
;
1681 ost
->st_gen
= st
->st_gen
;
1683 #endif /* COMPAT_43 */
1686 * Get file status; this version follows links.
1694 stat(p
, uap
, retval
)
1696 register struct stat_args
*uap
;
1701 struct nameidata nd
;
1703 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1705 if (error
= namei(&nd
))
1707 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1711 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1716 * Get file status; this version does not follow links.
1724 lstat(p
, uap
, retval
)
1726 register struct lstat_args
*uap
;
1730 struct vnode
*vp
, *dvp
;
1731 struct stat sb
, sb1
;
1732 struct nameidata nd
;
1734 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1736 if (error
= namei(&nd
))
1739 * For symbolic links, always return the attributes of its containing
1740 * directory, except for mode, size, inode number, and links.
1744 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1749 error
= vn_stat(vp
, &sb
, p
);
1753 if (vp
->v_type
== VLNK
)
1754 sb
.st_mode
|= S_IFLNK
;
1756 error
= vn_stat(dvp
, &sb
, p
);
1762 error
= vn_stat(vp
, &sb1
, p
);
1766 sb
.st_mode
&= ~S_IFDIR
;
1767 sb
.st_mode
|= S_IFLNK
;
1768 sb
.st_nlink
= sb1
.st_nlink
;
1769 sb
.st_size
= sb1
.st_size
;
1770 sb
.st_blocks
= sb1
.st_blocks
;
1771 sb
.st_ino
= sb1
.st_ino
;
1773 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1778 * Get configurable pathname variables.
1780 struct pathconf_args
{
1786 pathconf(p
, uap
, retval
)
1788 register struct pathconf_args
*uap
;
1792 struct nameidata nd
;
1794 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1796 if (error
= namei(&nd
))
1798 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1804 * Return target name of a symbolic link.
1806 struct readlink_args
{
1813 readlink(p
, uap
, retval
)
1815 register struct readlink_args
*uap
;
1818 register struct vnode
*vp
;
1822 struct nameidata nd
;
1824 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1826 if (error
= namei(&nd
))
1829 if (vp
->v_type
!= VLNK
)
1832 aiov
.iov_base
= uap
->buf
;
1833 aiov
.iov_len
= uap
->count
;
1834 auio
.uio_iov
= &aiov
;
1835 auio
.uio_iovcnt
= 1;
1836 auio
.uio_offset
= 0;
1837 auio
.uio_rw
= UIO_READ
;
1838 auio
.uio_segflg
= UIO_USERSPACE
;
1840 auio
.uio_resid
= uap
->count
;
1841 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1844 *retval
= uap
->count
- auio
.uio_resid
;
1849 * Change flags of a file given a path name.
1851 struct chflags_args
{
1857 chflags(p
, uap
, retval
)
1859 register struct chflags_args
*uap
;
1862 register struct vnode
*vp
;
1865 struct nameidata nd
;
1867 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1868 if (error
= namei(&nd
))
1871 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1872 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1874 vattr
.va_flags
= uap
->flags
;
1875 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1881 * Change flags of a file given a file descriptor.
1883 struct fchflags_args
{
1889 fchflags(p
, uap
, retval
)
1891 register struct fchflags_args
*uap
;
1899 if (error
= getvnode(p
, uap
->fd
, &fp
))
1901 vp
= (struct vnode
*)fp
->f_data
;
1902 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1903 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1905 vattr
.va_flags
= uap
->flags
;
1906 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1907 VOP_UNLOCK(vp
, 0, p
);
1912 * Change mode of a file given path name.
1920 chmod(p
, uap
, retval
)
1922 register struct chmod_args
*uap
;
1925 register struct vnode
*vp
;
1928 struct nameidata nd
;
1930 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1931 if (error
= namei(&nd
))
1934 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1935 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1937 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1938 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1944 * Change mode of a file given a file descriptor.
1946 struct fchmod_args
{
1952 fchmod(p
, uap
, retval
)
1954 register struct fchmod_args
*uap
;
1962 if (error
= getvnode(p
, uap
->fd
, &fp
))
1964 vp
= (struct vnode
*)fp
->f_data
;
1965 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1966 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1968 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1969 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1970 VOP_UNLOCK(vp
, 0, p
);
1975 * Set ownership given a path name.
1984 chown(p
, uap
, retval
)
1986 register struct chown_args
*uap
;
1989 register struct vnode
*vp
;
1992 struct nameidata nd
;
1994 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1995 if (error
= namei(&nd
))
2000 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2001 * by looking for chown() calls on /dev/console from a console process.
2003 if ((vp
) && (vp
->v_specinfo
) &&
2004 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2005 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2006 console_user
= uap
->uid
;
2009 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2010 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2012 vattr
.va_uid
= uap
->uid
;
2013 vattr
.va_gid
= uap
->gid
;
2014 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2020 * Set ownership given a file descriptor.
2022 struct fchown_args
{
2029 fchown(p
, uap
, retval
)
2031 register struct fchown_args
*uap
;
2039 if (error
= getvnode(p
, uap
->fd
, &fp
))
2041 vp
= (struct vnode
*)fp
->f_data
;
2042 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2043 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2045 vattr
.va_uid
= uap
->uid
;
2046 vattr
.va_gid
= uap
->gid
;
2047 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2048 VOP_UNLOCK(vp
, 0, p
);
2053 getutimes(usrtvp
, tsp
)
2054 const struct timeval
*usrtvp
;
2055 struct timespec
*tsp
;
2057 struct timeval tv
[2];
2060 if (usrtvp
== NULL
) {
2062 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2065 if ((error
= copyin(usrtvp
, tv
, sizeof (tv
))) != 0)
2067 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2068 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
2074 setutimes(p
, vp
, ts
, nullflag
)
2077 const struct timespec
*ts
;
2083 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2084 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2088 vattr
.va_atime
= ts
[0];
2089 vattr
.va_mtime
= ts
[1];
2091 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
2092 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2093 VOP_UNLOCK(vp
, 0, p
);
2099 * Set the access and modification times of a file.
2101 struct utimes_args
{
2103 struct timeval
*tptr
;
2107 utimes(p
, uap
, retval
)
2109 register struct utimes_args
*uap
;
2112 struct timespec ts
[2];
2113 struct timeval
*usrtvp
;
2115 struct nameidata nd
;
2118 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2120 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2121 if ((error
= namei(&nd
)) != 0)
2123 error
= setutimes(p
, nd
.ni_vp
, ts
, usrtvp
== NULL
);
2129 * Set the access and modification times of a file.
2131 struct futimes_args
{
2133 struct timeval
*tptr
;
2137 futimes(p
, uap
, retval
)
2139 register struct futimes_args
*uap
;
2142 struct timespec ts
[2];
2144 struct timeval
*usrtvp
;
2148 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2150 if ((error
= getvnode(p
, uap
->fd
, &fp
)) != 0)
2152 return setutimes(p
, (struct vnode
*)fp
->f_data
, ts
, usrtvp
== NULL
);
2156 * Truncate a file given its path name.
2158 struct truncate_args
{
2160 #ifdef DOUBLE_ALIGN_PARAMS
2167 truncate(p
, uap
, retval
)
2169 register struct truncate_args
*uap
;
2172 register struct vnode
*vp
;
2175 struct nameidata nd
;
2177 if (uap
->length
< 0)
2179 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2180 if (error
= namei(&nd
))
2183 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2184 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2185 if (vp
->v_type
== VDIR
)
2187 else if ((error
= vn_writechk(vp
)) == 0 &&
2188 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2190 vattr
.va_size
= uap
->length
;
2191 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2198 * Truncate a file given a file descriptor.
2200 struct ftruncate_args
{
2202 #ifdef DOUBLE_ALIGN_PARAMS
2209 ftruncate(p
, uap
, retval
)
2211 register struct ftruncate_args
*uap
;
2219 if (uap
->length
< 0)
2222 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2225 if (fp
->f_type
== DTYPE_PSXSHM
) {
2226 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2228 if (fp
->f_type
!= DTYPE_VNODE
)
2231 if ((fp
->f_flag
& FWRITE
) == 0)
2233 vp
= (struct vnode
*)fp
->f_data
;
2234 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2235 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2236 if (vp
->v_type
== VDIR
)
2238 else if ((error
= vn_writechk(vp
)) == 0) {
2240 vattr
.va_size
= uap
->length
;
2241 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2243 VOP_UNLOCK(vp
, 0, p
);
2249 * Truncate a file given its path name.
2251 struct otruncate_args
{
2257 otruncate(p
, uap
, retval
)
2259 register struct otruncate_args
*uap
;
2262 struct truncate_args
/* {
2263 syscallarg(char *) path;
2264 #ifdef DOUBLE_ALIGN_PARAMS
2265 syscallarg(int) pad;
2267 syscallarg(off_t) length;
2270 nuap
.path
= uap
->path
;
2271 nuap
.length
= uap
->length
;
2272 return (truncate(p
, &nuap
, retval
));
2276 * Truncate a file given a file descriptor.
2278 struct oftruncate_args
{
2284 oftruncate(p
, uap
, retval
)
2286 register struct oftruncate_args
*uap
;
2289 struct ftruncate_args
/* {
2291 #ifdef DOUBLE_ALIGN_PARAMS
2292 syscallarg(int) pad;
2294 syscallarg(off_t) length;
2298 nuap
.length
= uap
->length
;
2299 return (ftruncate(p
, &nuap
, retval
));
2301 #endif /* COMPAT_43 */
2304 * Sync an open file.
2311 fsync(p
, uap
, retval
)
2313 struct fsync_args
*uap
;
2316 register struct vnode
*vp
;
2320 if (error
= getvnode(p
, uap
->fd
, &fp
))
2322 vp
= (struct vnode
*)fp
->f_data
;
2323 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2324 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2325 VOP_UNLOCK(vp
, 0, p
);
2330 * Duplicate files. Source must be a file, target must be a file or
2334 struct copyfile_args
{
2342 copyfile(p
, uap
, retval
)
2344 register struct copyfile_args
*uap
;
2347 register struct vnode
*tvp
, *fvp
, *tdvp
;
2348 register struct ucred
*cred
= p
->p_ucred
;
2349 struct nameidata fromnd
, tond
;
2352 /* Check that the flags are valid.
2355 if (uap
->flags
& ~CPF_MASK
) {
2359 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2361 if (error
= namei(&fromnd
))
2365 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2366 UIO_USERSPACE
, uap
->to
, p
);
2367 if (error
= namei(&tond
)) {
2374 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2380 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2385 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2391 * If source is the same as the destination (that is the
2392 * same inode number) then there is nothing to do.
2393 * (fixed to have POSIX semantics - CSM 3/2/98)
2399 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2401 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2410 vrele(tond
.ni_startdir
);
2411 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2413 if (fromnd
.ni_startdir
)
2414 vrele(fromnd
.ni_startdir
);
2415 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2422 * Rename files. Source and destination must either both be directories,
2423 * or both not be directories. If target is a directory, it must be empty.
2425 struct rename_args
{
2431 rename(p
, uap
, retval
)
2433 register struct rename_args
*uap
;
2436 register struct vnode
*tvp
, *fvp
, *tdvp
;
2437 struct nameidata fromnd
, tond
;
2440 int casesense
,casepres
;
2445 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2447 if (error
= namei(&fromnd
))
2451 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2452 UIO_USERSPACE
, uap
->to
, p
);
2453 if (fromnd
.ni_vp
->v_type
== VDIR
)
2454 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2455 if (error
= namei(&tond
)) {
2456 /* Translate error code for rename("dir1", "dir2/."). */
2457 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
2459 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2460 vrele(fromnd
.ni_dvp
);
2468 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2471 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2479 * If source is the same as the destination (that is the
2480 * same inode number) then there is nothing to do... EXCEPT if the
2481 * underlying file system supports case insensitivity and is case
2482 * preserving. Then a special case is made, i.e. foo -> Foo.
2484 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2485 * and _PC_CASE_PRESERVING can have this exception, and they need to
2486 * handle the special case of getting the same vnode as target and
2487 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2488 * so not to cause locking problems. There is a single reference on tvp.
2490 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2491 * that correct behaviour then is just to remove the source (link)
2493 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
) {
2494 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2495 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2496 fromnd
.ni_cnd
.cn_namelen
)) {
2497 error
= -1; /* Default "unix" behavior */
2498 } else { /* probe for file system specifics */
2499 if (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
))
2501 if (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
))
2503 if (!casesense
&& casepres
)
2504 vput(tvp
); /* Unlock target and drop ref */
2509 * Allow the renaming of mount points.
2510 * - target must not exist
2511 * - target must reside in the same directory as source
2512 * - union mounts cannot be renamed
2513 * - "/" cannot be renamed
2516 (fvp
->v_flag
& VROOT
) &&
2517 (fvp
->v_type
== VDIR
) &&
2519 (fvp
->v_mountedhere
== NULL
) &&
2520 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2521 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2522 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2524 /* switch fvp to the covered vnode */
2525 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2533 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2534 if (fromnd
.ni_dvp
!= tdvp
)
2535 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2537 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2538 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2539 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2544 * update filesystem's mount point data
2547 char *cp
, *pathend
, *mpname
;
2554 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2555 mp
= fvp
->v_mountedhere
;
2557 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2562 VOP_UNLOCK(fvp
, 0, p
);
2564 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2565 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2567 /* find current mount point prefix */
2568 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2569 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2573 /* find last component of target name */
2574 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2578 /* append name to prefix */
2579 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2580 bzero(pathend
, maxlen
);
2581 strncpy(pathend
, mpname
, maxlen
- 1);
2583 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2589 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2596 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2597 vrele(fromnd
.ni_dvp
);
2601 vrele(tond
.ni_startdir
);
2602 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2604 if (fromnd
.ni_startdir
)
2605 vrele(fromnd
.ni_startdir
);
2606 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2613 * Make a directory file.
2621 mkdir(p
, uap
, retval
)
2623 register struct mkdir_args
*uap
;
2626 register struct vnode
*vp
;
2629 struct nameidata nd
;
2632 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2633 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2634 if (error
= namei(&nd
))
2638 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2639 if (nd
.ni_dvp
== vp
)
2647 vattr
.va_type
= VDIR
;
2648 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2649 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2650 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2657 * Remove a directory file.
2664 rmdir(p
, uap
, retval
)
2666 struct rmdir_args
*uap
;
2669 register struct vnode
*vp
;
2671 struct nameidata nd
;
2674 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2676 if (error
= namei(&nd
))
2679 if (vp
->v_type
!= VDIR
) {
2684 * No rmdir "." please.
2686 if (nd
.ni_dvp
== vp
) {
2691 * The root of a mounted filesystem cannot be deleted.
2693 if (vp
->v_flag
& VROOT
)
2697 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2698 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2699 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2701 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2702 if (nd
.ni_dvp
== vp
)
2713 * Read a block of directory entries in a file system independent format.
2715 struct ogetdirentries_args
{
2722 ogetdirentries(p
, uap
, retval
)
2724 register struct ogetdirentries_args
*uap
;
2727 register struct vnode
*vp
;
2729 struct uio auio
, kuio
;
2730 struct iovec aiov
, kiov
;
2731 struct dirent
*dp
, *edp
;
2733 int error
, eofflag
, readcnt
;
2736 if (error
= getvnode(p
, uap
->fd
, &fp
))
2738 if ((fp
->f_flag
& FREAD
) == 0)
2740 vp
= (struct vnode
*)fp
->f_data
;
2742 if (vp
->v_type
!= VDIR
)
2744 aiov
.iov_base
= uap
->buf
;
2745 aiov
.iov_len
= uap
->count
;
2746 auio
.uio_iov
= &aiov
;
2747 auio
.uio_iovcnt
= 1;
2748 auio
.uio_rw
= UIO_READ
;
2749 auio
.uio_segflg
= UIO_USERSPACE
;
2751 auio
.uio_resid
= uap
->count
;
2752 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2753 loff
= auio
.uio_offset
= fp
->f_offset
;
2754 # if (BYTE_ORDER != LITTLE_ENDIAN)
2755 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2756 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2757 (int *)0, (u_long
*)0);
2758 fp
->f_offset
= auio
.uio_offset
;
2763 kuio
.uio_iov
= &kiov
;
2764 kuio
.uio_segflg
= UIO_SYSSPACE
;
2765 kiov
.iov_len
= uap
->count
;
2766 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2767 kiov
.iov_base
= dirbuf
;
2768 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2769 (int *)0, (u_long
*)0);
2770 fp
->f_offset
= kuio
.uio_offset
;
2772 readcnt
= uap
->count
- kuio
.uio_resid
;
2773 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2774 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2775 # if (BYTE_ORDER == LITTLE_ENDIAN)
2777 * The expected low byte of
2778 * dp->d_namlen is our dp->d_type.
2779 * The high MBZ byte of dp->d_namlen
2780 * is our dp->d_namlen.
2782 dp
->d_type
= dp
->d_namlen
;
2786 * The dp->d_type is the high byte
2787 * of the expected dp->d_namlen,
2788 * so must be zero'ed.
2792 if (dp
->d_reclen
> 0) {
2793 dp
= (struct dirent
*)
2794 ((char *)dp
+ dp
->d_reclen
);
2801 error
= uiomove(dirbuf
, readcnt
, &auio
);
2803 FREE(dirbuf
, M_TEMP
);
2805 VOP_UNLOCK(vp
, 0, p
);
2811 extern int (**union_vnodeop_p
)(void *);
2812 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2814 if ((uap
->count
== auio
.uio_resid
) &&
2815 (vp
->v_op
== union_vnodeop_p
)) {
2818 lvp
= union_dircache(vp
, p
);
2819 if (lvp
!= NULLVP
) {
2823 * If the directory is opaque,
2824 * then don't show lower entries
2826 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2827 if (va
.va_flags
& OPAQUE
) {
2833 if (lvp
!= NULLVP
) {
2834 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2839 VOP_UNLOCK(lvp
, 0, p
);
2840 fp
->f_data
= (caddr_t
) lvp
;
2842 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2853 if ((uap
->count
== auio
.uio_resid
) &&
2854 (vp
->v_flag
& VROOT
) &&
2855 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2856 struct vnode
*tvp
= vp
;
2857 vp
= vp
->v_mount
->mnt_vnodecovered
;
2859 fp
->f_data
= (caddr_t
) vp
;
2864 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2866 *retval
= uap
->count
- auio
.uio_resid
;
2869 #endif /* COMPAT_43 */
2872 * Read a block of directory entries in a file system independent format.
2874 struct getdirentries_args
{
2881 getdirentries(p
, uap
, retval
)
2883 register struct getdirentries_args
*uap
;
2886 register struct vnode
*vp
;
2893 if (error
= getvnode(p
, uap
->fd
, &fp
))
2895 if ((fp
->f_flag
& FREAD
) == 0)
2897 vp
= (struct vnode
*)fp
->f_data
;
2899 if (vp
->v_type
!= VDIR
)
2901 aiov
.iov_base
= uap
->buf
;
2902 aiov
.iov_len
= uap
->count
;
2903 auio
.uio_iov
= &aiov
;
2904 auio
.uio_iovcnt
= 1;
2905 auio
.uio_rw
= UIO_READ
;
2906 auio
.uio_segflg
= UIO_USERSPACE
;
2908 auio
.uio_resid
= uap
->count
;
2909 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2910 loff
= auio
.uio_offset
= fp
->f_offset
;
2911 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2912 (int *)0, (u_long
*)0);
2913 fp
->f_offset
= auio
.uio_offset
;
2914 VOP_UNLOCK(vp
, 0, p
);
2920 extern int (**union_vnodeop_p
)(void *);
2921 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2923 if ((uap
->count
== auio
.uio_resid
) &&
2924 (vp
->v_op
== union_vnodeop_p
)) {
2927 lvp
= union_dircache(vp
, p
);
2928 if (lvp
!= NULLVP
) {
2932 * If the directory is opaque,
2933 * then don't show lower entries
2935 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2936 if (va
.va_flags
& OPAQUE
) {
2942 if (lvp
!= NULLVP
) {
2943 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2948 VOP_UNLOCK(lvp
, 0, p
);
2949 fp
->f_data
= (caddr_t
) lvp
;
2951 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2962 if ((uap
->count
== auio
.uio_resid
) &&
2963 (vp
->v_flag
& VROOT
) &&
2964 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2965 struct vnode
*tvp
= vp
;
2966 vp
= vp
->v_mount
->mnt_vnodecovered
;
2968 fp
->f_data
= (caddr_t
) vp
;
2973 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2975 *retval
= uap
->count
- auio
.uio_resid
;
2980 * Set the mode mask for creation of filesystem nodes.
2986 umask(p
, uap
, retval
)
2988 struct umask_args
*uap
;
2991 register struct filedesc
*fdp
;
2994 *retval
= fdp
->fd_cmask
;
2995 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
3000 * Void all references to file by ripping underlying filesystem
3003 struct revoke_args
{
3008 revoke(p
, uap
, retval
)
3010 register struct revoke_args
*uap
;
3013 register struct vnode
*vp
;
3016 struct nameidata nd
;
3018 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
3019 if (error
= namei(&nd
))
3022 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
3024 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
3025 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
3027 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
3028 VOP_REVOKE(vp
, REVOKEALL
);
3035 * Convert a user file descriptor to a kernel file entry.
3038 getvnode(p
, fd
, fpp
)
3046 if (error
= fdgetf(p
, fd
, &fp
))
3048 if (fp
->f_type
!= DTYPE_VNODE
)
3055 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3056 * The following system calls are designed to support features
3057 * which are specific to the HFS & HFS Plus volume formats
3060 #ifdef __APPLE_API_OBSOLETE
3062 /************************************************/
3063 /* *** Following calls will be deleted soon *** */
3064 /************************************************/
3067 * Make a complex file. A complex file is one with multiple forks (data streams)
3069 struct mkcomplex_args
{
3070 const char *path
; /* pathname of the file to be created */
3071 mode_t mode
; /* access mode for the newly created file */
3072 u_long type
; /* format of the complex file */
3076 mkcomplex(p
,uap
,retval
)
3078 register struct mkcomplex_args
*uap
;
3084 struct nameidata nd
;
3086 /* mkcomplex wants the directory vnode locked so do that here */
3088 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3089 if (error
= namei(&nd
))
3092 /* Set the attributes as specified by the user */
3095 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
3096 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
3098 /* The mkcomplex call promises to release the parent vnode pointer
3099 * even an an error case so don't do it here unless the operation
3100 * is not supported. In that case, there isn't anyone to unlock the parent
3101 * The vnode pointer to the file will also be released.
3106 if (error
== EOPNOTSUPP
)
3113 } /* end of mkcomplex system call */
3116 * Extended stat call which returns volumeid and vnodeid as well as other info
3119 const char *path
; /* pathname of the target file */
3120 struct vstat
*vsb
; /* vstat structure for returned info */
3126 register struct statv_args
*uap
;
3130 return (EOPNOTSUPP
); /* We'll just return an error for now */
3132 } /* end of statv system call */
3135 * Extended lstat call which returns volumeid and vnodeid as well as other info
3137 struct lstatv_args
{
3138 const char *path
; /* pathname of the target file */
3139 struct vstat
*vsb
; /* vstat structure for returned info */
3143 lstatv(p
,uap
,retval
)
3145 register struct lstatv_args
*uap
;
3149 return (EOPNOTSUPP
); /* We'll just return an error for now */
3150 } /* end of lstatv system call */
3153 * Extended fstat call which returns volumeid and vnodeid as well as other info
3155 struct fstatv_args
{
3156 int fd
; /* file descriptor of the target file */
3157 struct vstat
*vsb
; /* vstat structure for returned info */
3161 fstatv(p
,uap
,retval
)
3163 register struct fstatv_args
*uap
;
3167 return (EOPNOTSUPP
); /* We'll just return an error for now */
3168 } /* end of fstatv system call */
3171 /************************************************/
3172 /* *** Preceding calls will be deleted soon *** */
3173 /************************************************/
3175 #endif /* __APPLE_API_OBSOLETE */
3179 * Obtain attribute information about a file system object
3182 struct getattrlist_args
{
3183 const char *path
; /* pathname of the target object */
3184 struct attrlist
* alist
; /* Attributes desired by the user */
3185 void * attributeBuffer
; /* buffer to hold returned attributes */
3186 size_t bufferSize
; /* size of the return buffer */
3187 unsigned long options
; /* options (follow/don't follow) */
3191 getattrlist (p
,uap
,retval
)
3193 register struct getattrlist_args
*uap
;
3198 struct nameidata nd
;
3201 struct attrlist attributelist
;
3204 /* Get the attributes desire and do our parameter checking */
3206 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3207 sizeof (attributelist
)))
3212 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3214 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3215 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3216 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3217 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3218 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3225 /* Get the vnode for the file we are getting info on. */
3226 nameiflags
= LOCKLEAF
;
3227 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3228 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3230 if (error
= namei(&nd
))
3233 /* Set up the UIO structure for use by the vfs routine */
3236 aiov
.iov_base
= uap
->attributeBuffer
;
3237 aiov
.iov_len
= uap
->bufferSize
;
3238 auio
.uio_iov
= &aiov
;
3239 auio
.uio_iovcnt
= 1;
3240 auio
.uio_offset
= 0;
3241 auio
.uio_rw
= UIO_READ
;
3242 auio
.uio_segflg
= UIO_USERSPACE
;
3244 auio
.uio_resid
= uap
->bufferSize
;
3247 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3249 /* Unlock and release the vnode which will have been locked by namei */
3253 /* return the effort if we got one, otherwise return success */
3262 } /* end of getattrlist system call */
3267 * Set attribute information about a file system object
3270 struct setattrlist_args
{
3271 const char *path
; /* pathname of the target object */
3272 struct attrlist
* alist
; /* Attributes being set by the user */
3273 void * attributeBuffer
; /* buffer with attribute values to be set */
3274 size_t bufferSize
; /* size of the return buffer */
3275 unsigned long options
; /* options (follow/don't follow) */
3279 setattrlist (p
,uap
,retval
)
3281 register struct setattrlist_args
*uap
;
3286 struct nameidata nd
;
3289 struct attrlist alist
;
3292 /* Get the attributes desired and do our parameter checking */
3294 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3299 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3302 /* Get the vnode for the file whose attributes are being set. */
3303 nameiflags
= LOCKLEAF
;
3304 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3305 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3306 if (error
= namei(&nd
))
3309 /* Set up the UIO structure for use by the vfs routine */
3310 aiov
.iov_base
= uap
->attributeBuffer
;
3311 aiov
.iov_len
= uap
->bufferSize
;
3312 auio
.uio_iov
= &aiov
;
3313 auio
.uio_iovcnt
= 1;
3314 auio
.uio_offset
= 0;
3315 auio
.uio_rw
= UIO_WRITE
;
3316 auio
.uio_segflg
= UIO_USERSPACE
;
3318 auio
.uio_resid
= uap
->bufferSize
;
3320 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3326 } /* end of setattrlist system call */
3330 * Obtain attribute information on objects in a directory while enumerating
3331 * the directory. This call does not yet support union mounted directories.
3333 * 1.union mounted directories.
3336 struct getdirentriesattr_args
{
3337 int fd
; /* file descriptor */
3338 struct attrlist
*alist
; /* bit map of requested attributes */
3339 void *buffer
; /* buffer to hold returned attribute info */
3340 size_t buffersize
; /* size of the return buffer */
3341 u_long
*count
; /* the count of entries requested/returned */
3342 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3343 u_long
*newstate
; /* a flag to inform of changes in directory */
3344 u_long options
; /* maybe unused for now */
3348 getdirentriesattr (p
,uap
,retval
)
3350 register struct getdirentriesattr_args
*uap
;
3354 register struct vnode
*vp
;
3362 struct attrlist attributelist
;
3364 /* Get the attributes into kernel space */
3365 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3367 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3370 if (error
= getvnode(p
, uap
->fd
, &fp
))
3372 if ((fp
->f_flag
& FREAD
) == 0)
3374 vp
= (struct vnode
*)fp
->f_data
;
3376 if (vp
->v_type
!= VDIR
)
3379 /* set up the uio structure which will contain the users return buffer */
3380 aiov
.iov_base
= uap
->buffer
;
3381 aiov
.iov_len
= uap
->buffersize
;
3382 auio
.uio_iov
= &aiov
;
3383 auio
.uio_iovcnt
= 1;
3384 auio
.uio_rw
= UIO_READ
;
3385 auio
.uio_segflg
= UIO_USERSPACE
;
3387 auio
.uio_resid
= uap
->buffersize
;
3389 loff
= auio
.uio_offset
= fp
->f_offset
;
3390 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3391 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3392 actualcount
, uap
->options
, &newstate
, &eofflag
,
3393 &actualcount
, ((u_long
**)0), p
->p_cred
);
3395 VOP_UNLOCK(vp
, 0, p
);
3396 if (error
) return (error
);
3397 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3399 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3401 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3403 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3406 *retval
= eofflag
; /* similar to getdirentries */
3407 return (0); /* return error earlier, an retval of 0 or 1 now */
3409 } /* end of getdirentryattr system call */
3412 * Exchange data between two files
3415 struct exchangedata_args
{
3416 const char *path1
; /* pathname of the first swapee */
3417 const char *path2
; /* pathname of the second swapee */
3418 unsigned long options
; /* options */
3422 exchangedata (p
,uap
,retval
)
3424 register struct exchangedata_args
*uap
;
3429 struct nameidata fnd
, snd
;
3430 struct vnode
*fvp
, *svp
;
3435 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3437 /* Global lock, to prevent race condition, only one exchange at a time */
3438 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3440 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3442 if (error
= namei(&fnd
))
3447 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3449 if (error
= namei(&snd
)) {
3456 /* if the files are the same, return an inval error */
3464 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3465 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3467 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3468 if (error
) goto out
;
3470 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3471 if (error
) goto out
;
3473 /* Ok, make the call */
3474 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3481 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3489 } /* end of exchangedata system call */
3491 #ifdef __APPLE_API_OBSOLETE
3493 /************************************************/
3494 /* *** Following calls will be deleted soon *** */
3495 /************************************************/
3498 * Check users access to a file
3501 struct checkuseraccess_args
{
3502 const char *path
; /* pathname of the target file */
3503 uid_t userid
; /* user for whom we are checking access */
3504 gid_t
*groups
; /* Group that we are checking for */
3505 int ngroups
; /* Number of groups being checked */
3506 int accessrequired
; /* needed access to the file */
3507 unsigned long options
; /* options */
3512 checkuseraccess (p
,uap
,retval
)
3514 register struct checkuseraccess_args
*uap
;
3518 register struct vnode
*vp
;
3520 struct nameidata nd
;
3522 int flags
; /*what will actually get passed to access*/
3525 /* Make sure that the number of groups is correct before we do anything */
3527 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3530 /* Verify that the caller is root */
3532 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3535 /* Fill in the credential structure */
3538 cred
.cr_uid
= uap
->userid
;
3539 cred
.cr_ngroups
= uap
->ngroups
;
3540 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3543 /* Get our hands on the file */
3545 nameiflags
= LOCKLEAF
;
3546 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3547 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3549 if (error
= namei(&nd
))
3553 /* Flags == 0 means only check for existence. */
3557 if (uap
->accessrequired
) {
3558 if (uap
->accessrequired
& R_OK
)
3560 if (uap
->accessrequired
& W_OK
)
3562 if (uap
->accessrequired
& X_OK
)
3565 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3574 } /* end of checkuseraccess system call */
3576 /************************************************/
3577 /* *** Preceding calls will be deleted soon *** */
3578 /************************************************/
3580 #endif /* __APPLE_API_OBSOLETE */
3584 struct searchfs_args
{
3586 struct fssearchblock
*searchblock
;
3590 struct searchstate
*state
;
3595 searchfs (p
,uap
,retval
)
3597 register struct searchfs_args
*uap
;
3601 register struct vnode
*vp
;
3604 struct nameidata nd
;
3605 struct fssearchblock searchblock
;
3606 struct searchstate
*state
;
3607 struct attrlist
*returnattrs
;
3608 void *searchparams1
,*searchparams2
;
3616 /* Start by copying in fsearchblock paramater list */
3618 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3621 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3622 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3623 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3626 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3627 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3629 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3631 /* Now set up the various pointers to the correct place in our newly allocated memory */
3633 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3634 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3635 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3637 /* Now copy in the stuff given our local variables. */
3639 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3642 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3645 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3648 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3651 /* set up the uio structure which will contain the users return buffer */
3653 aiov
.iov_base
= searchblock
.returnbuffer
;
3654 aiov
.iov_len
= searchblock
.returnbuffersize
;
3655 auio
.uio_iov
= &aiov
;
3656 auio
.uio_iovcnt
= 1;
3657 auio
.uio_rw
= UIO_READ
;
3658 auio
.uio_segflg
= UIO_USERSPACE
;
3660 auio
.uio_resid
= searchblock
.returnbuffersize
;
3662 nameiflags
= LOCKLEAF
;
3663 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3664 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3666 if (error
= namei(&nd
))
3673 * If searchblock.maxmatches == 0, then skip the search. This has happened
3674 * before and sometimes the underlyning code doesnt deal with it well.
3676 if (searchblock
.maxmatches
== 0) {
3682 Allright, we have everything we need, so lets make that call.
3684 We keep special track of the return value from the file system:
3685 EAGAIN is an acceptable error condition that shouldn't keep us
3686 from copying out any results...
3689 fserror
= VOP_SEARCHFS(vp
,
3692 &searchblock
.searchattrs
,
3693 searchblock
.maxmatches
,
3694 &searchblock
.timelimit
,
3706 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3707 search state. Everything was already put into he return buffer by the vop call. */
3709 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3712 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3719 FREE(searchparams1
,M_TEMP
);
3724 } /* end of searchfs system call */
3728 * Make a filesystem-specific control call:
3731 const char *path
; /* pathname of the target object */
3732 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3733 caddr_t data
; /* pointer to argument buffer */
3734 u_long options
; /* options for fsctl processing */
3738 fsctl (p
,uap
,retval
)
3740 struct fsctl_args
*uap
;
3745 struct nameidata nd
;
3747 u_long cmd
= uap
->cmd
;
3748 register u_int size
;
3749 #define STK_PARAMS 128
3750 char stkbuf
[STK_PARAMS
];
3753 size
= IOCPARM_LEN(cmd
);
3754 if (size
> IOCPARM_MAX
) return (EINVAL
);
3757 if (size
> sizeof (stkbuf
)) {
3758 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3766 error
= copyin(uap
->data
, data
, (u_int
)size
);
3767 if (error
) goto FSCtl_Exit
;
3769 *(caddr_t
*)data
= uap
->data
;
3771 } else if ((cmd
& IOC_OUT
) && size
) {
3773 * Zero the buffer so the user always
3774 * gets back something deterministic.
3777 } else if (cmd
& IOC_VOID
)
3778 *(caddr_t
*)data
= uap
->data
;
3780 /* Get the vnode for the file we are getting info on: */
3781 nameiflags
= LOCKLEAF
;
3782 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3783 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3784 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3786 /* Invoke the filesystem-specific code */
3787 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3792 * Copy any data to user, size was
3793 * already set and checked above.
3795 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3798 if (memp
) kfree(memp
, size
);
3802 /* end of fsctl system call */
3805 * An in-kernel sync for power management to call.
3807 __private_extern__
int
3810 boolean_t funnel_state
;
3813 struct sync_args data
;
3817 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3819 error
= sync(current_proc(), &data
, &retval
);
3821 thread_funnel_set(kernel_flock
, funnel_state
);
3824 } /* end of sync_internal call */