2 * Copyright (c) 1995-2001 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 <machine/cons.h>
79 #include <miscfs/specfs/specdev.h>
81 struct lock__bsd__ exchangelock
;
84 * The currently logged-in user, for ownership of files/directories whose on-disk
85 * permissions are ignored:
89 static int change_dir
__P((struct nameidata
*ndp
, struct proc
*p
));
90 static void checkdirs
__P((struct vnode
*olddp
));
92 /* counts number of mount and unmount operations */
93 unsigned int vfs_nummntops
=0;
96 * Virtual File System System Calls
100 * Mount a file system.
110 mount(p
, uap
, retval
)
112 register struct mount_args
*uap
;
117 struct vfsconf
*vfsp
;
118 int error
, flag
, err2
;
122 char fstypename
[MFSNAMELEN
];
125 * Get vnode to be covered
127 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
129 if (error
= namei(&nd
))
133 if ((vp
->v_flag
& VROOT
) &&
134 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
135 uap
->flags
|= MNT_UPDATE
;
137 if (uap
->flags
& MNT_UPDATE
) {
138 if ((vp
->v_flag
& VROOT
) == 0) {
145 * We only allow the filesystem to be reloaded if it
146 * is currently mounted read-only.
148 if ((uap
->flags
& MNT_RELOAD
) &&
149 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
151 return (EOPNOTSUPP
); /* Needs translation */
154 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
156 * Only root, or the user that did the original mount is
157 * permitted to update it.
159 if (mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
&&
160 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
165 * Do not allow NFS export by non-root users. FOr non-root
166 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
167 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
169 if (p
->p_ucred
->cr_uid
!= 0) {
170 if (uap
->flags
& MNT_EXPORTED
) {
174 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
175 if (flag
& MNT_NOEXEC
)
176 uap
->flags
|= MNT_NOEXEC
;
178 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
182 VOP_UNLOCK(vp
, 0, p
);
186 * If the user is not root, ensure that they own the directory
187 * onto which we are attempting to mount.
189 if ((error
= VOP_GETATTR(vp
, &va
, p
->p_ucred
, p
)) ||
190 (va
.va_uid
!= p
->p_ucred
->cr_uid
&&
191 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))) {
196 * Do not allow NFS export by non-root users. FOr non-root
197 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
198 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
200 if (p
->p_ucred
->cr_uid
!= 0) {
201 if (uap
->flags
& MNT_EXPORTED
) {
205 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
206 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
207 uap
->flags
|= MNT_NOEXEC
;
209 if (error
= vinvalbuf(vp
, V_SAVE
, p
->p_ucred
, p
, 0, 0)) {
213 if (vp
->v_type
!= VDIR
) {
219 * Historically filesystem types were identified by number. If we
220 * get an integer for the filesystem type instead of a string, we
221 * check to see if it matches one of the historic filesystem types.
223 fstypenum
= (u_long
)uap
->type
;
224 if (fstypenum
< maxvfsconf
) {
225 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
226 if (vfsp
->vfc_typenum
== fstypenum
)
232 strncpy(fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
234 #endif /* COMPAT_43 */
235 if (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) {
239 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
240 if (!strcmp(vfsp
->vfc_name
, fstypename
))
246 simple_lock(&vp
->v_interlock
);
247 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
248 simple_unlock(&vp
->v_interlock
);
252 SET(vp
->v_flag
, VMOUNT
);
253 simple_unlock(&vp
->v_interlock
);
256 * Allocate and initialize the filesystem.
258 mp
= (struct mount
*)_MALLOC_ZONE((u_long
)sizeof(struct mount
),
260 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
262 /* Initialize the default IO constraints */
263 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
264 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
266 lockinit(&mp
->mnt_lock
, PVFS
, "vfslock", 0, 0);
267 (void)vfs_busy(mp
, LK_NOWAIT
, 0, p
);
268 mp
->mnt_op
= vfsp
->vfc_vfsops
;
270 vfsp
->vfc_refcount
++;
271 mp
->mnt_stat
.f_type
= vfsp
->vfc_typenum
;
272 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
273 strncpy(mp
->mnt_stat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
274 mp
->mnt_vnodecovered
= vp
;
275 mp
->mnt_stat
.f_owner
= p
->p_ucred
->cr_uid
;
276 VOP_UNLOCK(vp
, 0, p
);
280 * Set the mount level flags.
282 if (uap
->flags
& MNT_RDONLY
)
283 mp
->mnt_flag
|= MNT_RDONLY
;
284 else if (mp
->mnt_flag
& MNT_RDONLY
)
285 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
286 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
287 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
288 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
289 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
290 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
291 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
293 * Mount the filesystem.
295 error
= VFS_MOUNT(mp
, uap
->path
, uap
->data
, &nd
, p
);
296 if (mp
->mnt_flag
& MNT_UPDATE
) {
298 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
299 mp
->mnt_flag
&= ~MNT_RDONLY
;
301 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
302 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
309 /* get the vnode lock */
310 err2
= vn_lock(vp
, LK_EXCLUSIVE
|LK_RETRY
, p
);
313 * Put the new filesystem on the mount list after root.
316 if (!error
&& !err2
) {
317 simple_lock(&vp
->v_interlock
);
318 CLR(vp
->v_flag
, VMOUNT
);
319 vp
->v_mountedhere
=mp
;
320 simple_unlock(&vp
->v_interlock
);
321 simple_lock(&mountlist_slock
);
322 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
323 simple_unlock(&mountlist_slock
);
325 VOP_UNLOCK(vp
, 0, p
);
327 if (error
= VFS_START(mp
, 0, p
))
330 /* increment the operations count */
334 simple_lock(&vp
->v_interlock
);
335 CLR(vp
->v_flag
, VMOUNT
);
336 simple_unlock(&vp
->v_interlock
);
337 mp
->mnt_vfc
->vfc_refcount
--;
339 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
349 * Scan all active processes to see if any of them have a current
350 * or root directory onto which the new filesystem has just been
351 * mounted. If so, replace them with the new mount point.
357 struct filedesc
*fdp
;
361 if (olddp
->v_usecount
== 1)
363 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
364 panic("mount: lost mount");
365 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
367 if (fdp
->fd_cdir
== olddp
) {
370 fdp
->fd_cdir
= newdp
;
372 if (fdp
->fd_rdir
== olddp
) {
375 fdp
->fd_rdir
= newdp
;
378 if (rootvnode
== olddp
) {
387 * Unmount a file system.
389 * Note: unmount takes a path to the vnode mounted on as argument,
390 * not special file (as before).
392 struct unmount_args
{
398 unmount(p
, uap
, retval
)
400 register struct unmount_args
*uap
;
403 register struct vnode
*vp
;
408 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
410 if (error
= namei(&nd
))
416 * Only root, or the user that did the original mount is
417 * permitted to unmount this filesystem.
419 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
420 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
426 * Don't allow unmounting the root file system.
428 if (mp
->mnt_flag
& MNT_ROOTFS
) {
430 return (EBUSY
); /* the root is always busy */
434 * Must be the root of the filesystem
436 if ((vp
->v_flag
& VROOT
) == 0) {
441 return (dounmount(mp
, uap
->flags
, p
));
445 * Do the actual file system unmount.
448 dounmount(mp
, flags
, p
)
449 register struct mount
*mp
;
453 struct vnode
*coveredvp
;
456 simple_lock(&mountlist_slock
);
457 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
458 lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
, &mountlist_slock
, p
);
459 mp
->mnt_flag
&=~ MNT_ASYNC
;
460 ubc_umount(mp
); /* release cached vnodes */
461 cache_purgevfs(mp
); /* remove cache entries for this file sys */
462 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
463 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
465 error
= VFS_UNMOUNT(mp
, flags
, p
);
466 simple_lock(&mountlist_slock
);
468 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
469 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
470 &mountlist_slock
, p
);
474 /* increment the operations count */
477 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
478 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
479 coveredvp
->v_mountedhere
= (struct mount
*)0;
480 simple_unlock(&mountlist_slock
);
482 simple_lock(&mountlist_slock
);
484 mp
->mnt_vfc
->vfc_refcount
--;
485 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
486 panic("unmount: dangling vnode");
488 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
490 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
493 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
498 * Sync each mounted filesystem.
502 struct ctldebug debug0
= { "syncprt", &syncprt
};
508 int print_vmpage_stat
=0;
514 struct sync_args
*uap
;
517 register struct mount
*mp
, *nmp
;
520 simple_lock(&mountlist_slock
);
521 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
522 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
523 nmp
= mp
->mnt_list
.cqe_next
;
526 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
527 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
528 mp
->mnt_flag
&= ~MNT_ASYNC
;
529 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
531 mp
->mnt_flag
|= MNT_ASYNC
;
533 simple_lock(&mountlist_slock
);
534 nmp
= mp
->mnt_list
.cqe_next
;
537 simple_unlock(&mountlist_slock
);
540 extern void vm_countdirtypages(void);
541 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
542 extern unsigned int dp_pgins
, dp_pgouts
;
543 if(print_vmpage_stat
) {
544 vm_countdirtypages();
545 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
546 dp_pgins
, dp_pgouts
);
552 #endif /* DIAGNOSTIC */
557 * Change filesystem quotas.
559 struct quotactl_args
{
567 quotactl(p
, uap
, retval
)
569 register struct quotactl_args
*uap
;
572 register struct mount
*mp
;
576 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
577 if (error
= namei(&nd
))
579 mp
= nd
.ni_vp
->v_mount
;
581 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
586 * Get filesystem statistics.
594 statfs(p
, uap
, retval
)
596 register struct statfs_args
*uap
;
599 register struct mount
*mp
;
600 register struct statfs
*sp
;
604 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
605 if (error
= namei(&nd
))
607 mp
= nd
.ni_vp
->v_mount
;
610 if (error
= VFS_STATFS(mp
, sp
, p
))
612 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
613 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
614 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
618 * Get filesystem statistics.
620 struct fstatfs_args
{
626 fstatfs(p
, uap
, retval
)
628 register struct fstatfs_args
*uap
;
633 register struct statfs
*sp
;
636 if (error
= getvnode(p
, uap
->fd
, &fp
))
638 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
642 if (error
= VFS_STATFS(mp
, sp
, p
))
644 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
645 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
646 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
650 * Get statistics on all filesystems.
652 struct getfsstat_args
{
658 getfsstat(p
, uap
, retval
)
660 register struct getfsstat_args
*uap
;
663 register struct mount
*mp
, *nmp
;
664 register struct statfs
*sp
;
666 long count
, maxcount
, error
;
668 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
669 sfsp
= (caddr_t
)uap
->buf
;
671 simple_lock(&mountlist_slock
);
672 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
673 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
674 nmp
= mp
->mnt_list
.cqe_next
;
677 if (sfsp
&& count
< maxcount
) {
680 * If MNT_NOWAIT is specified, do not refresh the
681 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
683 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
684 (uap
->flags
& MNT_WAIT
)) &&
685 (error
= VFS_STATFS(mp
, sp
, p
))) {
686 simple_lock(&mountlist_slock
);
687 nmp
= mp
->mnt_list
.cqe_next
;
691 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
692 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
697 simple_lock(&mountlist_slock
);
698 nmp
= mp
->mnt_list
.cqe_next
;
701 simple_unlock(&mountlist_slock
);
702 if (sfsp
&& count
> maxcount
)
710 ogetfsstat(p
, uap
, retval
)
712 register struct getfsstat_args
*uap
;
715 register struct mount
*mp
, *nmp
;
716 register struct statfs
*sp
;
718 long count
, maxcount
, error
;
720 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
721 sfsp
= (caddr_t
)uap
->buf
;
723 simple_lock(&mountlist_slock
);
724 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
725 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
726 nmp
= mp
->mnt_list
.cqe_next
;
729 if (sfsp
&& count
< maxcount
) {
732 * If MNT_NOWAIT is specified, do not refresh the
733 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
735 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
736 (uap
->flags
& MNT_WAIT
)) &&
737 (error
= VFS_STATFS(mp
, sp
, p
))) {
738 simple_lock(&mountlist_slock
);
739 nmp
= mp
->mnt_list
.cqe_next
;
743 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
744 error
= copyout((caddr_t
)sp
, sfsp
,
745 sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
));
748 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
751 simple_lock(&mountlist_slock
);
752 nmp
= mp
->mnt_list
.cqe_next
;
755 simple_unlock(&mountlist_slock
);
756 if (sfsp
&& count
> maxcount
)
765 * Change current working directory to a given file descriptor.
772 fchdir(p
, uap
, retval
)
774 struct fchdir_args
*uap
;
777 register struct filedesc
*fdp
= p
->p_fd
;
778 struct vnode
*vp
, *tdp
;
783 if (error
= getvnode(p
, uap
->fd
, &fp
))
785 vp
= (struct vnode
*)fp
->f_data
;
787 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
788 if (vp
->v_type
!= VDIR
)
791 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
792 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
793 if (vfs_busy(mp
, 0, 0, p
))
795 error
= VFS_ROOT(mp
, &tdp
);
806 VOP_UNLOCK(vp
, 0, p
);
813 * Change current working directory (``.'').
820 chdir(p
, uap
, retval
)
822 struct chdir_args
*uap
;
825 register struct filedesc
*fdp
= p
->p_fd
;
829 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
831 if (error
= change_dir(&nd
, p
))
834 fdp
->fd_cdir
= nd
.ni_vp
;
839 * Change notion of root (``/'') directory.
846 chroot(p
, uap
, retval
)
848 struct chroot_args
*uap
;
851 register struct filedesc
*fdp
= p
->p_fd
;
855 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
858 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
860 if (error
= change_dir(&nd
, p
))
863 if(error
= clone_system_shared_regions()) {
868 if (fdp
->fd_rdir
!= NULL
)
870 fdp
->fd_rdir
= nd
.ni_vp
;
875 * Common routine for chroot and chdir.
879 register struct nameidata
*ndp
;
885 if (error
= namei(ndp
))
888 if (vp
->v_type
!= VDIR
)
891 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
895 VOP_UNLOCK(vp
, 0, p
);
900 * Check permissions, allocate an open file structure,
901 * and call the device open routine if any.
911 register struct open_args
*uap
;
914 register struct filedesc
*fdp
= p
->p_fd
;
915 register struct file
*fp
;
916 register struct vnode
*vp
;
917 int flags
, cmode
, oflags
;
919 int type
, indx
, error
;
922 extern struct fileops vnops
;
925 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
927 flags
= FFLAGS(uap
->flags
);
928 if (error
= falloc(p
, &nfp
, &indx
))
931 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
932 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
933 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
934 if (error
= vn_open(&nd
, flags
, cmode
)) {
936 if ((error
== ENODEV
|| error
== ENXIO
) &&
937 p
->p_dupfd
>= 0 && /* XXX from fdopen */
939 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
943 if (error
== ERESTART
)
950 fp
->f_flag
= flags
& FMASK
;
951 fp
->f_type
= DTYPE_VNODE
;
953 fp
->f_data
= (caddr_t
)vp
;
954 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
955 lf
.l_whence
= SEEK_SET
;
958 if (flags
& O_EXLOCK
)
963 if ((flags
& FNONBLOCK
) == 0)
965 VOP_UNLOCK(vp
, 0, p
);
966 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
967 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
972 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
973 fp
->f_flag
|= FHASLOCK
;
975 VOP_UNLOCK(vp
, 0, p
);
976 *fdflags(p
, indx
) &= ~UF_RESERVED
;
990 ocreat(p
, uap
, retval
)
992 register struct ocreat_args
*uap
;
995 struct open_args nuap
;
997 nuap
.path
= uap
->path
;
998 nuap
.mode
= uap
->mode
;
999 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1000 return (open(p
, &nuap
, retval
));
1002 #endif /* COMPAT_43 */
1005 * Create a special file.
1014 mknod(p
, uap
, retval
)
1016 register struct mknod_args
*uap
;
1019 register struct vnode
*vp
;
1023 struct nameidata nd
;
1025 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1027 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1028 if (error
= namei(&nd
))
1035 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1036 vattr
.va_rdev
= uap
->dev
;
1039 switch (uap
->mode
& S_IFMT
) {
1040 case S_IFMT
: /* used by badsect to flag bad sectors */
1041 vattr
.va_type
= VBAD
;
1044 vattr
.va_type
= VCHR
;
1047 vattr
.va_type
= VBLK
;
1058 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1060 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1062 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1065 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1066 &nd
.ni_cnd
, &vattr
);
1069 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1070 if (nd
.ni_dvp
== vp
)
1081 * Create a named pipe.
1083 struct mkfifo_args
{
1089 mkfifo(p
, uap
, retval
)
1091 register struct mkfifo_args
*uap
;
1096 struct nameidata nd
;
1099 return (EOPNOTSUPP
);
1101 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1102 if (error
= namei(&nd
))
1104 if (nd
.ni_vp
!= NULL
) {
1105 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1106 if (nd
.ni_dvp
== nd
.ni_vp
)
1114 vattr
.va_type
= VFIFO
;
1115 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1116 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1117 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1122 * Make a hard file link.
1130 link(p
, uap
, retval
)
1132 register struct link_args
*uap
;
1135 register struct vnode
*vp
;
1136 struct nameidata nd
;
1139 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1140 if (error
= namei(&nd
))
1143 if (vp
->v_type
== VDIR
)
1144 error
= EPERM
; /* POSIX */
1146 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1147 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1148 nd
.ni_dirp
= uap
->link
;
1149 if ((error
= namei(&nd
)) == 0) {
1150 if (nd
.ni_vp
!= NULL
)
1153 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1155 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1156 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1158 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1159 if (nd
.ni_dvp
== nd
.ni_vp
)
1173 * Make a symbolic link.
1175 struct symlink_args
{
1181 symlink(p
, uap
, retval
)
1183 register struct symlink_args
*uap
;
1189 struct nameidata nd
;
1191 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1192 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1194 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1195 if (error
= namei(&nd
))
1198 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1199 if (nd
.ni_dvp
== nd
.ni_vp
)
1208 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1209 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1210 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1212 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1217 * Delete a whiteout from the filesystem.
1219 struct undelete_args
{
1224 undelete(p
, uap
, retval
)
1226 register struct undelete_args
*uap
;
1230 struct nameidata nd
;
1232 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1238 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1239 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1240 if (nd
.ni_dvp
== nd
.ni_vp
)
1249 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1250 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1251 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1257 * Delete a name from the filesystem.
1259 struct unlink_args
{
1264 _unlink(p
, uap
, retval
, nodelbusy
)
1266 struct unlink_args
*uap
;
1270 register struct vnode
*vp
;
1272 struct nameidata nd
;
1274 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1275 /* with Carbon semantics, busy files cannot be deleted */
1277 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1278 if (error
= namei(&nd
))
1281 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1282 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1284 if (vp
->v_type
== VDIR
)
1285 error
= EPERM
; /* POSIX */
1288 * The root of a mounted filesystem cannot be deleted.
1290 * XXX: can this only be a VDIR case?
1292 if (vp
->v_flag
& VROOT
)
1297 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1298 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1300 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1301 if (nd
.ni_dvp
== vp
)
1312 * Delete a name from the filesystem using POSIX semantics.
1315 unlink(p
, uap
, retval
)
1317 struct unlink_args
*uap
;
1320 return _unlink(p
, uap
, retval
, 0);
1324 * Delete a name from the filesystem using Carbon semantics.
1327 delete(p
, uap
, retval
)
1329 struct unlink_args
*uap
;
1332 return _unlink(p
, uap
, retval
, 1);
1336 * Reposition read/write file offset.
1340 #ifdef DOUBLE_ALIGN_PARAMS
1347 lseek(p
, uap
, retval
)
1349 register struct lseek_args
*uap
;
1352 struct ucred
*cred
= p
->p_ucred
;
1357 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1359 if (fp
->f_type
!= DTYPE_VNODE
)
1361 switch (uap
->whence
) {
1363 fp
->f_offset
+= uap
->offset
;
1367 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1369 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1372 fp
->f_offset
= uap
->offset
;
1377 *(off_t
*)retval
= fp
->f_offset
;
1383 * Reposition read/write file offset.
1385 struct olseek_args
{
1391 olseek(p
, uap
, retval
)
1393 register struct olseek_args
*uap
;
1396 struct lseek_args
/* {
1398 #ifdef DOUBLE_ALIGN_PARAMS
1399 syscallarg(int) pad;
1401 syscallarg(off_t) offset;
1402 syscallarg(int) whence;
1408 nuap
.offset
= uap
->offset
;
1409 nuap
.whence
= uap
->whence
;
1410 error
= lseek(p
, &nuap
, &qret
);
1411 *(long *)retval
= qret
;
1414 #endif /* COMPAT_43 */
1417 * Check access permissions.
1419 struct access_args
{
1424 access(p
, uap
, retval
)
1426 register struct access_args
*uap
;
1429 register struct ucred
*cred
= p
->p_ucred
;
1430 register struct vnode
*vp
;
1431 int error
, flags
, t_gid
, t_uid
;
1432 struct nameidata nd
;
1434 t_uid
= cred
->cr_uid
;
1435 t_gid
= cred
->cr_groups
[0];
1436 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1437 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1438 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1440 if (error
= namei(&nd
))
1444 /* Flags == 0 means only check for existence. */
1447 if (uap
->flags
& R_OK
)
1449 if (uap
->flags
& W_OK
)
1451 if (uap
->flags
& X_OK
)
1453 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1454 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1458 cred
->cr_uid
= t_uid
;
1459 cred
->cr_groups
[0] = t_gid
;
1465 * Get file status; this version follows links.
1473 ostat(p
, uap
, retval
)
1475 register struct ostat_args
*uap
;
1481 struct nameidata nd
;
1483 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1485 if (error
= namei(&nd
))
1487 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1492 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1497 * Get file status; this version does not follow links.
1499 struct olstat_args
{
1505 olstat(p
, uap
, retval
)
1507 register struct olstat_args
*uap
;
1510 struct vnode
*vp
, *dvp
;
1511 struct stat sb
, sb1
;
1514 struct nameidata nd
;
1516 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1518 if (error
= namei(&nd
))
1521 * For symbolic links, always return the attributes of its
1522 * containing directory, except for mode, size, and links.
1526 if (vp
->v_type
!= VLNK
) {
1531 error
= vn_stat(vp
, &sb
, p
);
1536 error
= vn_stat(dvp
, &sb
, p
);
1542 error
= vn_stat(vp
, &sb1
, p
);
1546 sb
.st_mode
&= ~S_IFDIR
;
1547 sb
.st_mode
|= S_IFLNK
;
1548 sb
.st_nlink
= sb1
.st_nlink
;
1549 sb
.st_size
= sb1
.st_size
;
1550 sb
.st_blocks
= sb1
.st_blocks
;
1553 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1558 * Convert from an old to a new stat structure.
1566 ost
->st_dev
= st
->st_dev
;
1567 ost
->st_ino
= st
->st_ino
;
1568 ost
->st_mode
= st
->st_mode
;
1569 ost
->st_nlink
= st
->st_nlink
;
1570 ost
->st_uid
= st
->st_uid
;
1571 ost
->st_gid
= st
->st_gid
;
1572 ost
->st_rdev
= st
->st_rdev
;
1573 if (st
->st_size
< (quad_t
)1 << 32)
1574 ost
->st_size
= st
->st_size
;
1577 ost
->st_atime
= st
->st_atime
;
1578 ost
->st_mtime
= st
->st_mtime
;
1579 ost
->st_ctime
= st
->st_ctime
;
1580 ost
->st_blksize
= st
->st_blksize
;
1581 ost
->st_blocks
= st
->st_blocks
;
1582 ost
->st_flags
= st
->st_flags
;
1583 ost
->st_gen
= st
->st_gen
;
1585 #endif /* COMPAT_43 */
1588 * Get file status; this version follows links.
1596 stat(p
, uap
, retval
)
1598 register struct stat_args
*uap
;
1603 struct nameidata nd
;
1605 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1607 if (error
= namei(&nd
))
1609 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1613 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1618 * Get file status; this version does not follow links.
1626 lstat(p
, uap
, retval
)
1628 register struct lstat_args
*uap
;
1632 struct vnode
*vp
, *dvp
;
1633 struct stat sb
, sb1
;
1634 struct nameidata nd
;
1636 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1638 if (error
= namei(&nd
))
1641 * For symbolic links, always return the attributes of its containing
1642 * directory, except for mode, size, inode number, and links.
1646 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1651 error
= vn_stat(vp
, &sb
, p
);
1655 if (vp
->v_type
== VLNK
)
1656 sb
.st_mode
|= S_IFLNK
;
1658 error
= vn_stat(dvp
, &sb
, p
);
1664 error
= vn_stat(vp
, &sb1
, p
);
1668 sb
.st_mode
&= ~S_IFDIR
;
1669 sb
.st_mode
|= S_IFLNK
;
1670 sb
.st_nlink
= sb1
.st_nlink
;
1671 sb
.st_size
= sb1
.st_size
;
1672 sb
.st_blocks
= sb1
.st_blocks
;
1673 sb
.st_ino
= sb1
.st_ino
;
1675 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1680 * Get configurable pathname variables.
1682 struct pathconf_args
{
1688 pathconf(p
, uap
, retval
)
1690 register struct pathconf_args
*uap
;
1694 struct nameidata nd
;
1696 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1698 if (error
= namei(&nd
))
1700 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1706 * Return target name of a symbolic link.
1708 struct readlink_args
{
1715 readlink(p
, uap
, retval
)
1717 register struct readlink_args
*uap
;
1720 register struct vnode
*vp
;
1724 struct nameidata nd
;
1726 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1728 if (error
= namei(&nd
))
1731 if (vp
->v_type
!= VLNK
)
1734 aiov
.iov_base
= uap
->buf
;
1735 aiov
.iov_len
= uap
->count
;
1736 auio
.uio_iov
= &aiov
;
1737 auio
.uio_iovcnt
= 1;
1738 auio
.uio_offset
= 0;
1739 auio
.uio_rw
= UIO_READ
;
1740 auio
.uio_segflg
= UIO_USERSPACE
;
1742 auio
.uio_resid
= uap
->count
;
1743 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1746 *retval
= uap
->count
- auio
.uio_resid
;
1751 * Change flags of a file given a path name.
1753 struct chflags_args
{
1759 chflags(p
, uap
, retval
)
1761 register struct chflags_args
*uap
;
1764 register struct vnode
*vp
;
1767 struct nameidata nd
;
1769 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1770 if (error
= namei(&nd
))
1773 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1774 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1776 vattr
.va_flags
= uap
->flags
;
1777 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1783 * Change flags of a file given a file descriptor.
1785 struct fchflags_args
{
1791 fchflags(p
, uap
, retval
)
1793 register struct fchflags_args
*uap
;
1801 if (error
= getvnode(p
, uap
->fd
, &fp
))
1803 vp
= (struct vnode
*)fp
->f_data
;
1804 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1805 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1807 vattr
.va_flags
= uap
->flags
;
1808 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1809 VOP_UNLOCK(vp
, 0, p
);
1814 * Change mode of a file given path name.
1822 chmod(p
, uap
, retval
)
1824 register struct chmod_args
*uap
;
1827 register struct vnode
*vp
;
1830 struct nameidata nd
;
1832 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1833 if (error
= namei(&nd
))
1836 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1837 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1839 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1840 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1846 * Change mode of a file given a file descriptor.
1848 struct fchmod_args
{
1854 fchmod(p
, uap
, retval
)
1856 register struct fchmod_args
*uap
;
1864 if (error
= getvnode(p
, uap
->fd
, &fp
))
1866 vp
= (struct vnode
*)fp
->f_data
;
1867 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1868 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1870 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1871 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1872 VOP_UNLOCK(vp
, 0, p
);
1877 * Set ownership given a path name.
1886 chown(p
, uap
, retval
)
1888 register struct chown_args
*uap
;
1891 register struct vnode
*vp
;
1894 struct nameidata nd
;
1896 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1897 if (error
= namei(&nd
))
1902 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
1903 * by looking for chown() calls on /dev/console from a console process.
1905 if ((vp
) && (vp
->v_specinfo
) &&
1906 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
1907 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
1908 console_user
= uap
->uid
;
1911 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1912 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1914 vattr
.va_uid
= uap
->uid
;
1915 vattr
.va_gid
= uap
->gid
;
1916 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1922 * Set ownership given a file descriptor.
1924 struct fchown_args
{
1931 fchown(p
, uap
, retval
)
1933 register struct fchown_args
*uap
;
1941 if (error
= getvnode(p
, uap
->fd
, &fp
))
1943 vp
= (struct vnode
*)fp
->f_data
;
1944 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1945 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1947 vattr
.va_uid
= uap
->uid
;
1948 vattr
.va_gid
= uap
->gid
;
1949 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1950 VOP_UNLOCK(vp
, 0, p
);
1955 * Set the access and modification times of a file.
1957 struct utimes_args
{
1959 struct timeval
*tptr
;
1963 utimes(p
, uap
, retval
)
1965 register struct utimes_args
*uap
;
1968 register struct vnode
*vp
;
1969 struct timeval tv
[2];
1972 struct nameidata nd
;
1975 if (uap
->tptr
== NULL
) {
1978 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
1979 } else if (error
= copyin((caddr_t
)uap
->tptr
, (caddr_t
)tv
,
1982 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1983 if (error
= namei(&nd
))
1986 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1987 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1988 vattr
.va_atime
.tv_sec
= tv
[0].tv_sec
;
1989 vattr
.va_atime
.tv_nsec
= tv
[0].tv_usec
* 1000;
1990 vattr
.va_mtime
.tv_sec
= tv
[1].tv_sec
;
1991 vattr
.va_mtime
.tv_nsec
= tv
[1].tv_usec
* 1000;
1992 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1998 * Truncate a file given its path name.
2000 struct truncate_args
{
2002 #ifdef DOUBLE_ALIGN_PARAMS
2009 truncate(p
, uap
, retval
)
2011 register struct truncate_args
*uap
;
2014 register struct vnode
*vp
;
2017 struct nameidata nd
;
2019 if (uap
->length
< 0)
2021 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2022 if (error
= namei(&nd
))
2025 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2026 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2027 if (vp
->v_type
== VDIR
)
2029 else if ((error
= vn_writechk(vp
)) == 0 &&
2030 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2032 vattr
.va_size
= uap
->length
;
2033 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2040 * Truncate a file given a file descriptor.
2042 struct ftruncate_args
{
2044 #ifdef DOUBLE_ALIGN_PARAMS
2051 ftruncate(p
, uap
, retval
)
2053 register struct ftruncate_args
*uap
;
2061 if (uap
->length
< 0)
2064 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2067 if (fp
->f_type
== DTYPE_PSXSHM
) {
2068 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2070 if (fp
->f_type
!= DTYPE_VNODE
)
2073 if ((fp
->f_flag
& FWRITE
) == 0)
2075 vp
= (struct vnode
*)fp
->f_data
;
2076 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2077 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2078 if (vp
->v_type
== VDIR
)
2080 else if ((error
= vn_writechk(vp
)) == 0) {
2082 vattr
.va_size
= uap
->length
;
2083 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2085 VOP_UNLOCK(vp
, 0, p
);
2091 * Truncate a file given its path name.
2093 struct otruncate_args
{
2099 otruncate(p
, uap
, retval
)
2101 register struct otruncate_args
*uap
;
2104 struct truncate_args
/* {
2105 syscallarg(char *) path;
2106 #ifdef DOUBLE_ALIGN_PARAMS
2107 syscallarg(int) pad;
2109 syscallarg(off_t) length;
2112 nuap
.path
= uap
->path
;
2113 nuap
.length
= uap
->length
;
2114 return (truncate(p
, &nuap
, retval
));
2118 * Truncate a file given a file descriptor.
2120 struct oftruncate_args
{
2126 oftruncate(p
, uap
, retval
)
2128 register struct oftruncate_args
*uap
;
2131 struct ftruncate_args
/* {
2133 #ifdef DOUBLE_ALIGN_PARAMS
2134 syscallarg(int) pad;
2136 syscallarg(off_t) length;
2140 nuap
.length
= uap
->length
;
2141 return (ftruncate(p
, &nuap
, retval
));
2143 #endif /* COMPAT_43 */
2146 * Sync an open file.
2153 fsync(p
, uap
, retval
)
2155 struct fsync_args
*uap
;
2158 register struct vnode
*vp
;
2162 if (error
= getvnode(p
, uap
->fd
, &fp
))
2164 vp
= (struct vnode
*)fp
->f_data
;
2165 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2166 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2167 VOP_UNLOCK(vp
, 0, p
);
2172 * Duplicate files. Source must be a file, target must be a file or
2176 struct copyfile_args
{
2184 copyfile(p
, uap
, retval
)
2186 register struct copyfile_args
*uap
;
2189 register struct vnode
*tvp
, *fvp
, *tdvp
;
2190 register struct ucred
*cred
= p
->p_ucred
;
2191 struct nameidata fromnd
, tond
;
2194 /* Check that the flags are valid.
2197 if (uap
->flags
& ~CPF_MASK
) {
2201 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2203 if (error
= namei(&fromnd
))
2207 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2208 UIO_USERSPACE
, uap
->to
, p
);
2209 if (error
= namei(&tond
)) {
2216 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2222 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2227 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2233 * If source is the same as the destination (that is the
2234 * same inode number) then there is nothing to do.
2235 * (fixed to have POSIX semantics - CSM 3/2/98)
2241 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2243 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2252 vrele(tond
.ni_startdir
);
2253 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2255 if (fromnd
.ni_startdir
)
2256 vrele(fromnd
.ni_startdir
);
2257 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2264 * Rename files. Source and destination must either both be directories,
2265 * or both not be directories. If target is a directory, it must be empty.
2267 struct rename_args
{
2273 rename(p
, uap
, retval
)
2275 register struct rename_args
*uap
;
2278 register struct vnode
*tvp
, *fvp
, *tdvp
;
2279 struct nameidata fromnd
, tond
;
2282 int casesense
,casepres
;
2286 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2288 if (error
= namei(&fromnd
))
2292 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2293 UIO_USERSPACE
, uap
->to
, p
);
2294 if (error
= namei(&tond
)) {
2295 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2296 vrele(fromnd
.ni_dvp
);
2304 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2307 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2315 * If source is the same as the destination (that is the
2316 * same inode number) then there is nothing to do...
2318 * underlyning file system supports case insensitivity and is case preserving. Then
2319 * a special case is made, i.e. foo -> Foo.
2321 * Only file systems that support the pathconf selectors _PC_CASE_SENSITIVE and
2322 * _PC_CASE_PRESERVING can have this exception, and then they would need to
2323 * handle the special case of getting the same vnode as target and source.
2324 * NOTE: Then the target is unlocked going into VOP_RENAME, so not to cause
2325 * locking problems. There is a single reference on tvp.
2330 * Check to see if just changing case, if:
2331 * - file system is case insensitive
2332 * - and also case preserving
2333 * _ same parent directories (so changing case by different links is not supported)
2334 * For instance: mv a/foo a/Foo
2336 if ((tond
.ni_dvp
== fromnd
.ni_dvp
) &&
2337 (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
) == 0) &&
2338 (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
) == 0) &&
2341 /* Since the target is locked...unlock it and lose a ref */
2348 * Allow the renaming of mount points.
2349 * - target must not exist
2350 * - target must reside in the same directory as source
2351 * - union mounts cannot be renamed
2352 * - "/" cannot be renamed
2354 if ((fvp
->v_flag
& VROOT
) &&
2355 (fvp
->v_type
== VDIR
) &&
2357 (fvp
->v_mountedhere
== NULL
) &&
2358 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2359 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2360 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2362 /* switch fvp to the covered vnode */
2363 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2371 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2372 if (fromnd
.ni_dvp
!= tdvp
)
2373 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2375 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2376 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2377 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2382 * update filesystem's mount point data
2385 char *cp
, *pathend
, *mpname
;
2392 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2393 mp
= fvp
->v_mountedhere
;
2395 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2400 VOP_UNLOCK(fvp
, 0, p
);
2402 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2403 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2405 /* find current mount point prefix */
2406 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2407 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2411 /* find last component of target name */
2412 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2416 /* append name to prefix */
2417 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2418 bzero(pathend
, maxlen
);
2419 strncpy(pathend
, mpname
, maxlen
- 1);
2421 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2427 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2434 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2435 vrele(fromnd
.ni_dvp
);
2439 vrele(tond
.ni_startdir
);
2440 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2442 if (fromnd
.ni_startdir
)
2443 vrele(fromnd
.ni_startdir
);
2444 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2451 * Make a directory file.
2459 mkdir(p
, uap
, retval
)
2461 register struct mkdir_args
*uap
;
2464 register struct vnode
*vp
;
2467 struct nameidata nd
;
2469 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2470 if (error
= namei(&nd
))
2474 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2475 if (nd
.ni_dvp
== vp
)
2483 vattr
.va_type
= VDIR
;
2484 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2485 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2486 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2493 * Remove a directory file.
2500 rmdir(p
, uap
, retval
)
2502 struct rmdir_args
*uap
;
2505 register struct vnode
*vp
;
2507 struct nameidata nd
;
2509 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2511 if (error
= namei(&nd
))
2514 if (vp
->v_type
!= VDIR
) {
2519 * No rmdir "." please.
2521 if (nd
.ni_dvp
== vp
) {
2526 * The root of a mounted filesystem cannot be deleted.
2528 if (vp
->v_flag
& VROOT
)
2532 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2533 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2534 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2536 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2537 if (nd
.ni_dvp
== vp
)
2548 * Read a block of directory entries in a file system independent format.
2550 struct ogetdirentries_args
{
2557 ogetdirentries(p
, uap
, retval
)
2559 register struct ogetdirentries_args
*uap
;
2562 register struct vnode
*vp
;
2564 struct uio auio
, kuio
;
2565 struct iovec aiov
, kiov
;
2566 struct dirent
*dp
, *edp
;
2568 int error
, eofflag
, readcnt
;
2571 if (error
= getvnode(p
, uap
->fd
, &fp
))
2573 if ((fp
->f_flag
& FREAD
) == 0)
2575 vp
= (struct vnode
*)fp
->f_data
;
2577 if (vp
->v_type
!= VDIR
)
2579 aiov
.iov_base
= uap
->buf
;
2580 aiov
.iov_len
= uap
->count
;
2581 auio
.uio_iov
= &aiov
;
2582 auio
.uio_iovcnt
= 1;
2583 auio
.uio_rw
= UIO_READ
;
2584 auio
.uio_segflg
= UIO_USERSPACE
;
2586 auio
.uio_resid
= uap
->count
;
2587 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2588 loff
= auio
.uio_offset
= fp
->f_offset
;
2589 # if (BYTE_ORDER != LITTLE_ENDIAN)
2590 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2591 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2592 (int *)0, (u_long
*)0);
2593 fp
->f_offset
= auio
.uio_offset
;
2598 kuio
.uio_iov
= &kiov
;
2599 kuio
.uio_segflg
= UIO_SYSSPACE
;
2600 kiov
.iov_len
= uap
->count
;
2601 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2602 kiov
.iov_base
= dirbuf
;
2603 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2604 (int *)0, (u_long
*)0);
2605 fp
->f_offset
= kuio
.uio_offset
;
2607 readcnt
= uap
->count
- kuio
.uio_resid
;
2608 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2609 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2610 # if (BYTE_ORDER == LITTLE_ENDIAN)
2612 * The expected low byte of
2613 * dp->d_namlen is our dp->d_type.
2614 * The high MBZ byte of dp->d_namlen
2615 * is our dp->d_namlen.
2617 dp
->d_type
= dp
->d_namlen
;
2621 * The dp->d_type is the high byte
2622 * of the expected dp->d_namlen,
2623 * so must be zero'ed.
2627 if (dp
->d_reclen
> 0) {
2628 dp
= (struct dirent
*)
2629 ((char *)dp
+ dp
->d_reclen
);
2636 error
= uiomove(dirbuf
, readcnt
, &auio
);
2638 FREE(dirbuf
, M_TEMP
);
2640 VOP_UNLOCK(vp
, 0, p
);
2646 extern int (**union_vnodeop_p
)(void *);
2647 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2649 if ((uap
->count
== auio
.uio_resid
) &&
2650 (vp
->v_op
== union_vnodeop_p
)) {
2653 lvp
= union_dircache(vp
, p
);
2654 if (lvp
!= NULLVP
) {
2658 * If the directory is opaque,
2659 * then don't show lower entries
2661 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2662 if (va
.va_flags
& OPAQUE
) {
2668 if (lvp
!= NULLVP
) {
2669 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2674 VOP_UNLOCK(lvp
, 0, p
);
2675 fp
->f_data
= (caddr_t
) lvp
;
2677 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2688 if ((uap
->count
== auio
.uio_resid
) &&
2689 (vp
->v_flag
& VROOT
) &&
2690 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2691 struct vnode
*tvp
= vp
;
2692 vp
= vp
->v_mount
->mnt_vnodecovered
;
2694 fp
->f_data
= (caddr_t
) vp
;
2699 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2701 *retval
= uap
->count
- auio
.uio_resid
;
2704 #endif /* COMPAT_43 */
2707 * Read a block of directory entries in a file system independent format.
2709 struct getdirentries_args
{
2716 getdirentries(p
, uap
, retval
)
2718 register struct getdirentries_args
*uap
;
2721 register struct vnode
*vp
;
2728 if (error
= getvnode(p
, uap
->fd
, &fp
))
2730 if ((fp
->f_flag
& FREAD
) == 0)
2732 vp
= (struct vnode
*)fp
->f_data
;
2734 if (vp
->v_type
!= VDIR
)
2736 aiov
.iov_base
= uap
->buf
;
2737 aiov
.iov_len
= uap
->count
;
2738 auio
.uio_iov
= &aiov
;
2739 auio
.uio_iovcnt
= 1;
2740 auio
.uio_rw
= UIO_READ
;
2741 auio
.uio_segflg
= UIO_USERSPACE
;
2743 auio
.uio_resid
= uap
->count
;
2744 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2745 loff
= auio
.uio_offset
= fp
->f_offset
;
2746 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2747 (int *)0, (u_long
*)0);
2748 fp
->f_offset
= auio
.uio_offset
;
2749 VOP_UNLOCK(vp
, 0, p
);
2755 extern int (**union_vnodeop_p
)(void *);
2756 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2758 if ((uap
->count
== auio
.uio_resid
) &&
2759 (vp
->v_op
== union_vnodeop_p
)) {
2762 lvp
= union_dircache(vp
, p
);
2763 if (lvp
!= NULLVP
) {
2767 * If the directory is opaque,
2768 * then don't show lower entries
2770 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2771 if (va
.va_flags
& OPAQUE
) {
2777 if (lvp
!= NULLVP
) {
2778 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2783 VOP_UNLOCK(lvp
, 0, p
);
2784 fp
->f_data
= (caddr_t
) lvp
;
2786 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2797 if ((uap
->count
== auio
.uio_resid
) &&
2798 (vp
->v_flag
& VROOT
) &&
2799 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2800 struct vnode
*tvp
= vp
;
2801 vp
= vp
->v_mount
->mnt_vnodecovered
;
2803 fp
->f_data
= (caddr_t
) vp
;
2808 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2810 *retval
= uap
->count
- auio
.uio_resid
;
2815 * Set the mode mask for creation of filesystem nodes.
2821 umask(p
, uap
, retval
)
2823 struct umask_args
*uap
;
2826 register struct filedesc
*fdp
;
2829 *retval
= fdp
->fd_cmask
;
2830 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
2835 * Void all references to file by ripping underlying filesystem
2838 struct revoke_args
{
2843 revoke(p
, uap
, retval
)
2845 register struct revoke_args
*uap
;
2848 register struct vnode
*vp
;
2851 struct nameidata nd
;
2853 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2854 if (error
= namei(&nd
))
2857 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
2859 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
2860 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
2862 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
2863 VOP_REVOKE(vp
, REVOKEALL
);
2870 * Convert a user file descriptor to a kernel file entry.
2873 getvnode(p
, fd
, fpp
)
2881 if (error
= fdgetf(p
, fd
, &fp
))
2883 if (fp
->f_type
!= DTYPE_VNODE
)
2890 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2891 * The following 10 system calls are designed to support features
2892 * which are specific to the HFS & HFS Plus volume formats
2897 * Make a complex file. A complex file is one with multiple forks (data streams)
2899 struct mkcomplex_args
{
2900 const char *path
; /* pathname of the file to be created */
2901 mode_t mode
; /* access mode for the newly created file */
2902 u_long type
; /* format of the complex file */
2906 mkcomplex(p
,uap
,retval
)
2908 register struct mkcomplex_args
*uap
;
2915 struct nameidata nd
;
2917 /* mkcomplex wants the directory vnode locked so do that here */
2919 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
2920 if (error
= namei(&nd
))
2923 /* Set the attributes as specified by the user */
2926 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
2927 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
2929 /* The mkcomplex call promises to release the parent vnode pointer
2930 * even an an error case so don't do it here unless the operation
2931 * is not supported. In that case, there isn't anyone to unlock the parent
2932 * The vnode pointer to the file will also be released.
2937 if (error
== EOPNOTSUPP
)
2944 } /* end of mkcomplex system call */
2949 * Extended stat call which returns volumeid and vnodeid as well as other info
2952 const char *path
; /* pathname of the target file */
2953 struct vstat
*vsb
; /* vstat structure for returned info */
2959 register struct statv_args
*uap
;
2963 return (EOPNOTSUPP
); /* We'll just return an error for now */
2965 } /* end of statv system call */
2970 * Extended lstat call which returns volumeid and vnodeid as well as other info
2972 struct lstatv_args
{
2973 const char *path
; /* pathname of the target file */
2974 struct vstat
*vsb
; /* vstat structure for returned info */
2978 lstatv(p
,uap
,retval
)
2980 register struct lstatv_args
*uap
;
2984 return (EOPNOTSUPP
); /* We'll just return an error for now */
2985 } /* end of lstatv system call */
2990 * Extended fstat call which returns volumeid and vnodeid as well as other info
2992 struct fstatv_args
{
2993 int fd
; /* file descriptor of the target file */
2994 struct vstat
*vsb
; /* vstat structure for returned info */
2998 fstatv(p
,uap
,retval
)
3000 register struct fstatv_args
*uap
;
3004 return (EOPNOTSUPP
); /* We'll just return an error for now */
3005 } /* end of fstatv system call */
3010 * Obtain attribute information about a file system object
3013 struct getattrlist_args
{
3014 const char *path
; /* pathname of the target object */
3015 struct attrlist
* alist
; /* Attributes desired by the user */
3016 void * attributeBuffer
; /* buffer to hold returned attributes */
3017 size_t bufferSize
; /* size of the return buffer */
3018 unsigned long options
; /* options (follow/don't follow) */
3022 getattrlist (p
,uap
,retval
)
3024 register struct getattrlist_args
*uap
;
3029 struct nameidata nd
;
3032 struct attrlist attributelist
;
3035 /* Get the attributes desire and do our parameter checking */
3037 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3038 sizeof (attributelist
)))
3043 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3045 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3046 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3047 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3048 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3049 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3056 /* Get the vnode for the file we are getting info on. */
3057 nameiflags
= LOCKLEAF
;
3058 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3059 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3061 if (error
= namei(&nd
))
3064 /* Set up the UIO structure for use by the vfs routine */
3067 aiov
.iov_base
= uap
->attributeBuffer
;
3068 aiov
.iov_len
= uap
->bufferSize
;
3069 auio
.uio_iov
= &aiov
;
3070 auio
.uio_iovcnt
= 1;
3071 auio
.uio_offset
= 0;
3072 auio
.uio_rw
= UIO_READ
;
3073 auio
.uio_segflg
= UIO_USERSPACE
;
3075 auio
.uio_resid
= uap
->bufferSize
;
3078 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3080 /* Unlock and release the vnode which will have been locked by namei */
3084 /* return the effort if we got one, otherwise return success */
3093 } /* end of getattrlist system call */
3098 * Set attribute information about a file system object
3101 struct setattrlist_args
{
3102 const char *path
; /* pathname of the target object */
3103 struct attrlist
* alist
; /* Attributes being set by the user */
3104 void * attributeBuffer
; /* buffer with attribute values to be set */
3105 size_t bufferSize
; /* size of the return buffer */
3106 unsigned long options
; /* options (follow/don't follow) */
3110 setattrlist (p
,uap
,retval
)
3112 register struct setattrlist_args
*uap
;
3117 struct nameidata nd
;
3120 struct attrlist alist
;
3123 /* Get the attributes desired and do our parameter checking */
3125 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3130 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3133 /* Get the vnode for the file whose attributes are being set. */
3134 nameiflags
= LOCKLEAF
;
3135 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3136 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3137 if (error
= namei(&nd
))
3140 /* Set up the UIO structure for use by the vfs routine */
3141 aiov
.iov_base
= uap
->attributeBuffer
;
3142 aiov
.iov_len
= uap
->bufferSize
;
3143 auio
.uio_iov
= &aiov
;
3144 auio
.uio_iovcnt
= 1;
3145 auio
.uio_offset
= 0;
3146 auio
.uio_rw
= UIO_WRITE
;
3147 auio
.uio_segflg
= UIO_USERSPACE
;
3149 auio
.uio_resid
= uap
->bufferSize
;
3151 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3157 } /* end of setattrlist system call */
3161 * Obtain attribute information on objects in a directory while enumerating
3162 * the directory. This call does not yet support union mounted directories.
3164 * 1.union mounted directories.
3167 struct getdirentriesattr_args
{
3168 int fd
; /* file descriptor */
3169 struct attrlist
*alist
; /* bit map of requested attributes */
3170 void *buffer
; /* buffer to hold returned attribute info */
3171 size_t buffersize
; /* size of the return buffer */
3172 u_long
*count
; /* the count of entries requested/returned */
3173 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3174 u_long
*newstate
; /* a flag to inform of changes in directory */
3175 u_long options
; /* maybe unused for now */
3179 getdirentriesattr (p
,uap
,retval
)
3181 register struct getdirentriesattr_args
*uap
;
3185 register struct vnode
*vp
;
3193 struct attrlist attributelist
;
3195 /* Get the attributes into kernel space */
3196 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3198 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3201 if (error
= getvnode(p
, uap
->fd
, &fp
))
3203 if ((fp
->f_flag
& FREAD
) == 0)
3205 vp
= (struct vnode
*)fp
->f_data
;
3207 if (vp
->v_type
!= VDIR
)
3210 /* set up the uio structure which will contain the users return buffer */
3211 aiov
.iov_base
= uap
->buffer
;
3212 aiov
.iov_len
= uap
->buffersize
;
3213 auio
.uio_iov
= &aiov
;
3214 auio
.uio_iovcnt
= 1;
3215 auio
.uio_rw
= UIO_READ
;
3216 auio
.uio_segflg
= UIO_USERSPACE
;
3218 auio
.uio_resid
= uap
->buffersize
;
3220 loff
= auio
.uio_offset
= fp
->f_offset
;
3221 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3222 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3223 actualcount
, uap
->options
, &newstate
, &eofflag
,
3224 &actualcount
, ((u_long
**)0), p
->p_cred
);
3226 VOP_UNLOCK(vp
, 0, p
);
3227 if (error
) return (error
);
3228 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3230 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3232 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3234 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3237 *retval
= eofflag
; /* similar to getdirentries */
3238 return (0); /* return error earlier, an retval of 0 or 1 now */
3240 } /* end of getdirentryattr system call */
3243 * Exchange data between two files
3246 struct exchangedata_args
{
3247 const char *path1
; /* pathname of the first swapee */
3248 const char *path2
; /* pathname of the second swapee */
3249 unsigned long options
; /* options */
3253 exchangedata (p
,uap
,retval
)
3255 register struct exchangedata_args
*uap
;
3260 struct nameidata fnd
, snd
;
3261 struct vnode
*fvp
, *svp
;
3266 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3268 /* Global lock, to prevent race condition, only one exchange at a time */
3269 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3271 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3273 if (error
= namei(&fnd
))
3278 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3280 if (error
= namei(&snd
)) {
3287 /* if the files are the same, return an inval error */
3295 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3296 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3298 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3299 if (error
) goto out
;
3301 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3302 if (error
) goto out
;
3304 /* Ok, make the call */
3305 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3312 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3320 } /* end of exchangedata system call */
3323 * Check users access to a file
3326 struct checkuseraccess_args
{
3327 const char *path
; /* pathname of the target file */
3328 uid_t userid
; /* user for whom we are checking access */
3329 gid_t
*groups
; /* Group that we are checking for */
3330 int ngroups
; /* Number of groups being checked */
3331 int accessrequired
; /* needed access to the file */
3332 unsigned long options
; /* options */
3337 checkuseraccess (p
,uap
,retval
)
3339 register struct checkuseraccess_args
*uap
;
3343 register struct vnode
*vp
;
3345 struct nameidata nd
;
3347 int flags
; /*what will actually get passed to access*/
3350 /* Make sure that the number of groups is correct before we do anything */
3352 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3355 /* Verify that the caller is root */
3357 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3360 /* Fill in the credential structure */
3363 cred
.cr_uid
= uap
->userid
;
3364 cred
.cr_ngroups
= uap
->ngroups
;
3365 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3368 /* Get our hands on the file */
3370 nameiflags
= LOCKLEAF
;
3371 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3372 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3374 if (error
= namei(&nd
))
3378 /* Flags == 0 means only check for existence. */
3382 if (uap
->accessrequired
) {
3383 if (uap
->accessrequired
& R_OK
)
3385 if (uap
->accessrequired
& W_OK
)
3387 if (uap
->accessrequired
& X_OK
)
3390 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3399 } /* end of checkuseraccess system call */
3402 struct searchfs_args
{
3404 struct fssearchblock
*searchblock
;
3408 struct searchstate
*state
;
3413 searchfs (p
,uap
,retval
)
3415 register struct searchfs_args
*uap
;
3419 register struct vnode
*vp
;
3422 struct nameidata nd
;
3423 struct fssearchblock searchblock
;
3424 struct searchstate
*state
;
3425 struct attrlist
*returnattrs
;
3426 void *searchparams1
,*searchparams2
;
3434 /* Start by copying in fsearchblock paramater list */
3436 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3439 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3440 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3441 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3444 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3445 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3447 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3449 /* Now set up the various pointers to the correct place in our newly allocated memory */
3451 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3452 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3453 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3455 /* Now copy in the stuff given our local variables. */
3457 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3460 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3463 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3466 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3469 /* set up the uio structure which will contain the users return buffer */
3471 aiov
.iov_base
= searchblock
.returnbuffer
;
3472 aiov
.iov_len
= searchblock
.returnbuffersize
;
3473 auio
.uio_iov
= &aiov
;
3474 auio
.uio_iovcnt
= 1;
3475 auio
.uio_rw
= UIO_READ
;
3476 auio
.uio_segflg
= UIO_USERSPACE
;
3478 auio
.uio_resid
= searchblock
.returnbuffersize
;
3480 nameiflags
= LOCKLEAF
;
3481 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3482 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3484 if (error
= namei(&nd
))
3491 * If searchblock.maxmatches == 0, then skip the search. This has happened
3492 * before and sometimes the underlyning code doesnt deal with it well.
3494 if (searchblock
.maxmatches
== 0) {
3500 Allright, we have everything we need, so lets make that call.
3502 We keep special track of the return value from the file system:
3503 EAGAIN is an acceptable error condition that shouldn't keep us
3504 from copying out any results...
3507 fserror
= VOP_SEARCHFS(vp
,
3510 &searchblock
.searchattrs
,
3511 searchblock
.maxmatches
,
3512 &searchblock
.timelimit
,
3524 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3525 search state. Everything was already put into he return buffer by the vop call. */
3527 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3530 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3537 FREE(searchparams1
,M_TEMP
);
3542 } /* end of searchfs system call */
3546 * Make a filesystem-specific control call:
3549 const char *path
; /* pathname of the target object */
3550 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3551 caddr_t data
; /* pointer to argument buffer */
3552 u_long options
; /* options for fsctl processing */
3556 fsctl (p
,uap
,retval
)
3558 struct fsctl_args
*uap
;
3563 struct nameidata nd
;
3565 u_long cmd
= uap
->cmd
;
3566 register u_int size
;
3567 #define STK_PARAMS 128
3568 char stkbuf
[STK_PARAMS
];
3571 size
= IOCPARM_LEN(cmd
);
3572 if (size
> IOCPARM_MAX
) return (EINVAL
);
3575 if (size
> sizeof (stkbuf
)) {
3576 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3584 error
= copyin(uap
->data
, data
, (u_int
)size
);
3585 if (error
) goto FSCtl_Exit
;
3587 *(caddr_t
*)data
= uap
->data
;
3589 } else if ((cmd
& IOC_OUT
) && size
) {
3591 * Zero the buffer so the user always
3592 * gets back something deterministic.
3595 } else if (cmd
& IOC_VOID
)
3596 *(caddr_t
*)data
= uap
->data
;
3598 /* Get the vnode for the file we are getting info on: */
3599 nameiflags
= LOCKLEAF
;
3600 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3601 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3602 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3604 /* Invoke the filesystem-specific code */
3605 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3610 * Copy any data to user, size was
3611 * already set and checked above.
3613 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3616 if (memp
) kfree(memp
, size
);
3620 /* end of fsctl system call */
3623 * An in-kernel sync for power management to call.
3625 __private_extern__
int
3628 boolean_t funnel_state
;
3631 struct sync_args data
;
3635 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3637 error
= sync(current_proc(), &data
, &retval
);
3639 thread_funnel_set(kernel_flock
, funnel_state
);
3642 } /* end of sync_internal call */