2 * Copyright (c) 1995-2000 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
));
261 lockinit(&mp
->mnt_lock
, PVFS
, "vfslock", 0, 0);
262 (void)vfs_busy(mp
, LK_NOWAIT
, 0, p
);
263 mp
->mnt_op
= vfsp
->vfc_vfsops
;
265 vfsp
->vfc_refcount
++;
266 mp
->mnt_stat
.f_type
= vfsp
->vfc_typenum
;
267 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
268 strncpy(mp
->mnt_stat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
269 mp
->mnt_vnodecovered
= vp
;
270 mp
->mnt_stat
.f_owner
= p
->p_ucred
->cr_uid
;
271 VOP_UNLOCK(vp
, 0, p
);
275 * Set the mount level flags.
277 if (uap
->flags
& MNT_RDONLY
)
278 mp
->mnt_flag
|= MNT_RDONLY
;
279 else if (mp
->mnt_flag
& MNT_RDONLY
)
280 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
281 mp
->mnt_flag
&=~ (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
282 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
| MNT_UNKNOWNPERMISSIONS
);
283 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
|
284 MNT_NODEV
| MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
| MNT_UNKNOWNPERMISSIONS
);
286 * Mount the filesystem.
288 error
= VFS_MOUNT(mp
, uap
->path
, uap
->data
, &nd
, p
);
289 if (mp
->mnt_flag
& MNT_UPDATE
) {
291 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
292 mp
->mnt_flag
&= ~MNT_RDONLY
;
294 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
295 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
302 * Put the new filesystem on the mount list after root.
306 simple_lock(&vp
->v_interlock
);
307 CLR(vp
->v_flag
, VMOUNT
);
308 vp
->v_mountedhere
=mp
;
309 simple_unlock(&vp
->v_interlock
);
310 simple_lock(&mountlist_slock
);
311 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
312 simple_unlock(&mountlist_slock
);
314 VOP_UNLOCK(vp
, 0, p
);
316 if (error
= VFS_START(mp
, 0, p
))
319 /* increment the operations count */
323 simple_lock(&vp
->v_interlock
);
324 CLR(vp
->v_flag
, VMOUNT
);
325 simple_unlock(&vp
->v_interlock
);
326 mp
->mnt_vfc
->vfc_refcount
--;
328 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
335 * Scan all active processes to see if any of them have a current
336 * or root directory onto which the new filesystem has just been
337 * mounted. If so, replace them with the new mount point.
343 struct filedesc
*fdp
;
347 if (olddp
->v_usecount
== 1)
349 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
350 panic("mount: lost mount");
351 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
353 if (fdp
->fd_cdir
== olddp
) {
356 fdp
->fd_cdir
= newdp
;
358 if (fdp
->fd_rdir
== olddp
) {
361 fdp
->fd_rdir
= newdp
;
364 if (rootvnode
== olddp
) {
373 * Unmount a file system.
375 * Note: unmount takes a path to the vnode mounted on as argument,
376 * not special file (as before).
378 struct unmount_args
{
384 unmount(p
, uap
, retval
)
386 register struct unmount_args
*uap
;
389 register struct vnode
*vp
;
394 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
396 if (error
= namei(&nd
))
402 * Only root, or the user that did the original mount is
403 * permitted to unmount this filesystem.
405 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
406 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
412 * Don't allow unmounting the root file system.
414 if (mp
->mnt_flag
& MNT_ROOTFS
) {
416 return (EBUSY
); /* the root is always busy */
420 * Must be the root of the filesystem
422 if ((vp
->v_flag
& VROOT
) == 0) {
427 return (dounmount(mp
, uap
->flags
, p
));
431 * Do the actual file system unmount.
434 dounmount(mp
, flags
, p
)
435 register struct mount
*mp
;
439 struct vnode
*coveredvp
;
442 simple_lock(&mountlist_slock
);
443 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
444 lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
, &mountlist_slock
, p
);
445 mp
->mnt_flag
&=~ MNT_ASYNC
;
446 ubc_umount(mp
); /* release cached vnodes */
447 cache_purgevfs(mp
); /* remove cache entries for this file sys */
448 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
449 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
451 error
= VFS_UNMOUNT(mp
, flags
, p
);
452 simple_lock(&mountlist_slock
);
454 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
455 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
456 &mountlist_slock
, p
);
460 /* increment the operations count */
463 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
464 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
465 coveredvp
->v_mountedhere
= (struct mount
*)0;
466 simple_unlock(&mountlist_slock
);
468 simple_lock(&mountlist_slock
);
470 mp
->mnt_vfc
->vfc_refcount
--;
471 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
472 panic("unmount: dangling vnode");
474 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
476 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
479 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
484 * Sync each mounted filesystem.
488 struct ctldebug debug0
= { "syncprt", &syncprt
};
494 int print_vmpage_stat
=0;
500 struct sync_args
*uap
;
503 register struct mount
*mp
, *nmp
;
506 simple_lock(&mountlist_slock
);
507 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
508 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
509 nmp
= mp
->mnt_list
.cqe_next
;
512 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
513 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
514 mp
->mnt_flag
&= ~MNT_ASYNC
;
515 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
517 mp
->mnt_flag
|= MNT_ASYNC
;
519 simple_lock(&mountlist_slock
);
520 nmp
= mp
->mnt_list
.cqe_next
;
523 simple_unlock(&mountlist_slock
);
526 extern void vm_countdirtypages(void);
527 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
528 extern unsigned int dp_pgins
, dp_pgouts
;
529 if(print_vmpage_stat
) {
530 vm_countdirtypages();
531 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
, dp_pgins
, dp_pgouts
);
537 #endif /* DIAGNOSTIC */
542 * Change filesystem quotas.
544 struct quotactl_args
{
552 quotactl(p
, uap
, retval
)
554 register struct quotactl_args
*uap
;
557 register struct mount
*mp
;
561 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
562 if (error
= namei(&nd
))
564 mp
= nd
.ni_vp
->v_mount
;
566 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
571 * Get filesystem statistics.
579 statfs(p
, uap
, retval
)
581 register struct statfs_args
*uap
;
584 register struct mount
*mp
;
585 register struct statfs
*sp
;
589 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
590 if (error
= namei(&nd
))
592 mp
= nd
.ni_vp
->v_mount
;
595 if (error
= VFS_STATFS(mp
, sp
, p
))
597 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
598 /* return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); */
599 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
, sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
603 * Get filesystem statistics.
605 struct fstatfs_args
{
611 fstatfs(p
, uap
, retval
)
613 register struct fstatfs_args
*uap
;
618 register struct statfs
*sp
;
621 if (error
= getvnode(p
, uap
->fd
, &fp
))
623 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
627 if (error
= VFS_STATFS(mp
, sp
, p
))
629 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
630 /* return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); */
631 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
, sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
635 * Get statistics on all filesystems.
637 struct getfsstat_args
{
643 getfsstat(p
, uap
, retval
)
645 register struct getfsstat_args
*uap
;
648 register struct mount
*mp
, *nmp
;
649 register struct statfs
*sp
;
651 long count
, maxcount
, error
;
653 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
654 sfsp
= (caddr_t
)uap
->buf
;
656 simple_lock(&mountlist_slock
);
657 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
658 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
659 nmp
= mp
->mnt_list
.cqe_next
;
662 if (sfsp
&& count
< maxcount
) {
665 * If MNT_NOWAIT is specified, do not refresh the
666 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
668 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
669 (uap
->flags
& MNT_WAIT
)) &&
670 (error
= VFS_STATFS(mp
, sp
, p
))) {
671 simple_lock(&mountlist_slock
);
672 nmp
= mp
->mnt_list
.cqe_next
;
676 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
677 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
682 simple_lock(&mountlist_slock
);
683 nmp
= mp
->mnt_list
.cqe_next
;
686 simple_unlock(&mountlist_slock
);
687 if (sfsp
&& count
> maxcount
)
695 ogetfsstat(p
, uap
, retval
)
697 register struct getfsstat_args
*uap
;
700 register struct mount
*mp
, *nmp
;
701 register struct statfs
*sp
;
703 long count
, maxcount
, error
;
705 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
706 sfsp
= (caddr_t
)uap
->buf
;
708 simple_lock(&mountlist_slock
);
709 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
710 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
711 nmp
= mp
->mnt_list
.cqe_next
;
714 if (sfsp
&& count
< maxcount
) {
717 * If MNT_NOWAIT is specified, do not refresh the
718 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
720 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
721 (uap
->flags
& MNT_WAIT
)) &&
722 (error
= VFS_STATFS(mp
, sp
, p
))) {
723 simple_lock(&mountlist_slock
);
724 nmp
= mp
->mnt_list
.cqe_next
;
728 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
729 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
)))
731 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
734 simple_lock(&mountlist_slock
);
735 nmp
= mp
->mnt_list
.cqe_next
;
738 simple_unlock(&mountlist_slock
);
739 if (sfsp
&& count
> maxcount
)
748 * Change current working directory to a given file descriptor.
755 fchdir(p
, uap
, retval
)
757 struct fchdir_args
*uap
;
760 register struct filedesc
*fdp
= p
->p_fd
;
761 struct vnode
*vp
, *tdp
;
766 if (error
= getvnode(p
, uap
->fd
, &fp
))
768 vp
= (struct vnode
*)fp
->f_data
;
770 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
771 if (vp
->v_type
!= VDIR
)
774 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
775 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
776 if (vfs_busy(mp
, 0, 0, p
))
778 error
= VFS_ROOT(mp
, &tdp
);
789 VOP_UNLOCK(vp
, 0, p
);
796 * Change current working directory (``.'').
803 chdir(p
, uap
, retval
)
805 struct chdir_args
*uap
;
808 register struct filedesc
*fdp
= p
->p_fd
;
812 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
814 if (error
= change_dir(&nd
, p
))
817 fdp
->fd_cdir
= nd
.ni_vp
;
822 * Change notion of root (``/'') directory.
829 chroot(p
, uap
, retval
)
831 struct chroot_args
*uap
;
834 register struct filedesc
*fdp
= p
->p_fd
;
838 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
841 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
843 if (error
= change_dir(&nd
, p
))
846 if(error
= clone_system_shared_regions()) {
851 if (fdp
->fd_rdir
!= NULL
)
853 fdp
->fd_rdir
= nd
.ni_vp
;
858 * Common routine for chroot and chdir.
862 register struct nameidata
*ndp
;
868 if (error
= namei(ndp
))
871 if (vp
->v_type
!= VDIR
)
874 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
878 VOP_UNLOCK(vp
, 0, p
);
883 * Check permissions, allocate an open file structure,
884 * and call the device open routine if any.
894 register struct open_args
*uap
;
897 register struct filedesc
*fdp
= p
->p_fd
;
898 register struct file
*fp
;
899 register struct vnode
*vp
;
902 int type
, indx
, error
;
905 extern struct fileops vnops
;
907 /* CERT advisory patch applied from FreeBSD */
908 /* Refer to Radar#2262895 A. Ramesh */
909 flags
= FFLAGS(uap
->flags
);
910 if ((flags
& (FREAD
| FWRITE
))==0)
912 if (error
= falloc(p
, &nfp
, &indx
))
915 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
916 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
917 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
918 if (error
= vn_open(&nd
, flags
, cmode
)) {
920 if ((error
== ENODEV
|| error
== ENXIO
) &&
921 p
->p_dupfd
>= 0 && /* XXX from fdopen */
923 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
927 if (error
== ERESTART
)
934 fp
->f_flag
= flags
& FMASK
;
935 fp
->f_type
= DTYPE_VNODE
;
937 fp
->f_data
= (caddr_t
)vp
;
938 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
939 lf
.l_whence
= SEEK_SET
;
942 if (flags
& O_EXLOCK
)
947 if ((flags
& FNONBLOCK
) == 0)
949 VOP_UNLOCK(vp
, 0, p
);
950 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
951 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
956 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
957 fp
->f_flag
|= FHASLOCK
;
959 VOP_UNLOCK(vp
, 0, p
);
960 *fdflags(p
, indx
) &= ~UF_RESERVED
;
974 ocreat(p
, uap
, retval
)
976 register struct ocreat_args
*uap
;
979 struct open_args nuap
;
981 nuap
.path
= uap
->path
;
982 nuap
.mode
= uap
->mode
;
983 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
984 return (open(p
, &nuap
, retval
));
986 #endif /* COMPAT_43 */
989 * Create a special file.
998 mknod(p
, uap
, retval
)
1000 register struct mknod_args
*uap
;
1003 register struct vnode
*vp
;
1007 struct nameidata nd
;
1009 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1011 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1012 if (error
= namei(&nd
))
1019 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1020 vattr
.va_rdev
= uap
->dev
;
1023 switch (uap
->mode
& S_IFMT
) {
1024 case S_IFMT
: /* used by badsect to flag bad sectors */
1025 vattr
.va_type
= VBAD
;
1028 vattr
.va_type
= VCHR
;
1031 vattr
.va_type
= VBLK
;
1042 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1044 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1046 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1049 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1050 &nd
.ni_cnd
, &vattr
);
1053 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1054 if (nd
.ni_dvp
== vp
)
1065 * Create a named pipe.
1067 struct mkfifo_args
{
1073 mkfifo(p
, uap
, retval
)
1075 register struct mkfifo_args
*uap
;
1080 struct nameidata nd
;
1083 return (EOPNOTSUPP
);
1085 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1086 if (error
= namei(&nd
))
1088 if (nd
.ni_vp
!= NULL
) {
1089 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1090 if (nd
.ni_dvp
== nd
.ni_vp
)
1098 vattr
.va_type
= VFIFO
;
1099 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1100 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1101 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1106 * Make a hard file link.
1114 link(p
, uap
, retval
)
1116 register struct link_args
*uap
;
1119 register struct vnode
*vp
;
1120 struct nameidata nd
;
1123 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1124 if (error
= namei(&nd
))
1127 if (vp
->v_type
== VDIR
)
1128 error
= EPERM
; /* POSIX */
1130 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1131 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1132 nd
.ni_dirp
= uap
->link
;
1133 if ((error
= namei(&nd
)) == 0) {
1134 if (nd
.ni_vp
!= NULL
)
1137 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1139 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1140 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1142 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1143 if (nd
.ni_dvp
== nd
.ni_vp
)
1157 * Make a symbolic link.
1159 struct symlink_args
{
1165 symlink(p
, uap
, retval
)
1167 register struct symlink_args
*uap
;
1173 struct nameidata nd
;
1175 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1176 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1178 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1179 if (error
= namei(&nd
))
1182 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1183 if (nd
.ni_dvp
== nd
.ni_vp
)
1192 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1193 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1194 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1196 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1201 * Delete a whiteout from the filesystem.
1203 struct undelete_args
{
1208 undelete(p
, uap
, retval
)
1210 register struct undelete_args
*uap
;
1214 struct nameidata nd
;
1216 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1222 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1223 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1224 if (nd
.ni_dvp
== nd
.ni_vp
)
1233 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1234 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1235 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1241 * Delete a name from the filesystem.
1243 struct unlink_args
{
1248 _unlink(p
, uap
, retval
, nodelbusy
)
1250 struct unlink_args
*uap
;
1254 register struct vnode
*vp
;
1256 struct nameidata nd
;
1258 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1259 /* with hfs semantics, busy files cannot be deleted */
1261 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1262 if (error
= namei(&nd
))
1265 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1266 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1268 if (vp
->v_type
== VDIR
)
1269 error
= EPERM
; /* POSIX */
1272 * The root of a mounted filesystem cannot be deleted.
1274 * XXX: can this only be a VDIR case?
1276 if (vp
->v_flag
& VROOT
)
1281 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1282 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1284 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1285 if (nd
.ni_dvp
== vp
)
1296 * Delete a name from the filesystem using POSIX semantics.
1299 unlink(p
, uap
, retval
)
1301 struct unlink_args
*uap
;
1304 return _unlink(p
, uap
, retval
, 0);
1308 * Delete a name from the filesystem using HFS semantics.
1311 delete(p
, uap
, retval
)
1313 struct unlink_args
*uap
;
1316 return _unlink(p
, uap
, retval
, 1);
1320 * Reposition read/write file offset.
1324 #ifdef DOUBLE_ALIGN_PARAMS
1331 lseek(p
, uap
, retval
)
1333 register struct lseek_args
*uap
;
1336 struct ucred
*cred
= p
->p_ucred
;
1341 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1343 if (fp
->f_type
!= DTYPE_VNODE
)
1345 switch (uap
->whence
) {
1347 fp
->f_offset
+= uap
->offset
;
1351 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1353 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1356 fp
->f_offset
= uap
->offset
;
1361 *(off_t
*)retval
= fp
->f_offset
;
1367 * Reposition read/write file offset.
1369 struct olseek_args
{
1375 olseek(p
, uap
, retval
)
1377 register struct olseek_args
*uap
;
1380 struct lseek_args
/* {
1382 #ifdef DOUBLE_ALIGN_PARAMS
1383 syscallarg(int) pad;
1385 syscallarg(off_t) offset;
1386 syscallarg(int) whence;
1392 nuap
.offset
= uap
->offset
;
1393 nuap
.whence
= uap
->whence
;
1394 error
= lseek(p
, &nuap
, &qret
);
1395 *(long *)retval
= qret
;
1398 #endif /* COMPAT_43 */
1401 * Check access permissions.
1403 struct access_args
{
1408 access(p
, uap
, retval
)
1410 register struct access_args
*uap
;
1413 register struct ucred
*cred
= p
->p_ucred
;
1414 register struct vnode
*vp
;
1415 int error
, flags
, t_gid
, t_uid
;
1416 struct nameidata nd
;
1418 t_uid
= cred
->cr_uid
;
1419 t_gid
= cred
->cr_groups
[0];
1420 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1421 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1422 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1424 if (error
= namei(&nd
))
1428 /* Flags == 0 means only check for existence. */
1431 if (uap
->flags
& R_OK
)
1433 if (uap
->flags
& W_OK
)
1435 if (uap
->flags
& X_OK
)
1437 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1438 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1442 cred
->cr_uid
= t_uid
;
1443 cred
->cr_groups
[0] = t_gid
;
1449 * Get file status; this version follows links.
1457 ostat(p
, uap
, retval
)
1459 register struct ostat_args
*uap
;
1465 struct nameidata nd
;
1467 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1469 if (error
= namei(&nd
))
1471 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1476 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1481 * Get file status; this version does not follow links.
1483 struct olstat_args
{
1489 olstat(p
, uap
, retval
)
1491 register struct olstat_args
*uap
;
1494 struct vnode
*vp
, *dvp
;
1495 struct stat sb
, sb1
;
1498 struct nameidata nd
;
1500 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1502 if (error
= namei(&nd
))
1505 * For symbolic links, always return the attributes of its
1506 * containing directory, except for mode, size, and links.
1510 if (vp
->v_type
!= VLNK
) {
1515 error
= vn_stat(vp
, &sb
, p
);
1520 error
= vn_stat(dvp
, &sb
, p
);
1526 error
= vn_stat(vp
, &sb1
, p
);
1530 sb
.st_mode
&= ~S_IFDIR
;
1531 sb
.st_mode
|= S_IFLNK
;
1532 sb
.st_nlink
= sb1
.st_nlink
;
1533 sb
.st_size
= sb1
.st_size
;
1534 sb
.st_blocks
= sb1
.st_blocks
;
1537 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1542 * Convert from an old to a new stat structure.
1550 ost
->st_dev
= st
->st_dev
;
1551 ost
->st_ino
= st
->st_ino
;
1552 ost
->st_mode
= st
->st_mode
;
1553 ost
->st_nlink
= st
->st_nlink
;
1554 ost
->st_uid
= st
->st_uid
;
1555 ost
->st_gid
= st
->st_gid
;
1556 ost
->st_rdev
= st
->st_rdev
;
1557 if (st
->st_size
< (quad_t
)1 << 32)
1558 ost
->st_size
= st
->st_size
;
1561 ost
->st_atime
= st
->st_atime
;
1562 ost
->st_mtime
= st
->st_mtime
;
1563 ost
->st_ctime
= st
->st_ctime
;
1564 ost
->st_blksize
= st
->st_blksize
;
1565 ost
->st_blocks
= st
->st_blocks
;
1566 ost
->st_flags
= st
->st_flags
;
1567 ost
->st_gen
= st
->st_gen
;
1569 #endif /* COMPAT_43 */
1572 * Get file status; this version follows links.
1580 stat(p
, uap
, retval
)
1582 register struct stat_args
*uap
;
1587 struct nameidata nd
;
1589 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1591 if (error
= namei(&nd
))
1593 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1597 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1602 * Get file status; this version does not follow links.
1610 lstat(p
, uap
, retval
)
1612 register struct lstat_args
*uap
;
1616 struct vnode
*vp
, *dvp
;
1617 struct stat sb
, sb1
;
1618 struct nameidata nd
;
1620 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1622 if (error
= namei(&nd
))
1625 * For symbolic links, always return the attributes of its containing
1626 * directory, except for mode, size, inode number, and links.
1630 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1635 error
= vn_stat(vp
, &sb
, p
);
1639 if (vp
->v_type
== VLNK
)
1640 sb
.st_mode
|= S_IFLNK
;
1642 error
= vn_stat(dvp
, &sb
, p
);
1648 error
= vn_stat(vp
, &sb1
, p
);
1652 sb
.st_mode
&= ~S_IFDIR
;
1653 sb
.st_mode
|= S_IFLNK
;
1654 sb
.st_nlink
= sb1
.st_nlink
;
1655 sb
.st_size
= sb1
.st_size
;
1656 sb
.st_blocks
= sb1
.st_blocks
;
1657 sb
.st_ino
= sb1
.st_ino
;
1659 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1664 * Get configurable pathname variables.
1666 struct pathconf_args
{
1672 pathconf(p
, uap
, retval
)
1674 register struct pathconf_args
*uap
;
1678 struct nameidata nd
;
1680 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1682 if (error
= namei(&nd
))
1684 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1690 * Return target name of a symbolic link.
1692 struct readlink_args
{
1699 readlink(p
, uap
, retval
)
1701 register struct readlink_args
*uap
;
1704 register struct vnode
*vp
;
1708 struct nameidata nd
;
1710 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1712 if (error
= namei(&nd
))
1715 if (vp
->v_type
!= VLNK
)
1718 aiov
.iov_base
= uap
->buf
;
1719 aiov
.iov_len
= uap
->count
;
1720 auio
.uio_iov
= &aiov
;
1721 auio
.uio_iovcnt
= 1;
1722 auio
.uio_offset
= 0;
1723 auio
.uio_rw
= UIO_READ
;
1724 auio
.uio_segflg
= UIO_USERSPACE
;
1726 auio
.uio_resid
= uap
->count
;
1727 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1730 *retval
= uap
->count
- auio
.uio_resid
;
1735 * Change flags of a file given a path name.
1737 struct chflags_args
{
1743 chflags(p
, uap
, retval
)
1745 register struct chflags_args
*uap
;
1748 register struct vnode
*vp
;
1751 struct nameidata nd
;
1753 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1754 if (error
= namei(&nd
))
1757 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1758 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1760 vattr
.va_flags
= uap
->flags
;
1761 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1767 * Change flags of a file given a file descriptor.
1769 struct fchflags_args
{
1775 fchflags(p
, uap
, retval
)
1777 register struct fchflags_args
*uap
;
1785 if (error
= getvnode(p
, uap
->fd
, &fp
))
1787 vp
= (struct vnode
*)fp
->f_data
;
1788 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1789 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1791 vattr
.va_flags
= uap
->flags
;
1792 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1793 VOP_UNLOCK(vp
, 0, p
);
1798 * Change mode of a file given path name.
1806 chmod(p
, uap
, retval
)
1808 register struct chmod_args
*uap
;
1811 register struct vnode
*vp
;
1814 struct nameidata nd
;
1816 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1817 if (error
= namei(&nd
))
1820 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1821 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1823 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1824 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1830 * Change mode of a file given a file descriptor.
1832 struct fchmod_args
{
1838 fchmod(p
, uap
, retval
)
1840 register struct fchmod_args
*uap
;
1848 if (error
= getvnode(p
, uap
->fd
, &fp
))
1850 vp
= (struct vnode
*)fp
->f_data
;
1851 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1852 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1854 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1855 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1856 VOP_UNLOCK(vp
, 0, p
);
1861 * Set ownership given a path name.
1870 chown(p
, uap
, retval
)
1872 register struct chown_args
*uap
;
1875 register struct vnode
*vp
;
1878 struct nameidata nd
;
1880 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1881 if (error
= namei(&nd
))
1886 XXX A TEMPORARY HACK FOR NOW: Try to track console_user
1887 by looking for chown() calls on /dev/console from a console process:
1889 if ((vp
) && (vp
->v_specinfo
) &&
1890 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
1891 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
1892 console_user
= uap
->uid
;
1895 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1896 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1898 vattr
.va_uid
= uap
->uid
;
1899 vattr
.va_gid
= uap
->gid
;
1900 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1906 * Set ownership given a file descriptor.
1908 struct fchown_args
{
1915 fchown(p
, uap
, retval
)
1917 register struct fchown_args
*uap
;
1925 if (error
= getvnode(p
, uap
->fd
, &fp
))
1927 vp
= (struct vnode
*)fp
->f_data
;
1928 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1929 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1931 vattr
.va_uid
= uap
->uid
;
1932 vattr
.va_gid
= uap
->gid
;
1933 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1934 VOP_UNLOCK(vp
, 0, p
);
1939 * Set the access and modification times of a file.
1941 struct utimes_args
{
1943 struct timeval
*tptr
;
1947 utimes(p
, uap
, retval
)
1949 register struct utimes_args
*uap
;
1952 register struct vnode
*vp
;
1953 struct timeval tv
[2];
1956 struct nameidata nd
;
1959 if (uap
->tptr
== NULL
) {
1962 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
1963 } else if (error
= copyin((caddr_t
)uap
->tptr
, (caddr_t
)tv
,
1966 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1967 if (error
= namei(&nd
))
1970 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1971 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1972 vattr
.va_atime
.tv_sec
= tv
[0].tv_sec
;
1973 vattr
.va_atime
.tv_nsec
= tv
[0].tv_usec
* 1000;
1974 vattr
.va_mtime
.tv_sec
= tv
[1].tv_sec
;
1975 vattr
.va_mtime
.tv_nsec
= tv
[1].tv_usec
* 1000;
1976 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1982 * Truncate a file given its path name.
1984 struct truncate_args
{
1986 #ifdef DOUBLE_ALIGN_PARAMS
1993 truncate(p
, uap
, retval
)
1995 register struct truncate_args
*uap
;
1998 register struct vnode
*vp
;
2001 struct nameidata nd
;
2003 if (uap
->length
< 0)
2005 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2006 if (error
= namei(&nd
))
2009 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2010 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2011 if (vp
->v_type
== VDIR
)
2013 else if ((error
= vn_writechk(vp
)) == 0 &&
2014 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2016 vattr
.va_size
= uap
->length
;
2017 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2024 * Truncate a file given a file descriptor.
2026 struct ftruncate_args
{
2028 #ifdef DOUBLE_ALIGN_PARAMS
2035 ftruncate(p
, uap
, retval
)
2037 register struct ftruncate_args
*uap
;
2045 if (uap
->length
< 0)
2048 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2051 if (fp
->f_type
== DTYPE_PSXSHM
) {
2052 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2054 if (fp
->f_type
!= DTYPE_VNODE
)
2058 if ((fp
->f_flag
& FWRITE
) == 0)
2060 vp
= (struct vnode
*)fp
->f_data
;
2061 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2062 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2063 if (vp
->v_type
== VDIR
)
2065 else if ((error
= vn_writechk(vp
)) == 0) {
2067 vattr
.va_size
= uap
->length
;
2068 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2070 VOP_UNLOCK(vp
, 0, p
);
2076 * Truncate a file given its path name.
2078 struct otruncate_args
{
2084 otruncate(p
, uap
, retval
)
2086 register struct otruncate_args
*uap
;
2089 struct truncate_args
/* {
2090 syscallarg(char *) path;
2091 #ifdef DOUBLE_ALIGN_PARAMS
2092 syscallarg(int) pad;
2094 syscallarg(off_t) length;
2097 nuap
.path
= uap
->path
;
2098 nuap
.length
= uap
->length
;
2099 return (truncate(p
, &nuap
, retval
));
2103 * Truncate a file given a file descriptor.
2105 struct oftruncate_args
{
2111 oftruncate(p
, uap
, retval
)
2113 register struct oftruncate_args
*uap
;
2116 struct ftruncate_args
/* {
2118 #ifdef DOUBLE_ALIGN_PARAMS
2119 syscallarg(int) pad;
2121 syscallarg(off_t) length;
2125 nuap
.length
= uap
->length
;
2126 return (ftruncate(p
, &nuap
, retval
));
2128 #endif /* COMPAT_43 */
2131 * Sync an open file.
2138 fsync(p
, uap
, retval
)
2140 struct fsync_args
*uap
;
2143 register struct vnode
*vp
;
2147 if (error
= getvnode(p
, uap
->fd
, &fp
))
2149 vp
= (struct vnode
*)fp
->f_data
;
2150 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2151 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2152 VOP_UNLOCK(vp
, 0, p
);
2157 * Duplicate files. Source must be a file, target must be a file or
2161 struct copyfile_args
{
2169 copyfile(p
, uap
, retval
)
2171 register struct copyfile_args
*uap
;
2174 register struct vnode
*tvp
, *fvp
, *tdvp
;
2175 register struct ucred
*cred
= p
->p_ucred
;
2176 struct nameidata fromnd
, tond
;
2179 /* Check that the flags are valid.
2182 if (uap
->flags
& ~CPF_MASK
) {
2186 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2188 if (error
= namei(&fromnd
))
2192 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2193 UIO_USERSPACE
, uap
->to
, p
);
2194 if (error
= namei(&tond
)) {
2201 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2207 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2212 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2218 * If source is the same as the destination (that is the
2219 * same inode number) then there is nothing to do.
2220 * (fixed to have POSIX semantics - CSM 3/2/98)
2226 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2228 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2237 vrele(tond
.ni_startdir
);
2238 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2240 if (fromnd
.ni_startdir
)
2241 vrele(fromnd
.ni_startdir
);
2242 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2249 * Rename files. Source and destination must either both be directories,
2250 * or both not be directories. If target is a directory, it must be empty.
2252 struct rename_args
{
2258 rename(p
, uap
, retval
)
2260 register struct rename_args
*uap
;
2263 register struct vnode
*tvp
, *fvp
, *tdvp
;
2264 struct nameidata fromnd
, tond
;
2270 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2272 if (error
= namei(&fromnd
))
2276 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2277 UIO_USERSPACE
, uap
->to
, p
);
2278 if (error
= namei(&tond
)) {
2279 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2280 vrele(fromnd
.ni_dvp
);
2288 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2291 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2299 * If source is the same as the destination (that is the
2300 * same inode number) then there is nothing to do.
2306 * Allow the renaming of mount points.
2307 * - target must not exist
2308 * - target must reside in the same directory as source
2309 * - union mounts cannot be renamed
2310 * - "/" cannot be renamed
2312 if ((fvp
->v_flag
& VROOT
) &&
2313 (fvp
->v_type
== VDIR
) &&
2315 (fvp
->v_mountedhere
== NULL
) &&
2316 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2317 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2318 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2320 /* switch fvp to the covered vnode */
2321 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2329 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2330 if (fromnd
.ni_dvp
!= tdvp
)
2331 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2333 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2334 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2335 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2340 * update filesystem's mount point data
2343 char *cp
, *pathend
, *mpname
;
2350 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2351 mp
= fvp
->v_mountedhere
;
2353 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2358 VOP_UNLOCK(fvp
, 0, p
);
2360 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2361 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2363 /* find current mount point prefix */
2364 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2365 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2369 /* find last component of target name */
2370 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2374 /* append name to prefix */
2375 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2376 bzero(pathend
, maxlen
);
2377 strncpy(pathend
, mpname
, maxlen
- 1);
2379 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2385 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2392 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2393 vrele(fromnd
.ni_dvp
);
2397 vrele(tond
.ni_startdir
);
2398 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2400 if (fromnd
.ni_startdir
)
2401 vrele(fromnd
.ni_startdir
);
2402 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2409 * Make a directory file.
2417 mkdir(p
, uap
, retval
)
2419 register struct mkdir_args
*uap
;
2422 register struct vnode
*vp
;
2425 struct nameidata nd
;
2427 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2428 if (error
= namei(&nd
))
2432 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2433 if (nd
.ni_dvp
== vp
)
2441 vattr
.va_type
= VDIR
;
2442 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2443 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2444 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2451 * Remove a directory file.
2458 rmdir(p
, uap
, retval
)
2460 struct rmdir_args
*uap
;
2463 register struct vnode
*vp
;
2465 struct nameidata nd
;
2467 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2469 if (error
= namei(&nd
))
2472 if (vp
->v_type
!= VDIR
) {
2477 * No rmdir "." please.
2479 if (nd
.ni_dvp
== vp
) {
2484 * The root of a mounted filesystem cannot be deleted.
2486 if (vp
->v_flag
& VROOT
)
2490 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2491 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2492 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2494 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2495 if (nd
.ni_dvp
== vp
)
2506 * Read a block of directory entries in a file system independent format.
2508 struct ogetdirentries_args
{
2515 ogetdirentries(p
, uap
, retval
)
2517 register struct ogetdirentries_args
*uap
;
2520 register struct vnode
*vp
;
2522 struct uio auio
, kuio
;
2523 struct iovec aiov
, kiov
;
2524 struct dirent
*dp
, *edp
;
2526 int error
, eofflag
, readcnt
;
2529 if (error
= getvnode(p
, uap
->fd
, &fp
))
2531 if ((fp
->f_flag
& FREAD
) == 0)
2533 vp
= (struct vnode
*)fp
->f_data
;
2535 if (vp
->v_type
!= VDIR
)
2537 aiov
.iov_base
= uap
->buf
;
2538 aiov
.iov_len
= uap
->count
;
2539 auio
.uio_iov
= &aiov
;
2540 auio
.uio_iovcnt
= 1;
2541 auio
.uio_rw
= UIO_READ
;
2542 auio
.uio_segflg
= UIO_USERSPACE
;
2544 auio
.uio_resid
= uap
->count
;
2545 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2546 loff
= auio
.uio_offset
= fp
->f_offset
;
2547 # if (BYTE_ORDER != LITTLE_ENDIAN)
2548 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2549 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2550 (int *)0, (u_long
*)0);
2551 fp
->f_offset
= auio
.uio_offset
;
2556 kuio
.uio_iov
= &kiov
;
2557 kuio
.uio_segflg
= UIO_SYSSPACE
;
2558 kiov
.iov_len
= uap
->count
;
2559 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2560 kiov
.iov_base
= dirbuf
;
2561 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2562 (int *)0, (u_long
*)0);
2563 fp
->f_offset
= kuio
.uio_offset
;
2565 readcnt
= uap
->count
- kuio
.uio_resid
;
2566 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2567 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2568 # if (BYTE_ORDER == LITTLE_ENDIAN)
2570 * The expected low byte of
2571 * dp->d_namlen is our dp->d_type.
2572 * The high MBZ byte of dp->d_namlen
2573 * is our dp->d_namlen.
2575 dp
->d_type
= dp
->d_namlen
;
2579 * The dp->d_type is the high byte
2580 * of the expected dp->d_namlen,
2581 * so must be zero'ed.
2585 if (dp
->d_reclen
> 0) {
2586 dp
= (struct dirent
*)
2587 ((char *)dp
+ dp
->d_reclen
);
2594 error
= uiomove(dirbuf
, readcnt
, &auio
);
2596 FREE(dirbuf
, M_TEMP
);
2598 VOP_UNLOCK(vp
, 0, p
);
2604 extern int (**union_vnodeop_p
)(void *);
2605 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2607 if ((uap
->count
== auio
.uio_resid
) &&
2608 (vp
->v_op
== union_vnodeop_p
)) {
2611 lvp
= union_dircache(vp
, p
);
2612 if (lvp
!= NULLVP
) {
2616 * If the directory is opaque,
2617 * then don't show lower entries
2619 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2620 if (va
.va_flags
& OPAQUE
) {
2626 if (lvp
!= NULLVP
) {
2627 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2632 VOP_UNLOCK(lvp
, 0, p
);
2633 fp
->f_data
= (caddr_t
) lvp
;
2635 error
= vn_close(vp
, FREAD
, fp
->f_cred
, p
);
2645 if ((uap
->count
== auio
.uio_resid
) &&
2646 (vp
->v_flag
& VROOT
) &&
2647 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2648 struct vnode
*tvp
= vp
;
2649 vp
= vp
->v_mount
->mnt_vnodecovered
;
2651 fp
->f_data
= (caddr_t
) vp
;
2656 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2658 *retval
= uap
->count
- auio
.uio_resid
;
2661 #endif /* COMPAT_43 */
2664 * Read a block of directory entries in a file system independent format.
2666 struct getdirentries_args
{
2673 getdirentries(p
, uap
, retval
)
2675 register struct getdirentries_args
*uap
;
2678 register struct vnode
*vp
;
2685 if (error
= getvnode(p
, uap
->fd
, &fp
))
2687 if ((fp
->f_flag
& FREAD
) == 0)
2689 vp
= (struct vnode
*)fp
->f_data
;
2691 if (vp
->v_type
!= VDIR
)
2693 aiov
.iov_base
= uap
->buf
;
2694 aiov
.iov_len
= uap
->count
;
2695 auio
.uio_iov
= &aiov
;
2696 auio
.uio_iovcnt
= 1;
2697 auio
.uio_rw
= UIO_READ
;
2698 auio
.uio_segflg
= UIO_USERSPACE
;
2700 auio
.uio_resid
= uap
->count
;
2701 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2702 loff
= auio
.uio_offset
= fp
->f_offset
;
2703 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2704 (int *)0, (u_long
*)0);
2705 fp
->f_offset
= auio
.uio_offset
;
2706 VOP_UNLOCK(vp
, 0, p
);
2712 extern int (**union_vnodeop_p
)(void *);
2713 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2715 if ((uap
->count
== auio
.uio_resid
) &&
2716 (vp
->v_op
== union_vnodeop_p
)) {
2719 lvp
= union_dircache(vp
, p
);
2720 if (lvp
!= NULLVP
) {
2724 * If the directory is opaque,
2725 * then don't show lower entries
2727 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2728 if (va
.va_flags
& OPAQUE
) {
2734 if (lvp
!= NULLVP
) {
2735 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2740 VOP_UNLOCK(lvp
, 0, p
);
2741 fp
->f_data
= (caddr_t
) lvp
;
2743 error
= vn_close(vp
, FREAD
, fp
->f_cred
, p
);
2753 if ((uap
->count
== auio
.uio_resid
) &&
2754 (vp
->v_flag
& VROOT
) &&
2755 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2756 struct vnode
*tvp
= vp
;
2757 vp
= vp
->v_mount
->mnt_vnodecovered
;
2759 fp
->f_data
= (caddr_t
) vp
;
2764 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2766 *retval
= uap
->count
- auio
.uio_resid
;
2771 * Set the mode mask for creation of filesystem nodes.
2777 umask(p
, uap
, retval
)
2779 struct umask_args
*uap
;
2782 register struct filedesc
*fdp
;
2785 *retval
= fdp
->fd_cmask
;
2786 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
2791 * Void all references to file by ripping underlying filesystem
2794 struct revoke_args
{
2799 revoke(p
, uap
, retval
)
2801 register struct revoke_args
*uap
;
2804 register struct vnode
*vp
;
2807 struct nameidata nd
;
2809 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2810 if (error
= namei(&nd
))
2813 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
2815 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
2816 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
2818 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
2819 VOP_REVOKE(vp
, REVOKEALL
);
2826 * Convert a user file descriptor to a kernel file entry.
2829 getvnode(p
, fd
, fpp
)
2837 if (error
= fdgetf(p
, fd
, &fp
))
2839 if (fp
->f_type
!= DTYPE_VNODE
)
2845 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2846 * The following 10 system calls are designed to support features
2847 * which are specific to the HFS & HFS Plus volume formats
2852 * Make a complex file. A complex file is one with multiple forks (data streams)
2854 struct mkcomplex_args
{
2855 const char *path
; /* pathname of the file to be created */
2856 mode_t mode
; /* access mode for the newly created file */
2857 u_long type
; /* format of the complex file */
2861 mkcomplex(p
,uap
,retval
)
2863 register struct mkcomplex_args
*uap
;
2870 struct nameidata nd
;
2872 /* mkcomplex wants the directory vnode locked so do that here */
2874 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
2875 if (error
= namei(&nd
))
2878 /* Set the attributes as specified by the user */
2881 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
2882 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
2884 /* The mkcomplex call promises to release the parent vnode pointer
2885 * even an an error case so don't do it here unless the operation
2886 * is not supported. In that case, there isn't anyone to unlock the parent
2887 * The vnode pointer to the file will also be released.
2892 if (error
== EOPNOTSUPP
)
2899 } /* end of mkcomplex system call */
2904 * Extended stat call which returns volumeid and vnodeid as well as other info
2907 const char *path
; /* pathname of the target file */
2908 struct vstat
*vsb
; /* vstat structure for returned info */
2914 register struct statv_args
*uap
;
2918 return (EOPNOTSUPP
); /* We'll just return an error for now */
2920 } /* end of statv system call */
2925 * Extended lstat call which returns volumeid and vnodeid as well as other info
2927 struct lstatv_args
{
2928 const char *path
; /* pathname of the target file */
2929 struct vstat
*vsb
; /* vstat structure for returned info */
2933 lstatv(p
,uap
,retval
)
2935 register struct lstatv_args
*uap
;
2939 return (EOPNOTSUPP
); /* We'll just return an error for now */
2940 } /* end of lstatv system call */
2945 * Extended fstat call which returns volumeid and vnodeid as well as other info
2947 struct fstatv_args
{
2948 int fd
; /* file descriptor of the target file */
2949 struct vstat
*vsb
; /* vstat structure for returned info */
2953 fstatv(p
,uap
,retval
)
2955 register struct fstatv_args
*uap
;
2959 return (EOPNOTSUPP
); /* We'll just return an error for now */
2960 } /* end of fstatv system call */
2965 * Obtain attribute information about a file system object
2968 struct getattrlist_args
{
2969 const char *path
; /* pathname of the target object */
2970 struct attrlist
* alist
; /* Attributes desired by the user */
2971 void * attributeBuffer
; /* buffer to hold returned attributes */
2972 size_t bufferSize
; /* size of the return buffer */
2973 unsigned long options
; /* options (follow/don't follow) */
2977 getattrlist (p
,uap
,retval
)
2979 register struct getattrlist_args
*uap
;
2984 struct nameidata nd
;
2987 struct attrlist attributelist
;
2990 /* Get the attributes desire and do our parameter checking */
2992 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
2993 sizeof (attributelist
)))
2998 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3000 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3001 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3002 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3003 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3004 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3011 /* Get the vnode for the file we are getting info on. */
3012 nameiflags
= LOCKLEAF
;
3013 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3014 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3016 if (error
= namei(&nd
))
3019 /* Set up the UIO structure for use by the vfs routine */
3022 aiov
.iov_base
= uap
->attributeBuffer
;
3023 aiov
.iov_len
= uap
->bufferSize
;
3024 auio
.uio_iov
= &aiov
;
3025 auio
.uio_iovcnt
= 1;
3026 auio
.uio_offset
= 0;
3027 auio
.uio_rw
= UIO_READ
;
3028 auio
.uio_segflg
= UIO_USERSPACE
;
3030 auio
.uio_resid
= uap
->bufferSize
;
3033 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3035 /* Unlock and release the vnode which will have been locked by namei */
3039 /* return the effort if we got one, otherwise return success */
3048 } /* end of getattrlist system call */
3053 * Set attribute information about a file system object
3056 struct setattrlist_args
{
3057 const char *path
; /* pathname of the target object */
3058 struct attrlist
* alist
; /* Attributes being set by the user */
3059 void * attributeBuffer
; /* buffer with attribute values to be set */
3060 size_t bufferSize
; /* size of the return buffer */
3061 unsigned long options
; /* options (follow/don't follow) */
3065 setattrlist (p
,uap
,retval
)
3067 register struct setattrlist_args
*uap
;
3072 struct nameidata nd
;
3075 struct attrlist alist
;
3078 /* Get the attributes desired and do our parameter checking */
3080 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3085 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3088 /* Get the vnode for the file whose attributes are being set. */
3089 nameiflags
= LOCKLEAF
;
3090 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3091 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3092 if (error
= namei(&nd
))
3095 /* Set up the UIO structure for use by the vfs routine */
3096 aiov
.iov_base
= uap
->attributeBuffer
;
3097 aiov
.iov_len
= uap
->bufferSize
;
3098 auio
.uio_iov
= &aiov
;
3099 auio
.uio_iovcnt
= 1;
3100 auio
.uio_offset
= 0;
3101 auio
.uio_rw
= UIO_WRITE
;
3102 auio
.uio_segflg
= UIO_USERSPACE
;
3104 auio
.uio_resid
= uap
->bufferSize
;
3106 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3112 } /* end of setattrlist system call */
3116 * Obtain attribute information on objects in a directory while enumerating
3117 * the directory. This call does not yet support union mounted directories.
3119 * 1.union mounted directories.
3122 struct getdirentriesattr_args
{
3123 int fd
; /* file descriptor */
3124 struct attrlist
*alist
; /* bit map of requested attributes */
3125 void *buffer
; /* buffer to hold returned attribute info */
3126 size_t buffersize
; /* size of the return buffer */
3127 u_long
*count
; /* the count of entries requested/returned */
3128 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3129 u_long
*newstate
; /* a flag to inform of changes in directory */
3130 u_long options
; /* maybe unused for now */
3134 getdirentriesattr (p
,uap
,retval
)
3136 register struct getdirentriesattr_args
*uap
;
3140 register struct vnode
*vp
;
3148 struct attrlist attributelist
;
3150 /* Get the attributes into kernel space */
3151 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3153 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3156 if (error
= getvnode(p
, uap
->fd
, &fp
))
3158 if ((fp
->f_flag
& FREAD
) == 0)
3160 vp
= (struct vnode
*)fp
->f_data
;
3162 if (vp
->v_type
!= VDIR
)
3165 /* set up the uio structure which will contain the users return buffer */
3166 aiov
.iov_base
= uap
->buffer
;
3167 aiov
.iov_len
= uap
->buffersize
;
3168 auio
.uio_iov
= &aiov
;
3169 auio
.uio_iovcnt
= 1;
3170 auio
.uio_rw
= UIO_READ
;
3171 auio
.uio_segflg
= UIO_USERSPACE
;
3173 auio
.uio_resid
= uap
->buffersize
;
3175 loff
= auio
.uio_offset
= fp
->f_offset
;
3176 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3177 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3178 actualcount
, uap
->options
, &newstate
, &eofflag
,
3179 &actualcount
, ((u_long
**)0), p
->p_cred
);
3181 VOP_UNLOCK(vp
, 0, p
);
3182 if (error
) return (error
);
3183 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3185 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3187 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3189 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3192 *retval
= eofflag
; /* similar to getdirentries */
3193 return (0); /* return error earlier, an retval of 0 or 1 now */
3195 } /* end of getdirentryattr system call */
3198 * Exchange data between two files
3201 struct exchangedata_args
{
3202 const char *path1
; /* pathname of the first swapee */
3203 const char *path2
; /* pathname of the second swapee */
3204 unsigned long options
; /* options */
3208 exchangedata (p
,uap
,retval
)
3210 register struct exchangedata_args
*uap
;
3215 struct nameidata fnd
, snd
;
3216 struct vnode
*fvp
, *svp
;
3221 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3223 /* Global lock, to prevent race condition, only one exchange at a time */
3224 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3226 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3228 if (error
= namei(&fnd
))
3233 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3235 if (error
= namei(&snd
)) {
3242 /* if the files are the same, return an inval error */
3250 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3251 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3253 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3254 if (error
) goto out
;
3256 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3257 if (error
) goto out
;
3259 /* Ok, make the call */
3260 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3267 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3275 } /* end of exchangedata system call */
3278 * Check users access to a file
3281 struct checkuseraccess_args
{
3282 const char *path
; /* pathname of the target file */
3283 uid_t userid
; /* user for whom we are checking access */
3284 gid_t
*groups
; /* Group that we are checking for */
3285 int ngroups
; /* Number of groups being checked */
3286 int accessrequired
; /* needed access to the file */
3287 unsigned long options
; /* options */
3292 checkuseraccess (p
,uap
,retval
)
3294 register struct checkuseraccess_args
*uap
;
3298 register struct vnode
*vp
;
3300 struct nameidata nd
;
3302 int flags
; /*what will actually get passed to access*/
3305 /* Make sure that the number of groups is correct before we do anything */
3307 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3310 /* Verify that the caller is root */
3312 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3315 /* Fill in the credential structure */
3318 cred
.cr_uid
= uap
->userid
;
3319 cred
.cr_ngroups
= uap
->ngroups
;
3320 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3323 /* Get our hands on the file */
3325 nameiflags
= LOCKLEAF
;
3326 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3327 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3329 if (error
= namei(&nd
))
3333 /* Flags == 0 means only check for existence. */
3337 if (uap
->accessrequired
) {
3338 if (uap
->accessrequired
& R_OK
)
3340 if (uap
->accessrequired
& W_OK
)
3342 if (uap
->accessrequired
& X_OK
)
3345 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3354 } /* end of checkuseraccess system call */
3357 struct searchfs_args
{
3359 struct fssearchblock
*searchblock
;
3363 struct searchstate
*state
;
3368 searchfs (p
,uap
,retval
)
3370 register struct searchfs_args
*uap
;
3374 register struct vnode
*vp
;
3377 struct nameidata nd
;
3378 struct fssearchblock searchblock
;
3379 struct searchstate
*state
;
3380 struct attrlist
*returnattrs
;
3381 void *searchparams1
,*searchparams2
;
3389 /* Start by copying in fsearchblock paramater list */
3391 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3394 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3395 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3396 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3399 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3400 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3402 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3404 /* Now set up the various pointers to the correct place in our newly allocated memory */
3406 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3407 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3408 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3410 /* Now copy in the stuff given our local variables. */
3412 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3415 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3418 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3421 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3424 /* set up the uio structure which will contain the users return buffer */
3426 aiov
.iov_base
= searchblock
.returnbuffer
;
3427 aiov
.iov_len
= searchblock
.returnbuffersize
;
3428 auio
.uio_iov
= &aiov
;
3429 auio
.uio_iovcnt
= 1;
3430 auio
.uio_rw
= UIO_READ
;
3431 auio
.uio_segflg
= UIO_USERSPACE
;
3433 auio
.uio_resid
= searchblock
.returnbuffersize
;
3435 nameiflags
= LOCKLEAF
;
3436 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3437 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3439 if (error
= namei(&nd
))
3446 * If searchblock.maxmatches == 0, then skip the search. This has happened
3447 * before and sometimes the underlyning code doesnt deal with it well.
3449 if (searchblock
.maxmatches
== 0) {
3455 Allright, we have everything we need, so lets make that call.
3457 We keep special track of the return value from the file system:
3458 EAGAIN is an acceptable error condition that shouldn't keep us
3459 from copying out any results...
3462 fserror
= VOP_SEARCHFS(vp
,
3465 &searchblock
.searchattrs
,
3466 searchblock
.maxmatches
,
3467 &searchblock
.timelimit
,
3479 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3480 search state. Everything was already put into he return buffer by the vop call. */
3482 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3485 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3492 FREE(searchparams1
,M_TEMP
);
3497 } /* end of searchfs system call */
3501 * Make a filesystem-specific control call:
3504 const char *path
; /* pathname of the target object */
3505 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3506 caddr_t data
; /* pointer to argument buffer */
3507 u_long options
; /* options for fsctl processing */
3511 fsctl (p
,uap
,retval
)
3513 struct fsctl_args
*uap
;
3518 struct nameidata nd
;
3520 u_long cmd
= uap
->cmd
;
3521 register u_int size
;
3522 #define STK_PARAMS 128
3523 char stkbuf
[STK_PARAMS
];
3526 size
= IOCPARM_LEN(cmd
);
3527 if (size
> IOCPARM_MAX
) return (EINVAL
);
3530 if (size
> sizeof (stkbuf
)) {
3531 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3539 error
= copyin(uap
->data
, data
, (u_int
)size
);
3540 if (error
) goto FSCtl_Exit
;
3542 *(caddr_t
*)data
= uap
->data
;
3544 } else if ((cmd
& IOC_OUT
) && size
) {
3546 * Zero the buffer so the user always
3547 * gets back something deterministic.
3550 } else if (cmd
& IOC_VOID
)
3551 *(caddr_t
*)data
= uap
->data
;
3553 /* Get the vnode for the file we are getting info on: */
3554 nameiflags
= LOCKLEAF
;
3555 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3556 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3557 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3559 /* Invoke the filesystem-specific code */
3560 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3565 * Copy any data to user, size was
3566 * already set and checked above.
3568 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3571 if (memp
) kfree(memp
, size
);
3575 /* end of fsctl system call */