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
;
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 * Put the new filesystem on the mount list after root.
313 simple_lock(&vp
->v_interlock
);
314 CLR(vp
->v_flag
, VMOUNT
);
315 vp
->v_mountedhere
=mp
;
316 simple_unlock(&vp
->v_interlock
);
317 simple_lock(&mountlist_slock
);
318 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
319 simple_unlock(&mountlist_slock
);
321 VOP_UNLOCK(vp
, 0, p
);
323 if (error
= VFS_START(mp
, 0, p
))
326 /* increment the operations count */
330 simple_lock(&vp
->v_interlock
);
331 CLR(vp
->v_flag
, VMOUNT
);
332 simple_unlock(&vp
->v_interlock
);
333 mp
->mnt_vfc
->vfc_refcount
--;
335 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
342 * Scan all active processes to see if any of them have a current
343 * or root directory onto which the new filesystem has just been
344 * mounted. If so, replace them with the new mount point.
350 struct filedesc
*fdp
;
354 if (olddp
->v_usecount
== 1)
356 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
357 panic("mount: lost mount");
358 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
360 if (fdp
->fd_cdir
== olddp
) {
363 fdp
->fd_cdir
= newdp
;
365 if (fdp
->fd_rdir
== olddp
) {
368 fdp
->fd_rdir
= newdp
;
371 if (rootvnode
== olddp
) {
380 * Unmount a file system.
382 * Note: unmount takes a path to the vnode mounted on as argument,
383 * not special file (as before).
385 struct unmount_args
{
391 unmount(p
, uap
, retval
)
393 register struct unmount_args
*uap
;
396 register struct vnode
*vp
;
401 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
403 if (error
= namei(&nd
))
409 * Only root, or the user that did the original mount is
410 * permitted to unmount this filesystem.
412 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
413 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
419 * Don't allow unmounting the root file system.
421 if (mp
->mnt_flag
& MNT_ROOTFS
) {
423 return (EBUSY
); /* the root is always busy */
427 * Must be the root of the filesystem
429 if ((vp
->v_flag
& VROOT
) == 0) {
434 return (dounmount(mp
, uap
->flags
, p
));
438 * Do the actual file system unmount.
441 dounmount(mp
, flags
, p
)
442 register struct mount
*mp
;
446 struct vnode
*coveredvp
;
449 simple_lock(&mountlist_slock
);
450 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
451 lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
, &mountlist_slock
, p
);
452 mp
->mnt_flag
&=~ MNT_ASYNC
;
453 ubc_umount(mp
); /* release cached vnodes */
454 cache_purgevfs(mp
); /* remove cache entries for this file sys */
455 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
456 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
458 error
= VFS_UNMOUNT(mp
, flags
, p
);
459 simple_lock(&mountlist_slock
);
461 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
462 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
463 &mountlist_slock
, p
);
467 /* increment the operations count */
470 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
471 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
472 coveredvp
->v_mountedhere
= (struct mount
*)0;
473 simple_unlock(&mountlist_slock
);
475 simple_lock(&mountlist_slock
);
477 mp
->mnt_vfc
->vfc_refcount
--;
478 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
479 panic("unmount: dangling vnode");
481 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
483 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
486 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
491 * Sync each mounted filesystem.
495 struct ctldebug debug0
= { "syncprt", &syncprt
};
501 int print_vmpage_stat
=0;
507 struct sync_args
*uap
;
510 register struct mount
*mp
, *nmp
;
513 simple_lock(&mountlist_slock
);
514 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
515 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
516 nmp
= mp
->mnt_list
.cqe_next
;
519 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
520 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
521 mp
->mnt_flag
&= ~MNT_ASYNC
;
522 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
524 mp
->mnt_flag
|= MNT_ASYNC
;
526 simple_lock(&mountlist_slock
);
527 nmp
= mp
->mnt_list
.cqe_next
;
530 simple_unlock(&mountlist_slock
);
533 extern void vm_countdirtypages(void);
534 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
535 extern unsigned int dp_pgins
, dp_pgouts
;
536 if(print_vmpage_stat
) {
537 vm_countdirtypages();
538 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
539 dp_pgins
, dp_pgouts
);
545 #endif /* DIAGNOSTIC */
550 * Change filesystem quotas.
552 struct quotactl_args
{
560 quotactl(p
, uap
, retval
)
562 register struct quotactl_args
*uap
;
565 register struct mount
*mp
;
569 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
570 if (error
= namei(&nd
))
572 mp
= nd
.ni_vp
->v_mount
;
574 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
579 * Get filesystem statistics.
587 statfs(p
, uap
, retval
)
589 register struct statfs_args
*uap
;
592 register struct mount
*mp
;
593 register struct statfs
*sp
;
597 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
598 if (error
= namei(&nd
))
600 mp
= nd
.ni_vp
->v_mount
;
603 if (error
= VFS_STATFS(mp
, sp
, p
))
605 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
606 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
607 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
611 * Get filesystem statistics.
613 struct fstatfs_args
{
619 fstatfs(p
, uap
, retval
)
621 register struct fstatfs_args
*uap
;
626 register struct statfs
*sp
;
629 if (error
= getvnode(p
, uap
->fd
, &fp
))
631 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
635 if (error
= VFS_STATFS(mp
, sp
, p
))
637 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
638 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
639 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
643 * Get statistics on all filesystems.
645 struct getfsstat_args
{
651 getfsstat(p
, uap
, retval
)
653 register struct getfsstat_args
*uap
;
656 register struct mount
*mp
, *nmp
;
657 register struct statfs
*sp
;
659 long count
, maxcount
, error
;
661 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
662 sfsp
= (caddr_t
)uap
->buf
;
664 simple_lock(&mountlist_slock
);
665 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
666 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
667 nmp
= mp
->mnt_list
.cqe_next
;
670 if (sfsp
&& count
< maxcount
) {
673 * If MNT_NOWAIT is specified, do not refresh the
674 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
676 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
677 (uap
->flags
& MNT_WAIT
)) &&
678 (error
= VFS_STATFS(mp
, sp
, p
))) {
679 simple_lock(&mountlist_slock
);
680 nmp
= mp
->mnt_list
.cqe_next
;
684 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
685 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
690 simple_lock(&mountlist_slock
);
691 nmp
= mp
->mnt_list
.cqe_next
;
694 simple_unlock(&mountlist_slock
);
695 if (sfsp
&& count
> maxcount
)
703 ogetfsstat(p
, uap
, retval
)
705 register struct getfsstat_args
*uap
;
708 register struct mount
*mp
, *nmp
;
709 register struct statfs
*sp
;
711 long count
, maxcount
, error
;
713 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
714 sfsp
= (caddr_t
)uap
->buf
;
716 simple_lock(&mountlist_slock
);
717 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
718 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
719 nmp
= mp
->mnt_list
.cqe_next
;
722 if (sfsp
&& count
< maxcount
) {
725 * If MNT_NOWAIT is specified, do not refresh the
726 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
728 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
729 (uap
->flags
& MNT_WAIT
)) &&
730 (error
= VFS_STATFS(mp
, sp
, p
))) {
731 simple_lock(&mountlist_slock
);
732 nmp
= mp
->mnt_list
.cqe_next
;
736 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
737 error
= copyout((caddr_t
)sp
, sfsp
,
738 sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
));
741 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
744 simple_lock(&mountlist_slock
);
745 nmp
= mp
->mnt_list
.cqe_next
;
748 simple_unlock(&mountlist_slock
);
749 if (sfsp
&& count
> maxcount
)
758 * Change current working directory to a given file descriptor.
765 fchdir(p
, uap
, retval
)
767 struct fchdir_args
*uap
;
770 register struct filedesc
*fdp
= p
->p_fd
;
771 struct vnode
*vp
, *tdp
;
776 if (error
= getvnode(p
, uap
->fd
, &fp
))
778 vp
= (struct vnode
*)fp
->f_data
;
780 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
781 if (vp
->v_type
!= VDIR
)
784 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
785 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
786 if (vfs_busy(mp
, 0, 0, p
))
788 error
= VFS_ROOT(mp
, &tdp
);
799 VOP_UNLOCK(vp
, 0, p
);
806 * Change current working directory (``.'').
813 chdir(p
, uap
, retval
)
815 struct chdir_args
*uap
;
818 register struct filedesc
*fdp
= p
->p_fd
;
822 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
824 if (error
= change_dir(&nd
, p
))
827 fdp
->fd_cdir
= nd
.ni_vp
;
832 * Change notion of root (``/'') directory.
839 chroot(p
, uap
, retval
)
841 struct chroot_args
*uap
;
844 register struct filedesc
*fdp
= p
->p_fd
;
848 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
851 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
853 if (error
= change_dir(&nd
, p
))
856 if(error
= clone_system_shared_regions()) {
861 if (fdp
->fd_rdir
!= NULL
)
863 fdp
->fd_rdir
= nd
.ni_vp
;
868 * Common routine for chroot and chdir.
872 register struct nameidata
*ndp
;
878 if (error
= namei(ndp
))
881 if (vp
->v_type
!= VDIR
)
884 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
888 VOP_UNLOCK(vp
, 0, p
);
893 * Check permissions, allocate an open file structure,
894 * and call the device open routine if any.
904 register struct open_args
*uap
;
907 register struct filedesc
*fdp
= p
->p_fd
;
908 register struct file
*fp
;
909 register struct vnode
*vp
;
910 int flags
, cmode
, oflags
;
912 int type
, indx
, error
;
915 extern struct fileops vnops
;
918 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
920 flags
= FFLAGS(uap
->flags
);
921 if (error
= falloc(p
, &nfp
, &indx
))
924 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
925 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
926 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
927 if (error
= vn_open(&nd
, flags
, cmode
)) {
929 if ((error
== ENODEV
|| error
== ENXIO
) &&
930 p
->p_dupfd
>= 0 && /* XXX from fdopen */
932 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
936 if (error
== ERESTART
)
943 fp
->f_flag
= flags
& FMASK
;
944 fp
->f_type
= DTYPE_VNODE
;
946 fp
->f_data
= (caddr_t
)vp
;
947 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
948 lf
.l_whence
= SEEK_SET
;
951 if (flags
& O_EXLOCK
)
956 if ((flags
& FNONBLOCK
) == 0)
958 VOP_UNLOCK(vp
, 0, p
);
959 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
960 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
965 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
966 fp
->f_flag
|= FHASLOCK
;
968 VOP_UNLOCK(vp
, 0, p
);
969 *fdflags(p
, indx
) &= ~UF_RESERVED
;
983 ocreat(p
, uap
, retval
)
985 register struct ocreat_args
*uap
;
988 struct open_args nuap
;
990 nuap
.path
= uap
->path
;
991 nuap
.mode
= uap
->mode
;
992 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
993 return (open(p
, &nuap
, retval
));
995 #endif /* COMPAT_43 */
998 * Create a special file.
1007 mknod(p
, uap
, retval
)
1009 register struct mknod_args
*uap
;
1012 register struct vnode
*vp
;
1016 struct nameidata nd
;
1018 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1020 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1021 if (error
= namei(&nd
))
1028 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1029 vattr
.va_rdev
= uap
->dev
;
1032 switch (uap
->mode
& S_IFMT
) {
1033 case S_IFMT
: /* used by badsect to flag bad sectors */
1034 vattr
.va_type
= VBAD
;
1037 vattr
.va_type
= VCHR
;
1040 vattr
.va_type
= VBLK
;
1051 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1053 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1055 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1058 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1059 &nd
.ni_cnd
, &vattr
);
1062 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1063 if (nd
.ni_dvp
== vp
)
1074 * Create a named pipe.
1076 struct mkfifo_args
{
1082 mkfifo(p
, uap
, retval
)
1084 register struct mkfifo_args
*uap
;
1089 struct nameidata nd
;
1092 return (EOPNOTSUPP
);
1094 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1095 if (error
= namei(&nd
))
1097 if (nd
.ni_vp
!= NULL
) {
1098 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1099 if (nd
.ni_dvp
== nd
.ni_vp
)
1107 vattr
.va_type
= VFIFO
;
1108 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1109 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1110 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1115 * Make a hard file link.
1123 link(p
, uap
, retval
)
1125 register struct link_args
*uap
;
1128 register struct vnode
*vp
;
1129 struct nameidata nd
;
1132 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1133 if (error
= namei(&nd
))
1136 if (vp
->v_type
== VDIR
)
1137 error
= EPERM
; /* POSIX */
1139 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1140 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1141 nd
.ni_dirp
= uap
->link
;
1142 if ((error
= namei(&nd
)) == 0) {
1143 if (nd
.ni_vp
!= NULL
)
1146 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1148 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1149 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1151 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1152 if (nd
.ni_dvp
== nd
.ni_vp
)
1166 * Make a symbolic link.
1168 struct symlink_args
{
1174 symlink(p
, uap
, retval
)
1176 register struct symlink_args
*uap
;
1182 struct nameidata nd
;
1184 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1185 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1187 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1188 if (error
= namei(&nd
))
1191 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1192 if (nd
.ni_dvp
== nd
.ni_vp
)
1201 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1202 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1203 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1205 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1210 * Delete a whiteout from the filesystem.
1212 struct undelete_args
{
1217 undelete(p
, uap
, retval
)
1219 register struct undelete_args
*uap
;
1223 struct nameidata nd
;
1225 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1231 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1232 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1233 if (nd
.ni_dvp
== nd
.ni_vp
)
1242 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1243 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1244 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1250 * Delete a name from the filesystem.
1252 struct unlink_args
{
1257 _unlink(p
, uap
, retval
, nodelbusy
)
1259 struct unlink_args
*uap
;
1263 register struct vnode
*vp
;
1265 struct nameidata nd
;
1267 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1268 /* with Carbon semantics, busy files cannot be deleted */
1270 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1271 if (error
= namei(&nd
))
1274 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1275 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1277 if (vp
->v_type
== VDIR
)
1278 error
= EPERM
; /* POSIX */
1281 * The root of a mounted filesystem cannot be deleted.
1283 * XXX: can this only be a VDIR case?
1285 if (vp
->v_flag
& VROOT
)
1290 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1291 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1293 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1294 if (nd
.ni_dvp
== vp
)
1305 * Delete a name from the filesystem using POSIX semantics.
1308 unlink(p
, uap
, retval
)
1310 struct unlink_args
*uap
;
1313 return _unlink(p
, uap
, retval
, 0);
1317 * Delete a name from the filesystem using Carbon semantics.
1320 delete(p
, uap
, retval
)
1322 struct unlink_args
*uap
;
1325 return _unlink(p
, uap
, retval
, 1);
1329 * Reposition read/write file offset.
1333 #ifdef DOUBLE_ALIGN_PARAMS
1340 lseek(p
, uap
, retval
)
1342 register struct lseek_args
*uap
;
1345 struct ucred
*cred
= p
->p_ucred
;
1350 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1352 if (fp
->f_type
!= DTYPE_VNODE
)
1354 switch (uap
->whence
) {
1356 fp
->f_offset
+= uap
->offset
;
1360 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1362 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1365 fp
->f_offset
= uap
->offset
;
1370 *(off_t
*)retval
= fp
->f_offset
;
1376 * Reposition read/write file offset.
1378 struct olseek_args
{
1384 olseek(p
, uap
, retval
)
1386 register struct olseek_args
*uap
;
1389 struct lseek_args
/* {
1391 #ifdef DOUBLE_ALIGN_PARAMS
1392 syscallarg(int) pad;
1394 syscallarg(off_t) offset;
1395 syscallarg(int) whence;
1401 nuap
.offset
= uap
->offset
;
1402 nuap
.whence
= uap
->whence
;
1403 error
= lseek(p
, &nuap
, &qret
);
1404 *(long *)retval
= qret
;
1407 #endif /* COMPAT_43 */
1410 * Check access permissions.
1412 struct access_args
{
1417 access(p
, uap
, retval
)
1419 register struct access_args
*uap
;
1422 register struct ucred
*cred
= p
->p_ucred
;
1423 register struct vnode
*vp
;
1424 int error
, flags
, t_gid
, t_uid
;
1425 struct nameidata nd
;
1427 t_uid
= cred
->cr_uid
;
1428 t_gid
= cred
->cr_groups
[0];
1429 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1430 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1431 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1433 if (error
= namei(&nd
))
1437 /* Flags == 0 means only check for existence. */
1440 if (uap
->flags
& R_OK
)
1442 if (uap
->flags
& W_OK
)
1444 if (uap
->flags
& X_OK
)
1446 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1447 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1451 cred
->cr_uid
= t_uid
;
1452 cred
->cr_groups
[0] = t_gid
;
1458 * Get file status; this version follows links.
1466 ostat(p
, uap
, retval
)
1468 register struct ostat_args
*uap
;
1474 struct nameidata nd
;
1476 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1478 if (error
= namei(&nd
))
1480 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1485 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1490 * Get file status; this version does not follow links.
1492 struct olstat_args
{
1498 olstat(p
, uap
, retval
)
1500 register struct olstat_args
*uap
;
1503 struct vnode
*vp
, *dvp
;
1504 struct stat sb
, sb1
;
1507 struct nameidata nd
;
1509 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1511 if (error
= namei(&nd
))
1514 * For symbolic links, always return the attributes of its
1515 * containing directory, except for mode, size, and links.
1519 if (vp
->v_type
!= VLNK
) {
1524 error
= vn_stat(vp
, &sb
, p
);
1529 error
= vn_stat(dvp
, &sb
, p
);
1535 error
= vn_stat(vp
, &sb1
, p
);
1539 sb
.st_mode
&= ~S_IFDIR
;
1540 sb
.st_mode
|= S_IFLNK
;
1541 sb
.st_nlink
= sb1
.st_nlink
;
1542 sb
.st_size
= sb1
.st_size
;
1543 sb
.st_blocks
= sb1
.st_blocks
;
1546 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1551 * Convert from an old to a new stat structure.
1559 ost
->st_dev
= st
->st_dev
;
1560 ost
->st_ino
= st
->st_ino
;
1561 ost
->st_mode
= st
->st_mode
;
1562 ost
->st_nlink
= st
->st_nlink
;
1563 ost
->st_uid
= st
->st_uid
;
1564 ost
->st_gid
= st
->st_gid
;
1565 ost
->st_rdev
= st
->st_rdev
;
1566 if (st
->st_size
< (quad_t
)1 << 32)
1567 ost
->st_size
= st
->st_size
;
1570 ost
->st_atime
= st
->st_atime
;
1571 ost
->st_mtime
= st
->st_mtime
;
1572 ost
->st_ctime
= st
->st_ctime
;
1573 ost
->st_blksize
= st
->st_blksize
;
1574 ost
->st_blocks
= st
->st_blocks
;
1575 ost
->st_flags
= st
->st_flags
;
1576 ost
->st_gen
= st
->st_gen
;
1578 #endif /* COMPAT_43 */
1581 * Get file status; this version follows links.
1589 stat(p
, uap
, retval
)
1591 register struct stat_args
*uap
;
1596 struct nameidata nd
;
1598 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1600 if (error
= namei(&nd
))
1602 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1606 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1611 * Get file status; this version does not follow links.
1619 lstat(p
, uap
, retval
)
1621 register struct lstat_args
*uap
;
1625 struct vnode
*vp
, *dvp
;
1626 struct stat sb
, sb1
;
1627 struct nameidata nd
;
1629 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1631 if (error
= namei(&nd
))
1634 * For symbolic links, always return the attributes of its containing
1635 * directory, except for mode, size, inode number, and links.
1639 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1644 error
= vn_stat(vp
, &sb
, p
);
1648 if (vp
->v_type
== VLNK
)
1649 sb
.st_mode
|= S_IFLNK
;
1651 error
= vn_stat(dvp
, &sb
, p
);
1657 error
= vn_stat(vp
, &sb1
, p
);
1661 sb
.st_mode
&= ~S_IFDIR
;
1662 sb
.st_mode
|= S_IFLNK
;
1663 sb
.st_nlink
= sb1
.st_nlink
;
1664 sb
.st_size
= sb1
.st_size
;
1665 sb
.st_blocks
= sb1
.st_blocks
;
1666 sb
.st_ino
= sb1
.st_ino
;
1668 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1673 * Get configurable pathname variables.
1675 struct pathconf_args
{
1681 pathconf(p
, uap
, retval
)
1683 register struct pathconf_args
*uap
;
1687 struct nameidata nd
;
1689 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1691 if (error
= namei(&nd
))
1693 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1699 * Return target name of a symbolic link.
1701 struct readlink_args
{
1708 readlink(p
, uap
, retval
)
1710 register struct readlink_args
*uap
;
1713 register struct vnode
*vp
;
1717 struct nameidata nd
;
1719 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1721 if (error
= namei(&nd
))
1724 if (vp
->v_type
!= VLNK
)
1727 aiov
.iov_base
= uap
->buf
;
1728 aiov
.iov_len
= uap
->count
;
1729 auio
.uio_iov
= &aiov
;
1730 auio
.uio_iovcnt
= 1;
1731 auio
.uio_offset
= 0;
1732 auio
.uio_rw
= UIO_READ
;
1733 auio
.uio_segflg
= UIO_USERSPACE
;
1735 auio
.uio_resid
= uap
->count
;
1736 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1739 *retval
= uap
->count
- auio
.uio_resid
;
1744 * Change flags of a file given a path name.
1746 struct chflags_args
{
1752 chflags(p
, uap
, retval
)
1754 register struct chflags_args
*uap
;
1757 register struct vnode
*vp
;
1760 struct nameidata nd
;
1762 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1763 if (error
= namei(&nd
))
1766 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1767 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1769 vattr
.va_flags
= uap
->flags
;
1770 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1776 * Change flags of a file given a file descriptor.
1778 struct fchflags_args
{
1784 fchflags(p
, uap
, retval
)
1786 register struct fchflags_args
*uap
;
1794 if (error
= getvnode(p
, uap
->fd
, &fp
))
1796 vp
= (struct vnode
*)fp
->f_data
;
1797 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1798 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1800 vattr
.va_flags
= uap
->flags
;
1801 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1802 VOP_UNLOCK(vp
, 0, p
);
1807 * Change mode of a file given path name.
1815 chmod(p
, uap
, retval
)
1817 register struct chmod_args
*uap
;
1820 register struct vnode
*vp
;
1823 struct nameidata nd
;
1825 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1826 if (error
= namei(&nd
))
1829 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1830 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1832 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1833 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1839 * Change mode of a file given a file descriptor.
1841 struct fchmod_args
{
1847 fchmod(p
, uap
, retval
)
1849 register struct fchmod_args
*uap
;
1857 if (error
= getvnode(p
, uap
->fd
, &fp
))
1859 vp
= (struct vnode
*)fp
->f_data
;
1860 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1861 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1863 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1864 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1865 VOP_UNLOCK(vp
, 0, p
);
1870 * Set ownership given a path name.
1879 chown(p
, uap
, retval
)
1881 register struct chown_args
*uap
;
1884 register struct vnode
*vp
;
1887 struct nameidata nd
;
1889 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1890 if (error
= namei(&nd
))
1895 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
1896 * by looking for chown() calls on /dev/console from a console process.
1898 if ((vp
) && (vp
->v_specinfo
) &&
1899 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
1900 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
1901 console_user
= uap
->uid
;
1904 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1905 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1907 vattr
.va_uid
= uap
->uid
;
1908 vattr
.va_gid
= uap
->gid
;
1909 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1915 * Set ownership given a file descriptor.
1917 struct fchown_args
{
1924 fchown(p
, uap
, retval
)
1926 register struct fchown_args
*uap
;
1934 if (error
= getvnode(p
, uap
->fd
, &fp
))
1936 vp
= (struct vnode
*)fp
->f_data
;
1937 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1938 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1940 vattr
.va_uid
= uap
->uid
;
1941 vattr
.va_gid
= uap
->gid
;
1942 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1943 VOP_UNLOCK(vp
, 0, p
);
1948 * Set the access and modification times of a file.
1950 struct utimes_args
{
1952 struct timeval
*tptr
;
1956 utimes(p
, uap
, retval
)
1958 register struct utimes_args
*uap
;
1961 register struct vnode
*vp
;
1962 struct timeval tv
[2];
1965 struct nameidata nd
;
1968 if (uap
->tptr
== NULL
) {
1971 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
1972 } else if (error
= copyin((caddr_t
)uap
->tptr
, (caddr_t
)tv
,
1975 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1976 if (error
= namei(&nd
))
1979 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1980 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1981 vattr
.va_atime
.tv_sec
= tv
[0].tv_sec
;
1982 vattr
.va_atime
.tv_nsec
= tv
[0].tv_usec
* 1000;
1983 vattr
.va_mtime
.tv_sec
= tv
[1].tv_sec
;
1984 vattr
.va_mtime
.tv_nsec
= tv
[1].tv_usec
* 1000;
1985 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1991 * Truncate a file given its path name.
1993 struct truncate_args
{
1995 #ifdef DOUBLE_ALIGN_PARAMS
2002 truncate(p
, uap
, retval
)
2004 register struct truncate_args
*uap
;
2007 register struct vnode
*vp
;
2010 struct nameidata nd
;
2012 if (uap
->length
< 0)
2014 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2015 if (error
= namei(&nd
))
2018 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2019 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2020 if (vp
->v_type
== VDIR
)
2022 else if ((error
= vn_writechk(vp
)) == 0 &&
2023 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2025 vattr
.va_size
= uap
->length
;
2026 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2033 * Truncate a file given a file descriptor.
2035 struct ftruncate_args
{
2037 #ifdef DOUBLE_ALIGN_PARAMS
2044 ftruncate(p
, uap
, retval
)
2046 register struct ftruncate_args
*uap
;
2054 if (uap
->length
< 0)
2057 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2060 if (fp
->f_type
== DTYPE_PSXSHM
) {
2061 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2063 if (fp
->f_type
!= DTYPE_VNODE
)
2066 if ((fp
->f_flag
& FWRITE
) == 0)
2068 vp
= (struct vnode
*)fp
->f_data
;
2069 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2070 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2071 if (vp
->v_type
== VDIR
)
2073 else if ((error
= vn_writechk(vp
)) == 0) {
2075 vattr
.va_size
= uap
->length
;
2076 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2078 VOP_UNLOCK(vp
, 0, p
);
2084 * Truncate a file given its path name.
2086 struct otruncate_args
{
2092 otruncate(p
, uap
, retval
)
2094 register struct otruncate_args
*uap
;
2097 struct truncate_args
/* {
2098 syscallarg(char *) path;
2099 #ifdef DOUBLE_ALIGN_PARAMS
2100 syscallarg(int) pad;
2102 syscallarg(off_t) length;
2105 nuap
.path
= uap
->path
;
2106 nuap
.length
= uap
->length
;
2107 return (truncate(p
, &nuap
, retval
));
2111 * Truncate a file given a file descriptor.
2113 struct oftruncate_args
{
2119 oftruncate(p
, uap
, retval
)
2121 register struct oftruncate_args
*uap
;
2124 struct ftruncate_args
/* {
2126 #ifdef DOUBLE_ALIGN_PARAMS
2127 syscallarg(int) pad;
2129 syscallarg(off_t) length;
2133 nuap
.length
= uap
->length
;
2134 return (ftruncate(p
, &nuap
, retval
));
2136 #endif /* COMPAT_43 */
2139 * Sync an open file.
2146 fsync(p
, uap
, retval
)
2148 struct fsync_args
*uap
;
2151 register struct vnode
*vp
;
2155 if (error
= getvnode(p
, uap
->fd
, &fp
))
2157 vp
= (struct vnode
*)fp
->f_data
;
2158 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2159 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2160 VOP_UNLOCK(vp
, 0, p
);
2165 * Duplicate files. Source must be a file, target must be a file or
2169 struct copyfile_args
{
2177 copyfile(p
, uap
, retval
)
2179 register struct copyfile_args
*uap
;
2182 register struct vnode
*tvp
, *fvp
, *tdvp
;
2183 register struct ucred
*cred
= p
->p_ucred
;
2184 struct nameidata fromnd
, tond
;
2187 /* Check that the flags are valid.
2190 if (uap
->flags
& ~CPF_MASK
) {
2194 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2196 if (error
= namei(&fromnd
))
2200 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2201 UIO_USERSPACE
, uap
->to
, p
);
2202 if (error
= namei(&tond
)) {
2209 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2215 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2220 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2226 * If source is the same as the destination (that is the
2227 * same inode number) then there is nothing to do.
2228 * (fixed to have POSIX semantics - CSM 3/2/98)
2234 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2236 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2245 vrele(tond
.ni_startdir
);
2246 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2248 if (fromnd
.ni_startdir
)
2249 vrele(fromnd
.ni_startdir
);
2250 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2257 * Rename files. Source and destination must either both be directories,
2258 * or both not be directories. If target is a directory, it must be empty.
2260 struct rename_args
{
2266 rename(p
, uap
, retval
)
2268 register struct rename_args
*uap
;
2271 register struct vnode
*tvp
, *fvp
, *tdvp
;
2272 struct nameidata fromnd
, tond
;
2275 int casesense
,casepres
;
2279 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2281 if (error
= namei(&fromnd
))
2285 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2286 UIO_USERSPACE
, uap
->to
, p
);
2287 if (error
= namei(&tond
)) {
2288 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2289 vrele(fromnd
.ni_dvp
);
2297 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2300 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2308 * If source is the same as the destination (that is the
2309 * same inode number) then there is nothing to do...
2311 * underlyning file system supports case insensitivity and is case preserving. Then
2312 * a special case is made, i.e. foo -> Foo.
2314 * Only file systems that support the pathconf selectors _PC_CASE_SENSITIVE and
2315 * _PC_CASE_PRESERVING can have this exception, and then they would need to
2316 * handle the special case of getting the same vnode as target and source.
2317 * NOTE: Then the target is unlocked going into VOP_RENAME, so not to cause
2318 * locking problems. There is a single reference on tvp.
2323 * Check to see if just changing case, if:
2324 * - file system is case insensitive
2325 * - and also case preserving
2326 * _ same parent directories (so changing case by different links is not supported)
2327 * For instance: mv a/foo a/Foo
2329 if ((tond
.ni_dvp
== fromnd
.ni_dvp
) &&
2330 (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
) == 0) &&
2331 (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
) == 0) &&
2334 /* Since the target is locked...unlock it and lose a ref */
2341 * Allow the renaming of mount points.
2342 * - target must not exist
2343 * - target must reside in the same directory as source
2344 * - union mounts cannot be renamed
2345 * - "/" cannot be renamed
2347 if ((fvp
->v_flag
& VROOT
) &&
2348 (fvp
->v_type
== VDIR
) &&
2350 (fvp
->v_mountedhere
== NULL
) &&
2351 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2352 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2353 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2355 /* switch fvp to the covered vnode */
2356 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2364 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2365 if (fromnd
.ni_dvp
!= tdvp
)
2366 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2368 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2369 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2370 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2375 * update filesystem's mount point data
2378 char *cp
, *pathend
, *mpname
;
2385 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2386 mp
= fvp
->v_mountedhere
;
2388 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2393 VOP_UNLOCK(fvp
, 0, p
);
2395 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2396 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2398 /* find current mount point prefix */
2399 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2400 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2404 /* find last component of target name */
2405 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2409 /* append name to prefix */
2410 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2411 bzero(pathend
, maxlen
);
2412 strncpy(pathend
, mpname
, maxlen
- 1);
2414 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2420 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2427 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2428 vrele(fromnd
.ni_dvp
);
2432 vrele(tond
.ni_startdir
);
2433 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2435 if (fromnd
.ni_startdir
)
2436 vrele(fromnd
.ni_startdir
);
2437 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2444 * Make a directory file.
2452 mkdir(p
, uap
, retval
)
2454 register struct mkdir_args
*uap
;
2457 register struct vnode
*vp
;
2460 struct nameidata nd
;
2462 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2463 if (error
= namei(&nd
))
2467 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2468 if (nd
.ni_dvp
== vp
)
2476 vattr
.va_type
= VDIR
;
2477 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2478 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2479 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2486 * Remove a directory file.
2493 rmdir(p
, uap
, retval
)
2495 struct rmdir_args
*uap
;
2498 register struct vnode
*vp
;
2500 struct nameidata nd
;
2502 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2504 if (error
= namei(&nd
))
2507 if (vp
->v_type
!= VDIR
) {
2512 * No rmdir "." please.
2514 if (nd
.ni_dvp
== vp
) {
2519 * The root of a mounted filesystem cannot be deleted.
2521 if (vp
->v_flag
& VROOT
)
2525 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2526 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2527 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2529 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2530 if (nd
.ni_dvp
== vp
)
2541 * Read a block of directory entries in a file system independent format.
2543 struct ogetdirentries_args
{
2550 ogetdirentries(p
, uap
, retval
)
2552 register struct ogetdirentries_args
*uap
;
2555 register struct vnode
*vp
;
2557 struct uio auio
, kuio
;
2558 struct iovec aiov
, kiov
;
2559 struct dirent
*dp
, *edp
;
2561 int error
, eofflag
, readcnt
;
2564 if (error
= getvnode(p
, uap
->fd
, &fp
))
2566 if ((fp
->f_flag
& FREAD
) == 0)
2568 vp
= (struct vnode
*)fp
->f_data
;
2570 if (vp
->v_type
!= VDIR
)
2572 aiov
.iov_base
= uap
->buf
;
2573 aiov
.iov_len
= uap
->count
;
2574 auio
.uio_iov
= &aiov
;
2575 auio
.uio_iovcnt
= 1;
2576 auio
.uio_rw
= UIO_READ
;
2577 auio
.uio_segflg
= UIO_USERSPACE
;
2579 auio
.uio_resid
= uap
->count
;
2580 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2581 loff
= auio
.uio_offset
= fp
->f_offset
;
2582 # if (BYTE_ORDER != LITTLE_ENDIAN)
2583 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2584 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2585 (int *)0, (u_long
*)0);
2586 fp
->f_offset
= auio
.uio_offset
;
2591 kuio
.uio_iov
= &kiov
;
2592 kuio
.uio_segflg
= UIO_SYSSPACE
;
2593 kiov
.iov_len
= uap
->count
;
2594 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2595 kiov
.iov_base
= dirbuf
;
2596 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2597 (int *)0, (u_long
*)0);
2598 fp
->f_offset
= kuio
.uio_offset
;
2600 readcnt
= uap
->count
- kuio
.uio_resid
;
2601 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2602 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2603 # if (BYTE_ORDER == LITTLE_ENDIAN)
2605 * The expected low byte of
2606 * dp->d_namlen is our dp->d_type.
2607 * The high MBZ byte of dp->d_namlen
2608 * is our dp->d_namlen.
2610 dp
->d_type
= dp
->d_namlen
;
2614 * The dp->d_type is the high byte
2615 * of the expected dp->d_namlen,
2616 * so must be zero'ed.
2620 if (dp
->d_reclen
> 0) {
2621 dp
= (struct dirent
*)
2622 ((char *)dp
+ dp
->d_reclen
);
2629 error
= uiomove(dirbuf
, readcnt
, &auio
);
2631 FREE(dirbuf
, M_TEMP
);
2633 VOP_UNLOCK(vp
, 0, p
);
2639 extern int (**union_vnodeop_p
)(void *);
2640 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2642 if ((uap
->count
== auio
.uio_resid
) &&
2643 (vp
->v_op
== union_vnodeop_p
)) {
2646 lvp
= union_dircache(vp
, p
);
2647 if (lvp
!= NULLVP
) {
2651 * If the directory is opaque,
2652 * then don't show lower entries
2654 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2655 if (va
.va_flags
& OPAQUE
) {
2661 if (lvp
!= NULLVP
) {
2662 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2667 VOP_UNLOCK(lvp
, 0, p
);
2668 fp
->f_data
= (caddr_t
) lvp
;
2670 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2681 if ((uap
->count
== auio
.uio_resid
) &&
2682 (vp
->v_flag
& VROOT
) &&
2683 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2684 struct vnode
*tvp
= vp
;
2685 vp
= vp
->v_mount
->mnt_vnodecovered
;
2687 fp
->f_data
= (caddr_t
) vp
;
2692 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2694 *retval
= uap
->count
- auio
.uio_resid
;
2697 #endif /* COMPAT_43 */
2700 * Read a block of directory entries in a file system independent format.
2702 struct getdirentries_args
{
2709 getdirentries(p
, uap
, retval
)
2711 register struct getdirentries_args
*uap
;
2714 register struct vnode
*vp
;
2721 if (error
= getvnode(p
, uap
->fd
, &fp
))
2723 if ((fp
->f_flag
& FREAD
) == 0)
2725 vp
= (struct vnode
*)fp
->f_data
;
2727 if (vp
->v_type
!= VDIR
)
2729 aiov
.iov_base
= uap
->buf
;
2730 aiov
.iov_len
= uap
->count
;
2731 auio
.uio_iov
= &aiov
;
2732 auio
.uio_iovcnt
= 1;
2733 auio
.uio_rw
= UIO_READ
;
2734 auio
.uio_segflg
= UIO_USERSPACE
;
2736 auio
.uio_resid
= uap
->count
;
2737 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2738 loff
= auio
.uio_offset
= fp
->f_offset
;
2739 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2740 (int *)0, (u_long
*)0);
2741 fp
->f_offset
= auio
.uio_offset
;
2742 VOP_UNLOCK(vp
, 0, p
);
2748 extern int (**union_vnodeop_p
)(void *);
2749 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2751 if ((uap
->count
== auio
.uio_resid
) &&
2752 (vp
->v_op
== union_vnodeop_p
)) {
2755 lvp
= union_dircache(vp
, p
);
2756 if (lvp
!= NULLVP
) {
2760 * If the directory is opaque,
2761 * then don't show lower entries
2763 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2764 if (va
.va_flags
& OPAQUE
) {
2770 if (lvp
!= NULLVP
) {
2771 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2776 VOP_UNLOCK(lvp
, 0, p
);
2777 fp
->f_data
= (caddr_t
) lvp
;
2779 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2790 if ((uap
->count
== auio
.uio_resid
) &&
2791 (vp
->v_flag
& VROOT
) &&
2792 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2793 struct vnode
*tvp
= vp
;
2794 vp
= vp
->v_mount
->mnt_vnodecovered
;
2796 fp
->f_data
= (caddr_t
) vp
;
2801 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2803 *retval
= uap
->count
- auio
.uio_resid
;
2808 * Set the mode mask for creation of filesystem nodes.
2814 umask(p
, uap
, retval
)
2816 struct umask_args
*uap
;
2819 register struct filedesc
*fdp
;
2822 *retval
= fdp
->fd_cmask
;
2823 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
2828 * Void all references to file by ripping underlying filesystem
2831 struct revoke_args
{
2836 revoke(p
, uap
, retval
)
2838 register struct revoke_args
*uap
;
2841 register struct vnode
*vp
;
2844 struct nameidata nd
;
2846 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2847 if (error
= namei(&nd
))
2850 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
2852 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
2853 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
2855 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
2856 VOP_REVOKE(vp
, REVOKEALL
);
2863 * Convert a user file descriptor to a kernel file entry.
2866 getvnode(p
, fd
, fpp
)
2874 if (error
= fdgetf(p
, fd
, &fp
))
2876 if (fp
->f_type
!= DTYPE_VNODE
)
2883 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2884 * The following 10 system calls are designed to support features
2885 * which are specific to the HFS & HFS Plus volume formats
2890 * Make a complex file. A complex file is one with multiple forks (data streams)
2892 struct mkcomplex_args
{
2893 const char *path
; /* pathname of the file to be created */
2894 mode_t mode
; /* access mode for the newly created file */
2895 u_long type
; /* format of the complex file */
2899 mkcomplex(p
,uap
,retval
)
2901 register struct mkcomplex_args
*uap
;
2908 struct nameidata nd
;
2910 /* mkcomplex wants the directory vnode locked so do that here */
2912 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
2913 if (error
= namei(&nd
))
2916 /* Set the attributes as specified by the user */
2919 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
2920 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
2922 /* The mkcomplex call promises to release the parent vnode pointer
2923 * even an an error case so don't do it here unless the operation
2924 * is not supported. In that case, there isn't anyone to unlock the parent
2925 * The vnode pointer to the file will also be released.
2930 if (error
== EOPNOTSUPP
)
2937 } /* end of mkcomplex system call */
2942 * Extended stat call which returns volumeid and vnodeid as well as other info
2945 const char *path
; /* pathname of the target file */
2946 struct vstat
*vsb
; /* vstat structure for returned info */
2952 register struct statv_args
*uap
;
2956 return (EOPNOTSUPP
); /* We'll just return an error for now */
2958 } /* end of statv system call */
2963 * Extended lstat call which returns volumeid and vnodeid as well as other info
2965 struct lstatv_args
{
2966 const char *path
; /* pathname of the target file */
2967 struct vstat
*vsb
; /* vstat structure for returned info */
2971 lstatv(p
,uap
,retval
)
2973 register struct lstatv_args
*uap
;
2977 return (EOPNOTSUPP
); /* We'll just return an error for now */
2978 } /* end of lstatv system call */
2983 * Extended fstat call which returns volumeid and vnodeid as well as other info
2985 struct fstatv_args
{
2986 int fd
; /* file descriptor of the target file */
2987 struct vstat
*vsb
; /* vstat structure for returned info */
2991 fstatv(p
,uap
,retval
)
2993 register struct fstatv_args
*uap
;
2997 return (EOPNOTSUPP
); /* We'll just return an error for now */
2998 } /* end of fstatv system call */
3003 * Obtain attribute information about a file system object
3006 struct getattrlist_args
{
3007 const char *path
; /* pathname of the target object */
3008 struct attrlist
* alist
; /* Attributes desired by the user */
3009 void * attributeBuffer
; /* buffer to hold returned attributes */
3010 size_t bufferSize
; /* size of the return buffer */
3011 unsigned long options
; /* options (follow/don't follow) */
3015 getattrlist (p
,uap
,retval
)
3017 register struct getattrlist_args
*uap
;
3022 struct nameidata nd
;
3025 struct attrlist attributelist
;
3028 /* Get the attributes desire and do our parameter checking */
3030 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3031 sizeof (attributelist
)))
3036 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3038 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3039 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3040 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3041 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3042 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3049 /* Get the vnode for the file we are getting info on. */
3050 nameiflags
= LOCKLEAF
;
3051 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3052 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3054 if (error
= namei(&nd
))
3057 /* Set up the UIO structure for use by the vfs routine */
3060 aiov
.iov_base
= uap
->attributeBuffer
;
3061 aiov
.iov_len
= uap
->bufferSize
;
3062 auio
.uio_iov
= &aiov
;
3063 auio
.uio_iovcnt
= 1;
3064 auio
.uio_offset
= 0;
3065 auio
.uio_rw
= UIO_READ
;
3066 auio
.uio_segflg
= UIO_USERSPACE
;
3068 auio
.uio_resid
= uap
->bufferSize
;
3071 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3073 /* Unlock and release the vnode which will have been locked by namei */
3077 /* return the effort if we got one, otherwise return success */
3086 } /* end of getattrlist system call */
3091 * Set attribute information about a file system object
3094 struct setattrlist_args
{
3095 const char *path
; /* pathname of the target object */
3096 struct attrlist
* alist
; /* Attributes being set by the user */
3097 void * attributeBuffer
; /* buffer with attribute values to be set */
3098 size_t bufferSize
; /* size of the return buffer */
3099 unsigned long options
; /* options (follow/don't follow) */
3103 setattrlist (p
,uap
,retval
)
3105 register struct setattrlist_args
*uap
;
3110 struct nameidata nd
;
3113 struct attrlist alist
;
3116 /* Get the attributes desired and do our parameter checking */
3118 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3123 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3126 /* Get the vnode for the file whose attributes are being set. */
3127 nameiflags
= LOCKLEAF
;
3128 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3129 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3130 if (error
= namei(&nd
))
3133 /* Set up the UIO structure for use by the vfs routine */
3134 aiov
.iov_base
= uap
->attributeBuffer
;
3135 aiov
.iov_len
= uap
->bufferSize
;
3136 auio
.uio_iov
= &aiov
;
3137 auio
.uio_iovcnt
= 1;
3138 auio
.uio_offset
= 0;
3139 auio
.uio_rw
= UIO_WRITE
;
3140 auio
.uio_segflg
= UIO_USERSPACE
;
3142 auio
.uio_resid
= uap
->bufferSize
;
3144 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3150 } /* end of setattrlist system call */
3154 * Obtain attribute information on objects in a directory while enumerating
3155 * the directory. This call does not yet support union mounted directories.
3157 * 1.union mounted directories.
3160 struct getdirentriesattr_args
{
3161 int fd
; /* file descriptor */
3162 struct attrlist
*alist
; /* bit map of requested attributes */
3163 void *buffer
; /* buffer to hold returned attribute info */
3164 size_t buffersize
; /* size of the return buffer */
3165 u_long
*count
; /* the count of entries requested/returned */
3166 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3167 u_long
*newstate
; /* a flag to inform of changes in directory */
3168 u_long options
; /* maybe unused for now */
3172 getdirentriesattr (p
,uap
,retval
)
3174 register struct getdirentriesattr_args
*uap
;
3178 register struct vnode
*vp
;
3186 struct attrlist attributelist
;
3188 /* Get the attributes into kernel space */
3189 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3191 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3194 if (error
= getvnode(p
, uap
->fd
, &fp
))
3196 if ((fp
->f_flag
& FREAD
) == 0)
3198 vp
= (struct vnode
*)fp
->f_data
;
3200 if (vp
->v_type
!= VDIR
)
3203 /* set up the uio structure which will contain the users return buffer */
3204 aiov
.iov_base
= uap
->buffer
;
3205 aiov
.iov_len
= uap
->buffersize
;
3206 auio
.uio_iov
= &aiov
;
3207 auio
.uio_iovcnt
= 1;
3208 auio
.uio_rw
= UIO_READ
;
3209 auio
.uio_segflg
= UIO_USERSPACE
;
3211 auio
.uio_resid
= uap
->buffersize
;
3213 loff
= auio
.uio_offset
= fp
->f_offset
;
3214 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3215 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3216 actualcount
, uap
->options
, &newstate
, &eofflag
,
3217 &actualcount
, ((u_long
**)0), p
->p_cred
);
3219 VOP_UNLOCK(vp
, 0, p
);
3220 if (error
) return (error
);
3221 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3223 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3225 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3227 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3230 *retval
= eofflag
; /* similar to getdirentries */
3231 return (0); /* return error earlier, an retval of 0 or 1 now */
3233 } /* end of getdirentryattr system call */
3236 * Exchange data between two files
3239 struct exchangedata_args
{
3240 const char *path1
; /* pathname of the first swapee */
3241 const char *path2
; /* pathname of the second swapee */
3242 unsigned long options
; /* options */
3246 exchangedata (p
,uap
,retval
)
3248 register struct exchangedata_args
*uap
;
3253 struct nameidata fnd
, snd
;
3254 struct vnode
*fvp
, *svp
;
3259 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3261 /* Global lock, to prevent race condition, only one exchange at a time */
3262 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3264 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3266 if (error
= namei(&fnd
))
3271 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3273 if (error
= namei(&snd
)) {
3280 /* if the files are the same, return an inval error */
3288 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3289 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3291 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3292 if (error
) goto out
;
3294 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3295 if (error
) goto out
;
3297 /* Ok, make the call */
3298 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3305 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3313 } /* end of exchangedata system call */
3316 * Check users access to a file
3319 struct checkuseraccess_args
{
3320 const char *path
; /* pathname of the target file */
3321 uid_t userid
; /* user for whom we are checking access */
3322 gid_t
*groups
; /* Group that we are checking for */
3323 int ngroups
; /* Number of groups being checked */
3324 int accessrequired
; /* needed access to the file */
3325 unsigned long options
; /* options */
3330 checkuseraccess (p
,uap
,retval
)
3332 register struct checkuseraccess_args
*uap
;
3336 register struct vnode
*vp
;
3338 struct nameidata nd
;
3340 int flags
; /*what will actually get passed to access*/
3343 /* Make sure that the number of groups is correct before we do anything */
3345 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3348 /* Verify that the caller is root */
3350 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3353 /* Fill in the credential structure */
3356 cred
.cr_uid
= uap
->userid
;
3357 cred
.cr_ngroups
= uap
->ngroups
;
3358 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3361 /* Get our hands on the file */
3363 nameiflags
= LOCKLEAF
;
3364 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3365 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3367 if (error
= namei(&nd
))
3371 /* Flags == 0 means only check for existence. */
3375 if (uap
->accessrequired
) {
3376 if (uap
->accessrequired
& R_OK
)
3378 if (uap
->accessrequired
& W_OK
)
3380 if (uap
->accessrequired
& X_OK
)
3383 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3392 } /* end of checkuseraccess system call */
3395 struct searchfs_args
{
3397 struct fssearchblock
*searchblock
;
3401 struct searchstate
*state
;
3406 searchfs (p
,uap
,retval
)
3408 register struct searchfs_args
*uap
;
3412 register struct vnode
*vp
;
3415 struct nameidata nd
;
3416 struct fssearchblock searchblock
;
3417 struct searchstate
*state
;
3418 struct attrlist
*returnattrs
;
3419 void *searchparams1
,*searchparams2
;
3427 /* Start by copying in fsearchblock paramater list */
3429 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3432 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3433 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3434 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3437 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3438 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3440 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3442 /* Now set up the various pointers to the correct place in our newly allocated memory */
3444 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3445 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3446 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3448 /* Now copy in the stuff given our local variables. */
3450 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3453 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3456 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3459 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3462 /* set up the uio structure which will contain the users return buffer */
3464 aiov
.iov_base
= searchblock
.returnbuffer
;
3465 aiov
.iov_len
= searchblock
.returnbuffersize
;
3466 auio
.uio_iov
= &aiov
;
3467 auio
.uio_iovcnt
= 1;
3468 auio
.uio_rw
= UIO_READ
;
3469 auio
.uio_segflg
= UIO_USERSPACE
;
3471 auio
.uio_resid
= searchblock
.returnbuffersize
;
3473 nameiflags
= LOCKLEAF
;
3474 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3475 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3477 if (error
= namei(&nd
))
3484 * If searchblock.maxmatches == 0, then skip the search. This has happened
3485 * before and sometimes the underlyning code doesnt deal with it well.
3487 if (searchblock
.maxmatches
== 0) {
3493 Allright, we have everything we need, so lets make that call.
3495 We keep special track of the return value from the file system:
3496 EAGAIN is an acceptable error condition that shouldn't keep us
3497 from copying out any results...
3500 fserror
= VOP_SEARCHFS(vp
,
3503 &searchblock
.searchattrs
,
3504 searchblock
.maxmatches
,
3505 &searchblock
.timelimit
,
3517 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3518 search state. Everything was already put into he return buffer by the vop call. */
3520 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3523 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3530 FREE(searchparams1
,M_TEMP
);
3535 } /* end of searchfs system call */
3539 * Make a filesystem-specific control call:
3542 const char *path
; /* pathname of the target object */
3543 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3544 caddr_t data
; /* pointer to argument buffer */
3545 u_long options
; /* options for fsctl processing */
3549 fsctl (p
,uap
,retval
)
3551 struct fsctl_args
*uap
;
3556 struct nameidata nd
;
3558 u_long cmd
= uap
->cmd
;
3559 register u_int size
;
3560 #define STK_PARAMS 128
3561 char stkbuf
[STK_PARAMS
];
3564 size
= IOCPARM_LEN(cmd
);
3565 if (size
> IOCPARM_MAX
) return (EINVAL
);
3568 if (size
> sizeof (stkbuf
)) {
3569 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3577 error
= copyin(uap
->data
, data
, (u_int
)size
);
3578 if (error
) goto FSCtl_Exit
;
3580 *(caddr_t
*)data
= uap
->data
;
3582 } else if ((cmd
& IOC_OUT
) && size
) {
3584 * Zero the buffer so the user always
3585 * gets back something deterministic.
3588 } else if (cmd
& IOC_VOID
)
3589 *(caddr_t
*)data
= uap
->data
;
3591 /* Get the vnode for the file we are getting info on: */
3592 nameiflags
= LOCKLEAF
;
3593 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3594 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3595 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3597 /* Invoke the filesystem-specific code */
3598 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3603 * Copy any data to user, size was
3604 * already set and checked above.
3606 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3609 if (memp
) kfree(memp
, size
);
3613 /* end of fsctl system call */
3616 * An in-kernel sync for power management to call.
3618 __private_extern__
int
3621 boolean_t funnel_state
;
3624 struct sync_args data
;
3628 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3630 error
= sync(current_proc(), &data
, &retval
);
3632 thread_funnel_set(kernel_flock
, funnel_state
);
3635 } /* end of sync_internal call */