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
;
362 if (olddp
->v_usecount
== 1)
364 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
365 panic("mount: lost mount");
366 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
368 if (fdp
->fd_cdir
== olddp
) {
371 fdp
->fd_cdir
= newdp
;
374 if (fdp
->fd_rdir
== olddp
) {
377 fdp
->fd_rdir
= newdp
;
381 if (rootvnode
== olddp
) {
391 * Unmount a file system.
393 * Note: unmount takes a path to the vnode mounted on as argument,
394 * not special file (as before).
396 struct unmount_args
{
402 unmount(p
, uap
, retval
)
404 register struct unmount_args
*uap
;
407 register struct vnode
*vp
;
412 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
414 if (error
= namei(&nd
))
420 * Only root, or the user that did the original mount is
421 * permitted to unmount this filesystem.
423 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
424 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
430 * Don't allow unmounting the root file system.
432 if (mp
->mnt_flag
& MNT_ROOTFS
) {
434 return (EBUSY
); /* the root is always busy */
438 * Must be the root of the filesystem
440 if ((vp
->v_flag
& VROOT
) == 0) {
445 return (dounmount(mp
, uap
->flags
, p
));
449 * Do the actual file system unmount.
452 dounmount(mp
, flags
, p
)
453 register struct mount
*mp
;
457 struct vnode
*coveredvp
;
460 simple_lock(&mountlist_slock
);
461 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
462 lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
, &mountlist_slock
, p
);
463 mp
->mnt_flag
&=~ MNT_ASYNC
;
464 ubc_umount(mp
); /* release cached vnodes */
465 cache_purgevfs(mp
); /* remove cache entries for this file sys */
466 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
467 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
469 error
= VFS_UNMOUNT(mp
, flags
, p
);
470 simple_lock(&mountlist_slock
);
472 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
473 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
474 &mountlist_slock
, p
);
478 /* increment the operations count */
481 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
482 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
483 coveredvp
->v_mountedhere
= (struct mount
*)0;
484 simple_unlock(&mountlist_slock
);
486 simple_lock(&mountlist_slock
);
488 mp
->mnt_vfc
->vfc_refcount
--;
489 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
490 panic("unmount: dangling vnode");
492 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
494 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
497 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
502 * Sync each mounted filesystem.
506 struct ctldebug debug0
= { "syncprt", &syncprt
};
512 int print_vmpage_stat
=0;
518 struct sync_args
*uap
;
521 register struct mount
*mp
, *nmp
;
524 simple_lock(&mountlist_slock
);
525 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
526 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
527 nmp
= mp
->mnt_list
.cqe_next
;
530 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
531 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
532 mp
->mnt_flag
&= ~MNT_ASYNC
;
533 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
535 mp
->mnt_flag
|= MNT_ASYNC
;
537 simple_lock(&mountlist_slock
);
538 nmp
= mp
->mnt_list
.cqe_next
;
541 simple_unlock(&mountlist_slock
);
544 extern void vm_countdirtypages(void);
545 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
546 extern unsigned int dp_pgins
, dp_pgouts
;
547 if(print_vmpage_stat
) {
548 vm_countdirtypages();
549 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
550 dp_pgins
, dp_pgouts
);
556 #endif /* DIAGNOSTIC */
561 * Change filesystem quotas.
563 struct quotactl_args
{
571 quotactl(p
, uap
, retval
)
573 register struct quotactl_args
*uap
;
576 register struct mount
*mp
;
580 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
581 if (error
= namei(&nd
))
583 mp
= nd
.ni_vp
->v_mount
;
585 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
590 * Get filesystem statistics.
598 statfs(p
, uap
, retval
)
600 register struct statfs_args
*uap
;
603 register struct mount
*mp
;
604 register struct statfs
*sp
;
608 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
609 if (error
= namei(&nd
))
611 mp
= nd
.ni_vp
->v_mount
;
614 if (error
= VFS_STATFS(mp
, sp
, p
))
616 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
617 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
618 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
622 * Get filesystem statistics.
624 struct fstatfs_args
{
630 fstatfs(p
, uap
, retval
)
632 register struct fstatfs_args
*uap
;
637 register struct statfs
*sp
;
640 if (error
= getvnode(p
, uap
->fd
, &fp
))
642 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
646 if (error
= VFS_STATFS(mp
, sp
, p
))
648 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
649 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
650 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
654 * Get statistics on all filesystems.
656 struct getfsstat_args
{
662 getfsstat(p
, uap
, retval
)
664 register struct getfsstat_args
*uap
;
667 register struct mount
*mp
, *nmp
;
668 register struct statfs
*sp
;
670 long count
, maxcount
, error
;
672 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
673 sfsp
= (caddr_t
)uap
->buf
;
675 simple_lock(&mountlist_slock
);
676 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
677 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
678 nmp
= mp
->mnt_list
.cqe_next
;
681 if (sfsp
&& count
< maxcount
) {
684 * If MNT_NOWAIT is specified, do not refresh the
685 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
687 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
688 (uap
->flags
& MNT_WAIT
)) &&
689 (error
= VFS_STATFS(mp
, sp
, p
))) {
690 simple_lock(&mountlist_slock
);
691 nmp
= mp
->mnt_list
.cqe_next
;
695 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
696 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
701 simple_lock(&mountlist_slock
);
702 nmp
= mp
->mnt_list
.cqe_next
;
705 simple_unlock(&mountlist_slock
);
706 if (sfsp
&& count
> maxcount
)
714 ogetfsstat(p
, uap
, retval
)
716 register struct getfsstat_args
*uap
;
719 register struct mount
*mp
, *nmp
;
720 register struct statfs
*sp
;
722 long count
, maxcount
, error
;
724 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
725 sfsp
= (caddr_t
)uap
->buf
;
727 simple_lock(&mountlist_slock
);
728 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
729 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
730 nmp
= mp
->mnt_list
.cqe_next
;
733 if (sfsp
&& count
< maxcount
) {
736 * If MNT_NOWAIT is specified, do not refresh the
737 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
739 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
740 (uap
->flags
& MNT_WAIT
)) &&
741 (error
= VFS_STATFS(mp
, sp
, p
))) {
742 simple_lock(&mountlist_slock
);
743 nmp
= mp
->mnt_list
.cqe_next
;
747 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
748 error
= copyout((caddr_t
)sp
, sfsp
,
749 sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
));
752 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
755 simple_lock(&mountlist_slock
);
756 nmp
= mp
->mnt_list
.cqe_next
;
759 simple_unlock(&mountlist_slock
);
760 if (sfsp
&& count
> maxcount
)
769 * Change current working directory to a given file descriptor.
776 fchdir(p
, uap
, retval
)
778 struct fchdir_args
*uap
;
781 register struct filedesc
*fdp
= p
->p_fd
;
782 struct vnode
*vp
, *tdp
, *tvp
;
787 if (error
= getvnode(p
, uap
->fd
, &fp
))
789 vp
= (struct vnode
*)fp
->f_data
;
791 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
792 if (vp
->v_type
!= VDIR
)
795 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
796 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
797 if (vfs_busy(mp
, 0, 0, p
))
799 error
= VFS_ROOT(mp
, &tdp
);
810 VOP_UNLOCK(vp
, 0, p
);
818 * Change current working directory (``.'').
825 chdir(p
, uap
, retval
)
827 struct chdir_args
*uap
;
830 register struct filedesc
*fdp
= p
->p_fd
;
835 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
837 if (error
= change_dir(&nd
, p
))
840 fdp
->fd_cdir
= nd
.ni_vp
;
846 * Change notion of root (``/'') directory.
853 chroot(p
, uap
, retval
)
855 struct chroot_args
*uap
;
858 register struct filedesc
*fdp
= p
->p_fd
;
863 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
866 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
868 if (error
= change_dir(&nd
, p
))
871 if(error
= clone_system_shared_regions()) {
877 fdp
->fd_rdir
= nd
.ni_vp
;
884 * Common routine for chroot and chdir.
888 register struct nameidata
*ndp
;
894 if (error
= namei(ndp
))
897 if (vp
->v_type
!= VDIR
)
900 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
904 VOP_UNLOCK(vp
, 0, p
);
909 * Check permissions, allocate an open file structure,
910 * and call the device open routine if any.
920 register struct open_args
*uap
;
923 register struct filedesc
*fdp
= p
->p_fd
;
924 register struct file
*fp
;
925 register struct vnode
*vp
;
926 int flags
, cmode
, oflags
;
928 int type
, indx
, error
;
931 extern struct fileops vnops
;
934 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
936 flags
= FFLAGS(uap
->flags
);
937 if (error
= falloc(p
, &nfp
, &indx
))
940 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
941 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
942 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
943 if (error
= vn_open(&nd
, flags
, cmode
)) {
945 if ((error
== ENODEV
|| error
== ENXIO
) &&
946 p
->p_dupfd
>= 0 && /* XXX from fdopen */
948 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
952 if (error
== ERESTART
)
959 fp
->f_flag
= flags
& FMASK
;
960 fp
->f_type
= DTYPE_VNODE
;
962 fp
->f_data
= (caddr_t
)vp
;
963 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
964 lf
.l_whence
= SEEK_SET
;
967 if (flags
& O_EXLOCK
)
972 if ((flags
& FNONBLOCK
) == 0)
974 VOP_UNLOCK(vp
, 0, p
);
975 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
976 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
981 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
982 fp
->f_flag
|= FHASLOCK
;
984 VOP_UNLOCK(vp
, 0, p
);
985 *fdflags(p
, indx
) &= ~UF_RESERVED
;
999 ocreat(p
, uap
, retval
)
1001 register struct ocreat_args
*uap
;
1004 struct open_args nuap
;
1006 nuap
.path
= uap
->path
;
1007 nuap
.mode
= uap
->mode
;
1008 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1009 return (open(p
, &nuap
, retval
));
1011 #endif /* COMPAT_43 */
1014 * Create a special file.
1023 mknod(p
, uap
, retval
)
1025 register struct mknod_args
*uap
;
1028 register struct vnode
*vp
;
1032 struct nameidata nd
;
1034 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1036 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1037 if (error
= namei(&nd
))
1044 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1045 vattr
.va_rdev
= uap
->dev
;
1048 switch (uap
->mode
& S_IFMT
) {
1049 case S_IFMT
: /* used by badsect to flag bad sectors */
1050 vattr
.va_type
= VBAD
;
1053 vattr
.va_type
= VCHR
;
1056 vattr
.va_type
= VBLK
;
1067 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1069 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1071 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1074 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1075 &nd
.ni_cnd
, &vattr
);
1078 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1079 if (nd
.ni_dvp
== vp
)
1090 * Create a named pipe.
1092 struct mkfifo_args
{
1098 mkfifo(p
, uap
, retval
)
1100 register struct mkfifo_args
*uap
;
1105 struct nameidata nd
;
1108 return (EOPNOTSUPP
);
1110 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1111 if (error
= namei(&nd
))
1113 if (nd
.ni_vp
!= NULL
) {
1114 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1115 if (nd
.ni_dvp
== nd
.ni_vp
)
1123 vattr
.va_type
= VFIFO
;
1124 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1125 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1126 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1131 * Make a hard file link.
1139 link(p
, uap
, retval
)
1141 register struct link_args
*uap
;
1144 register struct vnode
*vp
;
1145 struct nameidata nd
;
1148 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1149 if (error
= namei(&nd
))
1152 if (vp
->v_type
== VDIR
)
1153 error
= EPERM
; /* POSIX */
1155 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1156 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1157 nd
.ni_dirp
= uap
->link
;
1158 if ((error
= namei(&nd
)) == 0) {
1159 if (nd
.ni_vp
!= NULL
)
1162 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1164 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1165 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1167 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1168 if (nd
.ni_dvp
== nd
.ni_vp
)
1182 * Make a symbolic link.
1184 struct symlink_args
{
1190 symlink(p
, uap
, retval
)
1192 register struct symlink_args
*uap
;
1198 struct nameidata nd
;
1200 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1201 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1203 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1204 if (error
= namei(&nd
))
1207 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1208 if (nd
.ni_dvp
== nd
.ni_vp
)
1217 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1218 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1219 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1221 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1226 * Delete a whiteout from the filesystem.
1228 struct undelete_args
{
1233 undelete(p
, uap
, retval
)
1235 register struct undelete_args
*uap
;
1239 struct nameidata nd
;
1241 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1247 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1248 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1249 if (nd
.ni_dvp
== nd
.ni_vp
)
1258 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1259 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1260 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1266 * Delete a name from the filesystem.
1268 struct unlink_args
{
1273 _unlink(p
, uap
, retval
, nodelbusy
)
1275 struct unlink_args
*uap
;
1279 register struct vnode
*vp
;
1281 struct nameidata nd
;
1283 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1284 /* with Carbon semantics, busy files cannot be deleted */
1286 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1287 if (error
= namei(&nd
))
1290 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1291 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1293 if (vp
->v_type
== VDIR
)
1294 error
= EPERM
; /* POSIX */
1297 * The root of a mounted filesystem cannot be deleted.
1299 * XXX: can this only be a VDIR case?
1301 if (vp
->v_flag
& VROOT
)
1306 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1307 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1309 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1310 if (nd
.ni_dvp
== vp
)
1321 * Delete a name from the filesystem using POSIX semantics.
1324 unlink(p
, uap
, retval
)
1326 struct unlink_args
*uap
;
1329 return _unlink(p
, uap
, retval
, 0);
1333 * Delete a name from the filesystem using Carbon semantics.
1336 delete(p
, uap
, retval
)
1338 struct unlink_args
*uap
;
1341 return _unlink(p
, uap
, retval
, 1);
1345 * Reposition read/write file offset.
1349 #ifdef DOUBLE_ALIGN_PARAMS
1356 lseek(p
, uap
, retval
)
1358 register struct lseek_args
*uap
;
1361 struct ucred
*cred
= p
->p_ucred
;
1366 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1368 if (fp
->f_type
!= DTYPE_VNODE
)
1370 switch (uap
->whence
) {
1372 fp
->f_offset
+= uap
->offset
;
1376 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1378 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1381 fp
->f_offset
= uap
->offset
;
1386 *(off_t
*)retval
= fp
->f_offset
;
1392 * Reposition read/write file offset.
1394 struct olseek_args
{
1400 olseek(p
, uap
, retval
)
1402 register struct olseek_args
*uap
;
1405 struct lseek_args
/* {
1407 #ifdef DOUBLE_ALIGN_PARAMS
1408 syscallarg(int) pad;
1410 syscallarg(off_t) offset;
1411 syscallarg(int) whence;
1417 nuap
.offset
= uap
->offset
;
1418 nuap
.whence
= uap
->whence
;
1419 error
= lseek(p
, &nuap
, &qret
);
1420 *(long *)retval
= qret
;
1423 #endif /* COMPAT_43 */
1426 * Check access permissions.
1428 struct access_args
{
1433 access(p
, uap
, retval
)
1435 register struct access_args
*uap
;
1438 register struct ucred
*cred
= p
->p_ucred
;
1439 register struct vnode
*vp
;
1440 int error
, flags
, t_gid
, t_uid
;
1441 struct nameidata nd
;
1443 t_uid
= cred
->cr_uid
;
1444 t_gid
= cred
->cr_groups
[0];
1445 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1446 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1447 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1449 if (error
= namei(&nd
))
1453 /* Flags == 0 means only check for existence. */
1456 if (uap
->flags
& R_OK
)
1458 if (uap
->flags
& W_OK
)
1460 if (uap
->flags
& X_OK
)
1462 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1463 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1467 cred
->cr_uid
= t_uid
;
1468 cred
->cr_groups
[0] = t_gid
;
1474 * Get file status; this version follows links.
1482 ostat(p
, uap
, retval
)
1484 register struct ostat_args
*uap
;
1490 struct nameidata nd
;
1492 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1494 if (error
= namei(&nd
))
1496 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1501 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1506 * Get file status; this version does not follow links.
1508 struct olstat_args
{
1514 olstat(p
, uap
, retval
)
1516 register struct olstat_args
*uap
;
1519 struct vnode
*vp
, *dvp
;
1520 struct stat sb
, sb1
;
1523 struct nameidata nd
;
1525 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1527 if (error
= namei(&nd
))
1530 * For symbolic links, always return the attributes of its
1531 * containing directory, except for mode, size, and links.
1535 if (vp
->v_type
!= VLNK
) {
1540 error
= vn_stat(vp
, &sb
, p
);
1545 error
= vn_stat(dvp
, &sb
, p
);
1551 error
= vn_stat(vp
, &sb1
, p
);
1555 sb
.st_mode
&= ~S_IFDIR
;
1556 sb
.st_mode
|= S_IFLNK
;
1557 sb
.st_nlink
= sb1
.st_nlink
;
1558 sb
.st_size
= sb1
.st_size
;
1559 sb
.st_blocks
= sb1
.st_blocks
;
1562 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1567 * Convert from an old to a new stat structure.
1575 ost
->st_dev
= st
->st_dev
;
1576 ost
->st_ino
= st
->st_ino
;
1577 ost
->st_mode
= st
->st_mode
;
1578 ost
->st_nlink
= st
->st_nlink
;
1579 ost
->st_uid
= st
->st_uid
;
1580 ost
->st_gid
= st
->st_gid
;
1581 ost
->st_rdev
= st
->st_rdev
;
1582 if (st
->st_size
< (quad_t
)1 << 32)
1583 ost
->st_size
= st
->st_size
;
1586 ost
->st_atime
= st
->st_atime
;
1587 ost
->st_mtime
= st
->st_mtime
;
1588 ost
->st_ctime
= st
->st_ctime
;
1589 ost
->st_blksize
= st
->st_blksize
;
1590 ost
->st_blocks
= st
->st_blocks
;
1591 ost
->st_flags
= st
->st_flags
;
1592 ost
->st_gen
= st
->st_gen
;
1594 #endif /* COMPAT_43 */
1597 * Get file status; this version follows links.
1605 stat(p
, uap
, retval
)
1607 register struct stat_args
*uap
;
1612 struct nameidata nd
;
1614 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1616 if (error
= namei(&nd
))
1618 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1622 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1627 * Get file status; this version does not follow links.
1635 lstat(p
, uap
, retval
)
1637 register struct lstat_args
*uap
;
1641 struct vnode
*vp
, *dvp
;
1642 struct stat sb
, sb1
;
1643 struct nameidata nd
;
1645 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1647 if (error
= namei(&nd
))
1650 * For symbolic links, always return the attributes of its containing
1651 * directory, except for mode, size, inode number, and links.
1655 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1660 error
= vn_stat(vp
, &sb
, p
);
1664 if (vp
->v_type
== VLNK
)
1665 sb
.st_mode
|= S_IFLNK
;
1667 error
= vn_stat(dvp
, &sb
, p
);
1673 error
= vn_stat(vp
, &sb1
, p
);
1677 sb
.st_mode
&= ~S_IFDIR
;
1678 sb
.st_mode
|= S_IFLNK
;
1679 sb
.st_nlink
= sb1
.st_nlink
;
1680 sb
.st_size
= sb1
.st_size
;
1681 sb
.st_blocks
= sb1
.st_blocks
;
1682 sb
.st_ino
= sb1
.st_ino
;
1684 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1689 * Get configurable pathname variables.
1691 struct pathconf_args
{
1697 pathconf(p
, uap
, retval
)
1699 register struct pathconf_args
*uap
;
1703 struct nameidata nd
;
1705 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1707 if (error
= namei(&nd
))
1709 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1715 * Return target name of a symbolic link.
1717 struct readlink_args
{
1724 readlink(p
, uap
, retval
)
1726 register struct readlink_args
*uap
;
1729 register struct vnode
*vp
;
1733 struct nameidata nd
;
1735 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1737 if (error
= namei(&nd
))
1740 if (vp
->v_type
!= VLNK
)
1743 aiov
.iov_base
= uap
->buf
;
1744 aiov
.iov_len
= uap
->count
;
1745 auio
.uio_iov
= &aiov
;
1746 auio
.uio_iovcnt
= 1;
1747 auio
.uio_offset
= 0;
1748 auio
.uio_rw
= UIO_READ
;
1749 auio
.uio_segflg
= UIO_USERSPACE
;
1751 auio
.uio_resid
= uap
->count
;
1752 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1755 *retval
= uap
->count
- auio
.uio_resid
;
1760 * Change flags of a file given a path name.
1762 struct chflags_args
{
1768 chflags(p
, uap
, retval
)
1770 register struct chflags_args
*uap
;
1773 register struct vnode
*vp
;
1776 struct nameidata nd
;
1778 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1779 if (error
= namei(&nd
))
1782 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1783 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1785 vattr
.va_flags
= uap
->flags
;
1786 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1792 * Change flags of a file given a file descriptor.
1794 struct fchflags_args
{
1800 fchflags(p
, uap
, retval
)
1802 register struct fchflags_args
*uap
;
1810 if (error
= getvnode(p
, uap
->fd
, &fp
))
1812 vp
= (struct vnode
*)fp
->f_data
;
1813 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1814 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1816 vattr
.va_flags
= uap
->flags
;
1817 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1818 VOP_UNLOCK(vp
, 0, p
);
1823 * Change mode of a file given path name.
1831 chmod(p
, uap
, retval
)
1833 register struct chmod_args
*uap
;
1836 register struct vnode
*vp
;
1839 struct nameidata nd
;
1841 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1842 if (error
= namei(&nd
))
1845 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1846 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1848 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1849 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1855 * Change mode of a file given a file descriptor.
1857 struct fchmod_args
{
1863 fchmod(p
, uap
, retval
)
1865 register struct fchmod_args
*uap
;
1873 if (error
= getvnode(p
, uap
->fd
, &fp
))
1875 vp
= (struct vnode
*)fp
->f_data
;
1876 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1877 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1879 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1880 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1881 VOP_UNLOCK(vp
, 0, p
);
1886 * Set ownership given a path name.
1895 chown(p
, uap
, retval
)
1897 register struct chown_args
*uap
;
1900 register struct vnode
*vp
;
1903 struct nameidata nd
;
1905 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1906 if (error
= namei(&nd
))
1911 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
1912 * by looking for chown() calls on /dev/console from a console process.
1914 if ((vp
) && (vp
->v_specinfo
) &&
1915 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
1916 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
1917 console_user
= uap
->uid
;
1920 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1921 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1923 vattr
.va_uid
= uap
->uid
;
1924 vattr
.va_gid
= uap
->gid
;
1925 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1931 * Set ownership given a file descriptor.
1933 struct fchown_args
{
1940 fchown(p
, uap
, retval
)
1942 register struct fchown_args
*uap
;
1950 if (error
= getvnode(p
, uap
->fd
, &fp
))
1952 vp
= (struct vnode
*)fp
->f_data
;
1953 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1954 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1956 vattr
.va_uid
= uap
->uid
;
1957 vattr
.va_gid
= uap
->gid
;
1958 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1959 VOP_UNLOCK(vp
, 0, p
);
1964 * Set the access and modification times of a file.
1966 struct utimes_args
{
1968 struct timeval
*tptr
;
1972 utimes(p
, uap
, retval
)
1974 register struct utimes_args
*uap
;
1977 register struct vnode
*vp
;
1978 struct timeval tv
[2];
1981 struct nameidata nd
;
1984 if (uap
->tptr
== NULL
) {
1987 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
1988 } else if (error
= copyin((caddr_t
)uap
->tptr
, (caddr_t
)tv
,
1991 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1992 if (error
= namei(&nd
))
1995 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1996 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1997 vattr
.va_atime
.tv_sec
= tv
[0].tv_sec
;
1998 vattr
.va_atime
.tv_nsec
= tv
[0].tv_usec
* 1000;
1999 vattr
.va_mtime
.tv_sec
= tv
[1].tv_sec
;
2000 vattr
.va_mtime
.tv_nsec
= tv
[1].tv_usec
* 1000;
2001 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2007 * Truncate a file given its path name.
2009 struct truncate_args
{
2011 #ifdef DOUBLE_ALIGN_PARAMS
2018 truncate(p
, uap
, retval
)
2020 register struct truncate_args
*uap
;
2023 register struct vnode
*vp
;
2026 struct nameidata nd
;
2028 if (uap
->length
< 0)
2030 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2031 if (error
= namei(&nd
))
2034 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2035 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2036 if (vp
->v_type
== VDIR
)
2038 else if ((error
= vn_writechk(vp
)) == 0 &&
2039 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2041 vattr
.va_size
= uap
->length
;
2042 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2049 * Truncate a file given a file descriptor.
2051 struct ftruncate_args
{
2053 #ifdef DOUBLE_ALIGN_PARAMS
2060 ftruncate(p
, uap
, retval
)
2062 register struct ftruncate_args
*uap
;
2070 if (uap
->length
< 0)
2073 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2076 if (fp
->f_type
== DTYPE_PSXSHM
) {
2077 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2079 if (fp
->f_type
!= DTYPE_VNODE
)
2082 if ((fp
->f_flag
& FWRITE
) == 0)
2084 vp
= (struct vnode
*)fp
->f_data
;
2085 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2086 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2087 if (vp
->v_type
== VDIR
)
2089 else if ((error
= vn_writechk(vp
)) == 0) {
2091 vattr
.va_size
= uap
->length
;
2092 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2094 VOP_UNLOCK(vp
, 0, p
);
2100 * Truncate a file given its path name.
2102 struct otruncate_args
{
2108 otruncate(p
, uap
, retval
)
2110 register struct otruncate_args
*uap
;
2113 struct truncate_args
/* {
2114 syscallarg(char *) path;
2115 #ifdef DOUBLE_ALIGN_PARAMS
2116 syscallarg(int) pad;
2118 syscallarg(off_t) length;
2121 nuap
.path
= uap
->path
;
2122 nuap
.length
= uap
->length
;
2123 return (truncate(p
, &nuap
, retval
));
2127 * Truncate a file given a file descriptor.
2129 struct oftruncate_args
{
2135 oftruncate(p
, uap
, retval
)
2137 register struct oftruncate_args
*uap
;
2140 struct ftruncate_args
/* {
2142 #ifdef DOUBLE_ALIGN_PARAMS
2143 syscallarg(int) pad;
2145 syscallarg(off_t) length;
2149 nuap
.length
= uap
->length
;
2150 return (ftruncate(p
, &nuap
, retval
));
2152 #endif /* COMPAT_43 */
2155 * Sync an open file.
2162 fsync(p
, uap
, retval
)
2164 struct fsync_args
*uap
;
2167 register struct vnode
*vp
;
2171 if (error
= getvnode(p
, uap
->fd
, &fp
))
2173 vp
= (struct vnode
*)fp
->f_data
;
2174 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2175 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2176 VOP_UNLOCK(vp
, 0, p
);
2181 * Duplicate files. Source must be a file, target must be a file or
2185 struct copyfile_args
{
2193 copyfile(p
, uap
, retval
)
2195 register struct copyfile_args
*uap
;
2198 register struct vnode
*tvp
, *fvp
, *tdvp
;
2199 register struct ucred
*cred
= p
->p_ucred
;
2200 struct nameidata fromnd
, tond
;
2203 /* Check that the flags are valid.
2206 if (uap
->flags
& ~CPF_MASK
) {
2210 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2212 if (error
= namei(&fromnd
))
2216 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2217 UIO_USERSPACE
, uap
->to
, p
);
2218 if (error
= namei(&tond
)) {
2225 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2231 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2236 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2242 * If source is the same as the destination (that is the
2243 * same inode number) then there is nothing to do.
2244 * (fixed to have POSIX semantics - CSM 3/2/98)
2250 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2252 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2261 vrele(tond
.ni_startdir
);
2262 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2264 if (fromnd
.ni_startdir
)
2265 vrele(fromnd
.ni_startdir
);
2266 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2273 * Rename files. Source and destination must either both be directories,
2274 * or both not be directories. If target is a directory, it must be empty.
2276 struct rename_args
{
2282 rename(p
, uap
, retval
)
2284 register struct rename_args
*uap
;
2287 register struct vnode
*tvp
, *fvp
, *tdvp
;
2288 struct nameidata fromnd
, tond
;
2291 int casesense
,casepres
;
2295 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2297 if (error
= namei(&fromnd
))
2301 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2302 UIO_USERSPACE
, uap
->to
, p
);
2303 if (error
= namei(&tond
)) {
2304 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2305 vrele(fromnd
.ni_dvp
);
2313 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2316 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2324 * If source is the same as the destination (that is the
2325 * same inode number) then there is nothing to do...
2327 * underlyning file system supports case insensitivity and is case preserving. Then
2328 * a special case is made, i.e. foo -> Foo.
2330 * Only file systems that support the pathconf selectors _PC_CASE_SENSITIVE and
2331 * _PC_CASE_PRESERVING can have this exception, and then they would need to
2332 * handle the special case of getting the same vnode as target and source.
2333 * NOTE: Then the target is unlocked going into VOP_RENAME, so not to cause
2334 * locking problems. There is a single reference on tvp.
2339 * Check to see if just changing case, if:
2340 * - file system is case insensitive
2341 * - and also case preserving
2342 * _ same parent directories (so changing case by different links is not supported)
2343 * For instance: mv a/foo a/Foo
2345 if ((tond
.ni_dvp
== fromnd
.ni_dvp
) &&
2346 (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
) == 0) &&
2347 (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
) == 0) &&
2350 /* Since the target is locked...unlock it and lose a ref */
2357 * Allow the renaming of mount points.
2358 * - target must not exist
2359 * - target must reside in the same directory as source
2360 * - union mounts cannot be renamed
2361 * - "/" cannot be renamed
2363 if ((fvp
->v_flag
& VROOT
) &&
2364 (fvp
->v_type
== VDIR
) &&
2366 (fvp
->v_mountedhere
== NULL
) &&
2367 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2368 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2369 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2371 /* switch fvp to the covered vnode */
2372 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2380 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2381 if (fromnd
.ni_dvp
!= tdvp
)
2382 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2384 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2385 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2386 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2391 * update filesystem's mount point data
2394 char *cp
, *pathend
, *mpname
;
2401 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2402 mp
= fvp
->v_mountedhere
;
2404 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2409 VOP_UNLOCK(fvp
, 0, p
);
2411 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2412 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2414 /* find current mount point prefix */
2415 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2416 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2420 /* find last component of target name */
2421 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2425 /* append name to prefix */
2426 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2427 bzero(pathend
, maxlen
);
2428 strncpy(pathend
, mpname
, maxlen
- 1);
2430 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2436 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2443 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2444 vrele(fromnd
.ni_dvp
);
2448 vrele(tond
.ni_startdir
);
2449 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2451 if (fromnd
.ni_startdir
)
2452 vrele(fromnd
.ni_startdir
);
2453 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2460 * Make a directory file.
2468 mkdir(p
, uap
, retval
)
2470 register struct mkdir_args
*uap
;
2473 register struct vnode
*vp
;
2476 struct nameidata nd
;
2478 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2479 if (error
= namei(&nd
))
2483 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2484 if (nd
.ni_dvp
== vp
)
2492 vattr
.va_type
= VDIR
;
2493 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2494 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2495 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2502 * Remove a directory file.
2509 rmdir(p
, uap
, retval
)
2511 struct rmdir_args
*uap
;
2514 register struct vnode
*vp
;
2516 struct nameidata nd
;
2518 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2520 if (error
= namei(&nd
))
2523 if (vp
->v_type
!= VDIR
) {
2528 * No rmdir "." please.
2530 if (nd
.ni_dvp
== vp
) {
2535 * The root of a mounted filesystem cannot be deleted.
2537 if (vp
->v_flag
& VROOT
)
2541 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2542 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2543 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2545 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2546 if (nd
.ni_dvp
== vp
)
2557 * Read a block of directory entries in a file system independent format.
2559 struct ogetdirentries_args
{
2566 ogetdirentries(p
, uap
, retval
)
2568 register struct ogetdirentries_args
*uap
;
2571 register struct vnode
*vp
;
2573 struct uio auio
, kuio
;
2574 struct iovec aiov
, kiov
;
2575 struct dirent
*dp
, *edp
;
2577 int error
, eofflag
, readcnt
;
2580 if (error
= getvnode(p
, uap
->fd
, &fp
))
2582 if ((fp
->f_flag
& FREAD
) == 0)
2584 vp
= (struct vnode
*)fp
->f_data
;
2586 if (vp
->v_type
!= VDIR
)
2588 aiov
.iov_base
= uap
->buf
;
2589 aiov
.iov_len
= uap
->count
;
2590 auio
.uio_iov
= &aiov
;
2591 auio
.uio_iovcnt
= 1;
2592 auio
.uio_rw
= UIO_READ
;
2593 auio
.uio_segflg
= UIO_USERSPACE
;
2595 auio
.uio_resid
= uap
->count
;
2596 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2597 loff
= auio
.uio_offset
= fp
->f_offset
;
2598 # if (BYTE_ORDER != LITTLE_ENDIAN)
2599 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2600 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2601 (int *)0, (u_long
*)0);
2602 fp
->f_offset
= auio
.uio_offset
;
2607 kuio
.uio_iov
= &kiov
;
2608 kuio
.uio_segflg
= UIO_SYSSPACE
;
2609 kiov
.iov_len
= uap
->count
;
2610 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2611 kiov
.iov_base
= dirbuf
;
2612 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2613 (int *)0, (u_long
*)0);
2614 fp
->f_offset
= kuio
.uio_offset
;
2616 readcnt
= uap
->count
- kuio
.uio_resid
;
2617 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2618 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2619 # if (BYTE_ORDER == LITTLE_ENDIAN)
2621 * The expected low byte of
2622 * dp->d_namlen is our dp->d_type.
2623 * The high MBZ byte of dp->d_namlen
2624 * is our dp->d_namlen.
2626 dp
->d_type
= dp
->d_namlen
;
2630 * The dp->d_type is the high byte
2631 * of the expected dp->d_namlen,
2632 * so must be zero'ed.
2636 if (dp
->d_reclen
> 0) {
2637 dp
= (struct dirent
*)
2638 ((char *)dp
+ dp
->d_reclen
);
2645 error
= uiomove(dirbuf
, readcnt
, &auio
);
2647 FREE(dirbuf
, M_TEMP
);
2649 VOP_UNLOCK(vp
, 0, p
);
2655 extern int (**union_vnodeop_p
)(void *);
2656 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2658 if ((uap
->count
== auio
.uio_resid
) &&
2659 (vp
->v_op
== union_vnodeop_p
)) {
2662 lvp
= union_dircache(vp
, p
);
2663 if (lvp
!= NULLVP
) {
2667 * If the directory is opaque,
2668 * then don't show lower entries
2670 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2671 if (va
.va_flags
& OPAQUE
) {
2677 if (lvp
!= NULLVP
) {
2678 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2683 VOP_UNLOCK(lvp
, 0, p
);
2684 fp
->f_data
= (caddr_t
) lvp
;
2686 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2697 if ((uap
->count
== auio
.uio_resid
) &&
2698 (vp
->v_flag
& VROOT
) &&
2699 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2700 struct vnode
*tvp
= vp
;
2701 vp
= vp
->v_mount
->mnt_vnodecovered
;
2703 fp
->f_data
= (caddr_t
) vp
;
2708 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2710 *retval
= uap
->count
- auio
.uio_resid
;
2713 #endif /* COMPAT_43 */
2716 * Read a block of directory entries in a file system independent format.
2718 struct getdirentries_args
{
2725 getdirentries(p
, uap
, retval
)
2727 register struct getdirentries_args
*uap
;
2730 register struct vnode
*vp
;
2737 if (error
= getvnode(p
, uap
->fd
, &fp
))
2739 if ((fp
->f_flag
& FREAD
) == 0)
2741 vp
= (struct vnode
*)fp
->f_data
;
2743 if (vp
->v_type
!= VDIR
)
2745 aiov
.iov_base
= uap
->buf
;
2746 aiov
.iov_len
= uap
->count
;
2747 auio
.uio_iov
= &aiov
;
2748 auio
.uio_iovcnt
= 1;
2749 auio
.uio_rw
= UIO_READ
;
2750 auio
.uio_segflg
= UIO_USERSPACE
;
2752 auio
.uio_resid
= uap
->count
;
2753 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2754 loff
= auio
.uio_offset
= fp
->f_offset
;
2755 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2756 (int *)0, (u_long
*)0);
2757 fp
->f_offset
= auio
.uio_offset
;
2758 VOP_UNLOCK(vp
, 0, p
);
2764 extern int (**union_vnodeop_p
)(void *);
2765 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2767 if ((uap
->count
== auio
.uio_resid
) &&
2768 (vp
->v_op
== union_vnodeop_p
)) {
2771 lvp
= union_dircache(vp
, p
);
2772 if (lvp
!= NULLVP
) {
2776 * If the directory is opaque,
2777 * then don't show lower entries
2779 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2780 if (va
.va_flags
& OPAQUE
) {
2786 if (lvp
!= NULLVP
) {
2787 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2792 VOP_UNLOCK(lvp
, 0, p
);
2793 fp
->f_data
= (caddr_t
) lvp
;
2795 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2806 if ((uap
->count
== auio
.uio_resid
) &&
2807 (vp
->v_flag
& VROOT
) &&
2808 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2809 struct vnode
*tvp
= vp
;
2810 vp
= vp
->v_mount
->mnt_vnodecovered
;
2812 fp
->f_data
= (caddr_t
) vp
;
2817 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2819 *retval
= uap
->count
- auio
.uio_resid
;
2824 * Set the mode mask for creation of filesystem nodes.
2830 umask(p
, uap
, retval
)
2832 struct umask_args
*uap
;
2835 register struct filedesc
*fdp
;
2838 *retval
= fdp
->fd_cmask
;
2839 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
2844 * Void all references to file by ripping underlying filesystem
2847 struct revoke_args
{
2852 revoke(p
, uap
, retval
)
2854 register struct revoke_args
*uap
;
2857 register struct vnode
*vp
;
2860 struct nameidata nd
;
2862 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2863 if (error
= namei(&nd
))
2866 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
2868 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
2869 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
2871 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
2872 VOP_REVOKE(vp
, REVOKEALL
);
2879 * Convert a user file descriptor to a kernel file entry.
2882 getvnode(p
, fd
, fpp
)
2890 if (error
= fdgetf(p
, fd
, &fp
))
2892 if (fp
->f_type
!= DTYPE_VNODE
)
2899 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2900 * The following 10 system calls are designed to support features
2901 * which are specific to the HFS & HFS Plus volume formats
2906 * Make a complex file. A complex file is one with multiple forks (data streams)
2908 struct mkcomplex_args
{
2909 const char *path
; /* pathname of the file to be created */
2910 mode_t mode
; /* access mode for the newly created file */
2911 u_long type
; /* format of the complex file */
2915 mkcomplex(p
,uap
,retval
)
2917 register struct mkcomplex_args
*uap
;
2924 struct nameidata nd
;
2926 /* mkcomplex wants the directory vnode locked so do that here */
2928 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
2929 if (error
= namei(&nd
))
2932 /* Set the attributes as specified by the user */
2935 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
2936 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
2938 /* The mkcomplex call promises to release the parent vnode pointer
2939 * even an an error case so don't do it here unless the operation
2940 * is not supported. In that case, there isn't anyone to unlock the parent
2941 * The vnode pointer to the file will also be released.
2946 if (error
== EOPNOTSUPP
)
2953 } /* end of mkcomplex system call */
2958 * Extended stat call which returns volumeid and vnodeid as well as other info
2961 const char *path
; /* pathname of the target file */
2962 struct vstat
*vsb
; /* vstat structure for returned info */
2968 register struct statv_args
*uap
;
2972 return (EOPNOTSUPP
); /* We'll just return an error for now */
2974 } /* end of statv system call */
2979 * Extended lstat call which returns volumeid and vnodeid as well as other info
2981 struct lstatv_args
{
2982 const char *path
; /* pathname of the target file */
2983 struct vstat
*vsb
; /* vstat structure for returned info */
2987 lstatv(p
,uap
,retval
)
2989 register struct lstatv_args
*uap
;
2993 return (EOPNOTSUPP
); /* We'll just return an error for now */
2994 } /* end of lstatv system call */
2999 * Extended fstat call which returns volumeid and vnodeid as well as other info
3001 struct fstatv_args
{
3002 int fd
; /* file descriptor of the target file */
3003 struct vstat
*vsb
; /* vstat structure for returned info */
3007 fstatv(p
,uap
,retval
)
3009 register struct fstatv_args
*uap
;
3013 return (EOPNOTSUPP
); /* We'll just return an error for now */
3014 } /* end of fstatv system call */
3019 * Obtain attribute information about a file system object
3022 struct getattrlist_args
{
3023 const char *path
; /* pathname of the target object */
3024 struct attrlist
* alist
; /* Attributes desired by the user */
3025 void * attributeBuffer
; /* buffer to hold returned attributes */
3026 size_t bufferSize
; /* size of the return buffer */
3027 unsigned long options
; /* options (follow/don't follow) */
3031 getattrlist (p
,uap
,retval
)
3033 register struct getattrlist_args
*uap
;
3038 struct nameidata nd
;
3041 struct attrlist attributelist
;
3044 /* Get the attributes desire and do our parameter checking */
3046 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3047 sizeof (attributelist
)))
3052 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3054 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3055 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3056 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3057 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3058 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3065 /* Get the vnode for the file we are getting info on. */
3066 nameiflags
= LOCKLEAF
;
3067 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3068 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3070 if (error
= namei(&nd
))
3073 /* Set up the UIO structure for use by the vfs routine */
3076 aiov
.iov_base
= uap
->attributeBuffer
;
3077 aiov
.iov_len
= uap
->bufferSize
;
3078 auio
.uio_iov
= &aiov
;
3079 auio
.uio_iovcnt
= 1;
3080 auio
.uio_offset
= 0;
3081 auio
.uio_rw
= UIO_READ
;
3082 auio
.uio_segflg
= UIO_USERSPACE
;
3084 auio
.uio_resid
= uap
->bufferSize
;
3087 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3089 /* Unlock and release the vnode which will have been locked by namei */
3093 /* return the effort if we got one, otherwise return success */
3102 } /* end of getattrlist system call */
3107 * Set attribute information about a file system object
3110 struct setattrlist_args
{
3111 const char *path
; /* pathname of the target object */
3112 struct attrlist
* alist
; /* Attributes being set by the user */
3113 void * attributeBuffer
; /* buffer with attribute values to be set */
3114 size_t bufferSize
; /* size of the return buffer */
3115 unsigned long options
; /* options (follow/don't follow) */
3119 setattrlist (p
,uap
,retval
)
3121 register struct setattrlist_args
*uap
;
3126 struct nameidata nd
;
3129 struct attrlist alist
;
3132 /* Get the attributes desired and do our parameter checking */
3134 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3139 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3142 /* Get the vnode for the file whose attributes are being set. */
3143 nameiflags
= LOCKLEAF
;
3144 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3145 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3146 if (error
= namei(&nd
))
3149 /* Set up the UIO structure for use by the vfs routine */
3150 aiov
.iov_base
= uap
->attributeBuffer
;
3151 aiov
.iov_len
= uap
->bufferSize
;
3152 auio
.uio_iov
= &aiov
;
3153 auio
.uio_iovcnt
= 1;
3154 auio
.uio_offset
= 0;
3155 auio
.uio_rw
= UIO_WRITE
;
3156 auio
.uio_segflg
= UIO_USERSPACE
;
3158 auio
.uio_resid
= uap
->bufferSize
;
3160 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3166 } /* end of setattrlist system call */
3170 * Obtain attribute information on objects in a directory while enumerating
3171 * the directory. This call does not yet support union mounted directories.
3173 * 1.union mounted directories.
3176 struct getdirentriesattr_args
{
3177 int fd
; /* file descriptor */
3178 struct attrlist
*alist
; /* bit map of requested attributes */
3179 void *buffer
; /* buffer to hold returned attribute info */
3180 size_t buffersize
; /* size of the return buffer */
3181 u_long
*count
; /* the count of entries requested/returned */
3182 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3183 u_long
*newstate
; /* a flag to inform of changes in directory */
3184 u_long options
; /* maybe unused for now */
3188 getdirentriesattr (p
,uap
,retval
)
3190 register struct getdirentriesattr_args
*uap
;
3194 register struct vnode
*vp
;
3202 struct attrlist attributelist
;
3204 /* Get the attributes into kernel space */
3205 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3207 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3210 if (error
= getvnode(p
, uap
->fd
, &fp
))
3212 if ((fp
->f_flag
& FREAD
) == 0)
3214 vp
= (struct vnode
*)fp
->f_data
;
3216 if (vp
->v_type
!= VDIR
)
3219 /* set up the uio structure which will contain the users return buffer */
3220 aiov
.iov_base
= uap
->buffer
;
3221 aiov
.iov_len
= uap
->buffersize
;
3222 auio
.uio_iov
= &aiov
;
3223 auio
.uio_iovcnt
= 1;
3224 auio
.uio_rw
= UIO_READ
;
3225 auio
.uio_segflg
= UIO_USERSPACE
;
3227 auio
.uio_resid
= uap
->buffersize
;
3229 loff
= auio
.uio_offset
= fp
->f_offset
;
3230 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3231 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3232 actualcount
, uap
->options
, &newstate
, &eofflag
,
3233 &actualcount
, ((u_long
**)0), p
->p_cred
);
3235 VOP_UNLOCK(vp
, 0, p
);
3236 if (error
) return (error
);
3237 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3239 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3241 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3243 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3246 *retval
= eofflag
; /* similar to getdirentries */
3247 return (0); /* return error earlier, an retval of 0 or 1 now */
3249 } /* end of getdirentryattr system call */
3252 * Exchange data between two files
3255 struct exchangedata_args
{
3256 const char *path1
; /* pathname of the first swapee */
3257 const char *path2
; /* pathname of the second swapee */
3258 unsigned long options
; /* options */
3262 exchangedata (p
,uap
,retval
)
3264 register struct exchangedata_args
*uap
;
3269 struct nameidata fnd
, snd
;
3270 struct vnode
*fvp
, *svp
;
3275 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3277 /* Global lock, to prevent race condition, only one exchange at a time */
3278 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3280 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3282 if (error
= namei(&fnd
))
3287 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3289 if (error
= namei(&snd
)) {
3296 /* if the files are the same, return an inval error */
3304 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3305 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3307 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3308 if (error
) goto out
;
3310 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3311 if (error
) goto out
;
3313 /* Ok, make the call */
3314 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3321 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3329 } /* end of exchangedata system call */
3332 * Check users access to a file
3335 struct checkuseraccess_args
{
3336 const char *path
; /* pathname of the target file */
3337 uid_t userid
; /* user for whom we are checking access */
3338 gid_t
*groups
; /* Group that we are checking for */
3339 int ngroups
; /* Number of groups being checked */
3340 int accessrequired
; /* needed access to the file */
3341 unsigned long options
; /* options */
3346 checkuseraccess (p
,uap
,retval
)
3348 register struct checkuseraccess_args
*uap
;
3352 register struct vnode
*vp
;
3354 struct nameidata nd
;
3356 int flags
; /*what will actually get passed to access*/
3359 /* Make sure that the number of groups is correct before we do anything */
3361 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3364 /* Verify that the caller is root */
3366 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3369 /* Fill in the credential structure */
3372 cred
.cr_uid
= uap
->userid
;
3373 cred
.cr_ngroups
= uap
->ngroups
;
3374 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3377 /* Get our hands on the file */
3379 nameiflags
= LOCKLEAF
;
3380 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3381 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3383 if (error
= namei(&nd
))
3387 /* Flags == 0 means only check for existence. */
3391 if (uap
->accessrequired
) {
3392 if (uap
->accessrequired
& R_OK
)
3394 if (uap
->accessrequired
& W_OK
)
3396 if (uap
->accessrequired
& X_OK
)
3399 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3408 } /* end of checkuseraccess system call */
3411 struct searchfs_args
{
3413 struct fssearchblock
*searchblock
;
3417 struct searchstate
*state
;
3422 searchfs (p
,uap
,retval
)
3424 register struct searchfs_args
*uap
;
3428 register struct vnode
*vp
;
3431 struct nameidata nd
;
3432 struct fssearchblock searchblock
;
3433 struct searchstate
*state
;
3434 struct attrlist
*returnattrs
;
3435 void *searchparams1
,*searchparams2
;
3443 /* Start by copying in fsearchblock paramater list */
3445 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3448 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3449 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3450 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3453 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3454 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3456 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3458 /* Now set up the various pointers to the correct place in our newly allocated memory */
3460 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3461 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3462 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3464 /* Now copy in the stuff given our local variables. */
3466 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3469 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3472 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3475 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3478 /* set up the uio structure which will contain the users return buffer */
3480 aiov
.iov_base
= searchblock
.returnbuffer
;
3481 aiov
.iov_len
= searchblock
.returnbuffersize
;
3482 auio
.uio_iov
= &aiov
;
3483 auio
.uio_iovcnt
= 1;
3484 auio
.uio_rw
= UIO_READ
;
3485 auio
.uio_segflg
= UIO_USERSPACE
;
3487 auio
.uio_resid
= searchblock
.returnbuffersize
;
3489 nameiflags
= LOCKLEAF
;
3490 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3491 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3493 if (error
= namei(&nd
))
3500 * If searchblock.maxmatches == 0, then skip the search. This has happened
3501 * before and sometimes the underlyning code doesnt deal with it well.
3503 if (searchblock
.maxmatches
== 0) {
3509 Allright, we have everything we need, so lets make that call.
3511 We keep special track of the return value from the file system:
3512 EAGAIN is an acceptable error condition that shouldn't keep us
3513 from copying out any results...
3516 fserror
= VOP_SEARCHFS(vp
,
3519 &searchblock
.searchattrs
,
3520 searchblock
.maxmatches
,
3521 &searchblock
.timelimit
,
3533 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3534 search state. Everything was already put into he return buffer by the vop call. */
3536 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3539 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3546 FREE(searchparams1
,M_TEMP
);
3551 } /* end of searchfs system call */
3555 * Make a filesystem-specific control call:
3558 const char *path
; /* pathname of the target object */
3559 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3560 caddr_t data
; /* pointer to argument buffer */
3561 u_long options
; /* options for fsctl processing */
3565 fsctl (p
,uap
,retval
)
3567 struct fsctl_args
*uap
;
3572 struct nameidata nd
;
3574 u_long cmd
= uap
->cmd
;
3575 register u_int size
;
3576 #define STK_PARAMS 128
3577 char stkbuf
[STK_PARAMS
];
3580 size
= IOCPARM_LEN(cmd
);
3581 if (size
> IOCPARM_MAX
) return (EINVAL
);
3584 if (size
> sizeof (stkbuf
)) {
3585 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3593 error
= copyin(uap
->data
, data
, (u_int
)size
);
3594 if (error
) goto FSCtl_Exit
;
3596 *(caddr_t
*)data
= uap
->data
;
3598 } else if ((cmd
& IOC_OUT
) && size
) {
3600 * Zero the buffer so the user always
3601 * gets back something deterministic.
3604 } else if (cmd
& IOC_VOID
)
3605 *(caddr_t
*)data
= uap
->data
;
3607 /* Get the vnode for the file we are getting info on: */
3608 nameiflags
= LOCKLEAF
;
3609 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3610 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3611 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3613 /* Invoke the filesystem-specific code */
3614 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3619 * Copy any data to user, size was
3620 * already set and checked above.
3622 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3625 if (memp
) kfree(memp
, size
);
3629 /* end of fsctl system call */
3632 * An in-kernel sync for power management to call.
3634 __private_extern__
int
3637 boolean_t funnel_state
;
3640 struct sync_args data
;
3644 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3646 error
= sync(current_proc(), &data
, &retval
);
3648 thread_funnel_set(kernel_flock
, funnel_state
);
3651 } /* end of sync_internal call */