2 * Copyright (c) 1995-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1989, 1993
27 * The Regents of the University of California. All rights reserved.
28 * (c) UNIX System Laboratories, Inc.
29 * All or some portions of this file are derived from material licensed
30 * to the University of California by American Telephone and Telegraph
31 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
32 * the permission of UNIX System Laboratories, Inc.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/namei.h>
68 #include <sys/filedesc.h>
69 #include <sys/kernel.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
76 #include <sys/malloc.h>
77 #include <sys/dirent.h>
79 #include <sys/sysctl.h>
81 #include <sys/quota.h>
82 #include <machine/cons.h>
83 #include <miscfs/specfs/specdev.h>
85 struct lock__bsd__ exchangelock
;
88 * The currently logged-in user, for ownership of files/directories whose on-disk
89 * permissions are ignored:
93 static int change_dir
__P((struct nameidata
*ndp
, struct proc
*p
));
94 static void checkdirs
__P((struct vnode
*olddp
));
95 static void enablequotas
__P((struct proc
*p
, struct mount
*mp
));
97 /* counts number of mount and unmount operations */
98 unsigned int vfs_nummntops
=0;
101 * Virtual File System System Calls
105 * Mount a file system.
115 mount(p
, uap
, retval
)
117 register struct mount_args
*uap
;
122 struct vfsconf
*vfsp
;
123 int error
, flag
, err2
;
127 char fstypename
[MFSNAMELEN
];
131 * Get vnode to be covered
133 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
135 if (error
= namei(&nd
))
139 if ((vp
->v_flag
& VROOT
) &&
140 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
141 uap
->flags
|= MNT_UPDATE
;
143 if (uap
->flags
& MNT_UPDATE
) {
144 if ((vp
->v_flag
& VROOT
) == 0) {
150 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
155 * We only allow the filesystem to be reloaded if it
156 * is currently mounted read-only.
158 if ((uap
->flags
& MNT_RELOAD
) &&
159 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
162 return (EOPNOTSUPP
); /* Needs translation */
165 * Only root, or the user that did the original mount is
166 * permitted to update it.
168 if (mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
&&
169 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
175 * Do not allow NFS export by non-root users. FOr non-root
176 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
177 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
179 if (p
->p_ucred
->cr_uid
!= 0) {
180 if (uap
->flags
& MNT_EXPORTED
) {
185 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
186 if (mp
->mnt_flag
& MNT_NOEXEC
)
187 uap
->flags
|= MNT_NOEXEC
;
192 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
194 VOP_UNLOCK(vp
, 0, p
);
199 * If the user is not root, ensure that they own the directory
200 * onto which we are attempting to mount.
202 if ((error
= VOP_GETATTR(vp
, &va
, p
->p_ucred
, p
)) ||
203 (va
.va_uid
!= p
->p_ucred
->cr_uid
&&
204 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))) {
209 * Do not allow NFS export by non-root users. FOr non-root
210 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
211 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
213 if (p
->p_ucred
->cr_uid
!= 0) {
214 if (uap
->flags
& MNT_EXPORTED
) {
218 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
219 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
220 uap
->flags
|= MNT_NOEXEC
;
222 if (error
= vinvalbuf(vp
, V_SAVE
, p
->p_ucred
, p
, 0, 0)) {
226 if (vp
->v_type
!= VDIR
) {
232 * Historically filesystem types were identified by number. If we
233 * get an integer for the filesystem type instead of a string, we
234 * check to see if it matches one of the historic filesystem types.
236 fstypenum
= (u_long
)uap
->type
;
237 if (fstypenum
< maxvfsconf
) {
238 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
239 if (vfsp
->vfc_typenum
== fstypenum
)
245 strncpy(fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
247 #endif /* COMPAT_43 */
248 if (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) {
252 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
253 if (!strcmp(vfsp
->vfc_name
, fstypename
))
259 simple_lock(&vp
->v_interlock
);
260 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
261 simple_unlock(&vp
->v_interlock
);
265 SET(vp
->v_flag
, VMOUNT
);
266 simple_unlock(&vp
->v_interlock
);
269 * Allocate and initialize the filesystem.
271 mp
= (struct mount
*)_MALLOC_ZONE((u_long
)sizeof(struct mount
),
273 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
275 /* Initialize the default IO constraints */
276 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
277 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
279 lockinit(&mp
->mnt_lock
, PVFS
, "vfslock", 0, 0);
280 (void)vfs_busy(mp
, LK_NOWAIT
, 0, p
);
281 mp
->mnt_op
= vfsp
->vfc_vfsops
;
283 vfsp
->vfc_refcount
++;
284 mp
->mnt_stat
.f_type
= vfsp
->vfc_typenum
;
285 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
286 strncpy(mp
->mnt_stat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
287 mp
->mnt_vnodecovered
= vp
;
288 mp
->mnt_stat
.f_owner
= p
->p_ucred
->cr_uid
;
289 VOP_UNLOCK(vp
, 0, p
);
293 * Set the mount level flags.
295 if (uap
->flags
& MNT_RDONLY
)
296 mp
->mnt_flag
|= MNT_RDONLY
;
297 else if (mp
->mnt_flag
& MNT_RDONLY
)
298 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
299 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
300 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
301 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
302 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
303 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
304 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
306 * Mount the filesystem.
308 error
= VFS_MOUNT(mp
, uap
->path
, uap
->data
, &nd
, p
);
310 if (uap
->flags
& MNT_UPDATE
) {
312 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
313 mp
->mnt_flag
&= ~MNT_RDONLY
;
315 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
316 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
325 /* get the vnode lock */
326 err2
= vn_lock(vp
, LK_EXCLUSIVE
|LK_RETRY
, p
);
329 * Put the new filesystem on the mount list after root.
332 if (!error
&& !err2
) {
333 simple_lock(&vp
->v_interlock
);
334 CLR(vp
->v_flag
, VMOUNT
);
335 vp
->v_mountedhere
=mp
;
336 simple_unlock(&vp
->v_interlock
);
337 simple_lock(&mountlist_slock
);
339 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
340 simple_unlock(&mountlist_slock
);
342 VOP_UNLOCK(vp
, 0, p
);
344 if (error
= VFS_START(mp
, 0, p
))
347 /* increment the operations count */
353 simple_lock(&vp
->v_interlock
);
354 CLR(vp
->v_flag
, VMOUNT
);
355 simple_unlock(&vp
->v_interlock
);
356 mp
->mnt_vfc
->vfc_refcount
--;
358 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
373 struct nameidata qnd
;
375 char qfpath
[MAXPATHLEN
];
376 char *qfname
= QUOTAFILENAME
;
377 char *qfopsname
= QUOTAOPSNAME
;
378 char *qfextension
[] = INITQFNAMES
;
381 if ((strcmp(mp
->mnt_stat
.f_fstypename
, "hfs") != 0 )
382 && (strcmp( mp
->mnt_stat
.f_fstypename
, "ufs") != 0))
386 * Enable filesystem disk quotas if necessary.
387 * We ignore errors as this should not interfere with final mount
389 for (type
=0; type
< MAXQUOTAS
; type
++) {
390 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfopsname
, qfextension
[type
]);
391 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, qfpath
, p
);
392 if (namei(&qnd
) != 0)
393 continue; /* option file to trigger quotas is not present */
395 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfname
, qfextension
[type
]);
396 if (vp
->v_tag
== VT_HFS
) {
398 (void)hfs_quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
399 } else if (vp
->v_tag
== VT_UFS
) {
401 (void)quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
410 * Scan all active processes to see if any of them have a current
411 * or root directory onto which the new filesystem has just been
412 * mounted. If so, replace them with the new mount point.
418 struct filedesc
*fdp
;
423 if (olddp
->v_usecount
== 1)
425 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
426 panic("mount: lost mount");
427 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
429 if (fdp
->fd_cdir
== olddp
) {
432 fdp
->fd_cdir
= newdp
;
435 if (fdp
->fd_rdir
== olddp
) {
438 fdp
->fd_rdir
= newdp
;
442 if (rootvnode
== olddp
) {
452 * Unmount a file system.
454 * Note: unmount takes a path to the vnode mounted on as argument,
455 * not special file (as before).
457 struct unmount_args
{
463 unmount(p
, uap
, retval
)
465 register struct unmount_args
*uap
;
468 register struct vnode
*vp
;
473 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
475 if (error
= namei(&nd
))
481 * Only root, or the user that did the original mount is
482 * permitted to unmount this filesystem.
484 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
485 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
491 * Don't allow unmounting the root file system.
493 if (mp
->mnt_flag
& MNT_ROOTFS
) {
495 return (EBUSY
); /* the root is always busy */
499 * Must be the root of the filesystem
501 if ((vp
->v_flag
& VROOT
) == 0) {
506 return (dounmount(mp
, uap
->flags
, p
));
510 * Do the actual file system unmount.
513 dounmount(mp
, flags
, p
)
514 register struct mount
*mp
;
518 struct vnode
*coveredvp
;
521 simple_lock(&mountlist_slock
);
522 /* XXX post jaguar fix LK_DRAIN - then clean this up */
523 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
524 simple_unlock(&mountlist_slock
);
525 mp
->mnt_kern_flag
|= MNTK_MWAIT
;
526 if ((error
= tsleep((void *)mp
, PRIBIO
, "dounmount", 0)))
529 * The prior unmount attempt has probably succeeded.
530 * Do not dereference mp here - returning EBUSY is safest.
534 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
535 error
= lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
,
536 &mountlist_slock
, p
);
538 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
541 mp
->mnt_flag
&=~ MNT_ASYNC
;
542 ubc_umount(mp
); /* release cached vnodes */
543 cache_purgevfs(mp
); /* remove cache entries for this file sys */
544 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
545 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
547 error
= VFS_UNMOUNT(mp
, flags
, p
);
548 simple_lock(&mountlist_slock
);
550 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
551 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
552 &mountlist_slock
, p
);
556 /* increment the operations count */
560 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
561 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
562 coveredvp
->v_mountedhere
= (struct mount
*)0;
563 simple_unlock(&mountlist_slock
);
565 simple_lock(&mountlist_slock
);
567 mp
->mnt_vfc
->vfc_refcount
--;
568 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
569 panic("unmount: dangling vnode");
571 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
573 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
576 _FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
581 * Sync each mounted filesystem.
585 struct ctldebug debug0
= { "syncprt", &syncprt
};
591 int print_vmpage_stat
=0;
597 struct sync_args
*uap
;
600 register struct mount
*mp
, *nmp
;
603 simple_lock(&mountlist_slock
);
604 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
605 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
606 nmp
= mp
->mnt_list
.cqe_next
;
609 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
610 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
611 mp
->mnt_flag
&= ~MNT_ASYNC
;
612 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
614 mp
->mnt_flag
|= MNT_ASYNC
;
616 simple_lock(&mountlist_slock
);
617 nmp
= mp
->mnt_list
.cqe_next
;
620 simple_unlock(&mountlist_slock
);
623 extern void vm_countdirtypages(void);
624 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
625 extern unsigned int dp_pgins
, dp_pgouts
;
626 if(print_vmpage_stat
) {
627 vm_countdirtypages();
628 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
629 dp_pgins
, dp_pgouts
);
635 #endif /* DIAGNOSTIC */
640 * Change filesystem quotas.
642 struct quotactl_args
{
650 quotactl(p
, uap
, retval
)
652 register struct quotactl_args
*uap
;
655 register struct mount
*mp
;
659 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
660 if (error
= namei(&nd
))
662 mp
= nd
.ni_vp
->v_mount
;
664 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
669 * Get filesystem statistics.
677 statfs(p
, uap
, retval
)
679 register struct statfs_args
*uap
;
682 register struct mount
*mp
;
683 register struct statfs
*sp
;
687 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
688 if (error
= namei(&nd
))
690 mp
= nd
.ni_vp
->v_mount
;
693 if (error
= VFS_STATFS(mp
, sp
, p
))
695 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
696 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
697 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
701 * Get filesystem statistics.
703 struct fstatfs_args
{
709 fstatfs(p
, uap
, retval
)
711 register struct fstatfs_args
*uap
;
716 register struct statfs
*sp
;
719 if (error
= getvnode(p
, uap
->fd
, &fp
))
721 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
725 if (error
= VFS_STATFS(mp
, sp
, p
))
727 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
728 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
729 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
733 * Get statistics on all filesystems.
735 struct getfsstat_args
{
741 getfsstat(p
, uap
, retval
)
743 register struct getfsstat_args
*uap
;
746 register struct mount
*mp
, *nmp
;
747 register struct statfs
*sp
;
749 long count
, maxcount
, error
;
751 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
752 sfsp
= (caddr_t
)uap
->buf
;
754 simple_lock(&mountlist_slock
);
755 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
756 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
757 nmp
= mp
->mnt_list
.cqe_next
;
760 if (sfsp
&& count
< maxcount
) {
763 * If MNT_NOWAIT is specified, do not refresh the
764 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
766 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
767 (uap
->flags
& MNT_WAIT
)) &&
768 (error
= VFS_STATFS(mp
, sp
, p
))) {
769 simple_lock(&mountlist_slock
);
770 nmp
= mp
->mnt_list
.cqe_next
;
774 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
775 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
)))
780 simple_lock(&mountlist_slock
);
781 nmp
= mp
->mnt_list
.cqe_next
;
784 simple_unlock(&mountlist_slock
);
785 if (sfsp
&& count
> maxcount
)
793 ogetfsstat(p
, uap
, retval
)
795 register struct getfsstat_args
*uap
;
798 register struct mount
*mp
, *nmp
;
799 register struct statfs
*sp
;
801 long count
, maxcount
, error
;
803 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
804 sfsp
= (caddr_t
)uap
->buf
;
806 simple_lock(&mountlist_slock
);
807 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
808 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
809 nmp
= mp
->mnt_list
.cqe_next
;
812 if (sfsp
&& count
< maxcount
) {
815 * If MNT_NOWAIT is specified, do not refresh the
816 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
818 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
819 (uap
->flags
& MNT_WAIT
)) &&
820 (error
= VFS_STATFS(mp
, sp
, p
))) {
821 simple_lock(&mountlist_slock
);
822 nmp
= mp
->mnt_list
.cqe_next
;
826 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
827 error
= copyout((caddr_t
)sp
, sfsp
,
828 sizeof(*sp
) - sizeof(sp
->f_reserved3
) - sizeof(sp
->f_reserved4
));
831 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
834 simple_lock(&mountlist_slock
);
835 nmp
= mp
->mnt_list
.cqe_next
;
838 simple_unlock(&mountlist_slock
);
839 if (sfsp
&& count
> maxcount
)
848 * Change current working directory to a given file descriptor.
855 fchdir(p
, uap
, retval
)
857 struct fchdir_args
*uap
;
860 register struct filedesc
*fdp
= p
->p_fd
;
861 struct vnode
*vp
, *tdp
, *tvp
;
866 if (error
= getvnode(p
, uap
->fd
, &fp
))
868 vp
= (struct vnode
*)fp
->f_data
;
870 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
871 if (vp
->v_type
!= VDIR
)
874 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
875 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
876 if (vfs_busy(mp
, 0, 0, p
))
878 error
= VFS_ROOT(mp
, &tdp
);
889 VOP_UNLOCK(vp
, 0, p
);
897 * Change current working directory (``.'').
904 chdir(p
, uap
, retval
)
906 struct chdir_args
*uap
;
909 register struct filedesc
*fdp
= p
->p_fd
;
914 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
916 if (error
= change_dir(&nd
, p
))
919 fdp
->fd_cdir
= nd
.ni_vp
;
925 * Change notion of root (``/'') directory.
932 chroot(p
, uap
, retval
)
934 struct chroot_args
*uap
;
937 register struct filedesc
*fdp
= p
->p_fd
;
940 boolean_t shared_regions_active
;
943 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
946 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
948 if (error
= change_dir(&nd
, p
))
951 if(p
->p_flag
& P_NOSHLIB
) {
952 shared_regions_active
= FALSE
;
954 shared_regions_active
= TRUE
;
957 if(error
= clone_system_shared_regions(shared_regions_active
)) {
963 fdp
->fd_rdir
= nd
.ni_vp
;
970 * Common routine for chroot and chdir.
974 register struct nameidata
*ndp
;
980 if (error
= namei(ndp
))
983 if (vp
->v_type
!= VDIR
)
986 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
990 VOP_UNLOCK(vp
, 0, p
);
995 * Check permissions, allocate an open file structure,
996 * and call the device open routine if any.
1004 open(p
, uap
, retval
)
1006 register struct open_args
*uap
;
1009 register struct filedesc
*fdp
= p
->p_fd
;
1010 register struct file
*fp
;
1011 register struct vnode
*vp
;
1012 int flags
, cmode
, oflags
;
1014 int type
, indx
, error
;
1016 struct nameidata nd
;
1017 extern struct fileops vnops
;
1019 oflags
= uap
->flags
;
1020 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1022 flags
= FFLAGS(uap
->flags
);
1023 if (error
= falloc(p
, &nfp
, &indx
))
1026 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
1027 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1028 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1029 if (error
= vn_open(&nd
, flags
, cmode
)) {
1031 if ((error
== ENODEV
|| error
== ENXIO
) &&
1032 p
->p_dupfd
>= 0 && /* XXX from fdopen */
1034 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1038 if (error
== ERESTART
)
1045 fp
->f_flag
= flags
& FMASK
;
1046 fp
->f_type
= DTYPE_VNODE
;
1048 fp
->f_data
= (caddr_t
)vp
;
1049 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1050 lf
.l_whence
= SEEK_SET
;
1053 if (flags
& O_EXLOCK
)
1054 lf
.l_type
= F_WRLCK
;
1056 lf
.l_type
= F_RDLCK
;
1058 if ((flags
& FNONBLOCK
) == 0)
1060 VOP_UNLOCK(vp
, 0, p
);
1061 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
)) {
1062 (void) vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
1067 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1068 fp
->f_flag
|= FHASLOCK
;
1070 VOP_UNLOCK(vp
, 0, p
);
1071 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1080 struct ocreat_args
{
1085 ocreat(p
, uap
, retval
)
1087 register struct ocreat_args
*uap
;
1090 struct open_args nuap
;
1092 nuap
.path
= uap
->path
;
1093 nuap
.mode
= uap
->mode
;
1094 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1095 return (open(p
, &nuap
, retval
));
1097 #endif /* COMPAT_43 */
1100 * Create a special file.
1109 mknod(p
, uap
, retval
)
1111 register struct mknod_args
*uap
;
1114 register struct vnode
*vp
;
1118 struct nameidata nd
;
1120 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1123 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1124 if (error
= namei(&nd
))
1131 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1132 vattr
.va_rdev
= uap
->dev
;
1135 switch (uap
->mode
& S_IFMT
) {
1136 case S_IFMT
: /* used by badsect to flag bad sectors */
1137 vattr
.va_type
= VBAD
;
1140 vattr
.va_type
= VCHR
;
1143 vattr
.va_type
= VBLK
;
1154 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1156 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1158 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1161 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1162 &nd
.ni_cnd
, &vattr
);
1165 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1166 if (nd
.ni_dvp
== vp
)
1177 * Create a named pipe.
1179 struct mkfifo_args
{
1185 mkfifo(p
, uap
, retval
)
1187 register struct mkfifo_args
*uap
;
1192 struct nameidata nd
;
1195 return (EOPNOTSUPP
);
1198 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1199 if (error
= namei(&nd
))
1201 if (nd
.ni_vp
!= NULL
) {
1202 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1203 if (nd
.ni_dvp
== nd
.ni_vp
)
1211 vattr
.va_type
= VFIFO
;
1212 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1213 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1214 return (VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
));
1219 * Make a hard file link.
1227 link(p
, uap
, retval
)
1229 register struct link_args
*uap
;
1232 register struct vnode
*vp
;
1233 struct nameidata nd
;
1237 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1238 if (error
= namei(&nd
))
1241 if (vp
->v_type
== VDIR
)
1242 error
= EPERM
; /* POSIX */
1244 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1245 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
1246 nd
.ni_dirp
= uap
->link
;
1247 if ((error
= namei(&nd
)) == 0) {
1248 if (nd
.ni_vp
!= NULL
)
1251 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1253 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1254 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1256 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1257 if (nd
.ni_dvp
== nd
.ni_vp
)
1271 * Make a symbolic link.
1273 struct symlink_args
{
1279 symlink(p
, uap
, retval
)
1281 register struct symlink_args
*uap
;
1287 struct nameidata nd
;
1289 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1290 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1293 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->link
, p
);
1294 if (error
= namei(&nd
))
1297 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1298 if (nd
.ni_dvp
== nd
.ni_vp
)
1307 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1308 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1309 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1311 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1316 * Delete a whiteout from the filesystem.
1318 struct undelete_args
{
1323 undelete(p
, uap
, retval
)
1325 register struct undelete_args
*uap
;
1329 struct nameidata nd
;
1332 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
, UIO_USERSPACE
,
1338 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1339 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1340 if (nd
.ni_dvp
== nd
.ni_vp
)
1349 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1350 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1351 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1357 * Delete a name from the filesystem.
1359 struct unlink_args
{
1364 _unlink(p
, uap
, retval
, nodelbusy
)
1366 struct unlink_args
*uap
;
1370 register struct vnode
*vp
;
1372 struct nameidata nd
;
1375 NDINIT(&nd
, DELETE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
1376 /* with Carbon semantics, busy files cannot be deleted */
1378 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1379 if (error
= namei(&nd
))
1382 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1383 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1385 if (vp
->v_type
== VDIR
)
1386 error
= EPERM
; /* POSIX */
1389 * The root of a mounted filesystem cannot be deleted.
1391 * XXX: can this only be a VDIR case?
1393 if (vp
->v_flag
& VROOT
)
1398 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1399 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1401 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1402 if (nd
.ni_dvp
== vp
)
1413 * Delete a name from the filesystem using POSIX semantics.
1416 unlink(p
, uap
, retval
)
1418 struct unlink_args
*uap
;
1421 return _unlink(p
, uap
, retval
, 0);
1425 * Delete a name from the filesystem using Carbon semantics.
1428 delete(p
, uap
, retval
)
1430 struct unlink_args
*uap
;
1433 return _unlink(p
, uap
, retval
, 1);
1437 * Reposition read/write file offset.
1441 #ifdef DOUBLE_ALIGN_PARAMS
1448 lseek(p
, uap
, retval
)
1450 register struct lseek_args
*uap
;
1453 struct ucred
*cred
= p
->p_ucred
;
1458 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1460 if (fp
->f_type
!= DTYPE_VNODE
)
1462 switch (uap
->whence
) {
1464 fp
->f_offset
+= uap
->offset
;
1468 VOP_GETATTR((struct vnode
*)fp
->f_data
, &vattr
, cred
, p
))
1470 fp
->f_offset
= uap
->offset
+ vattr
.va_size
;
1473 fp
->f_offset
= uap
->offset
;
1478 *(off_t
*)retval
= fp
->f_offset
;
1484 * Reposition read/write file offset.
1486 struct olseek_args
{
1492 olseek(p
, uap
, retval
)
1494 register struct olseek_args
*uap
;
1497 struct lseek_args
/* {
1499 #ifdef DOUBLE_ALIGN_PARAMS
1500 syscallarg(int) pad;
1502 syscallarg(off_t) offset;
1503 syscallarg(int) whence;
1509 nuap
.offset
= uap
->offset
;
1510 nuap
.whence
= uap
->whence
;
1511 error
= lseek(p
, &nuap
, &qret
);
1512 *(long *)retval
= qret
;
1515 #endif /* COMPAT_43 */
1518 * Check access permissions.
1520 struct access_args
{
1525 access(p
, uap
, retval
)
1527 register struct access_args
*uap
;
1530 register struct ucred
*cred
= p
->p_ucred
;
1531 register struct vnode
*vp
;
1532 int error
, flags
, t_gid
, t_uid
;
1533 struct nameidata nd
;
1535 t_uid
= cred
->cr_uid
;
1536 t_gid
= cred
->cr_groups
[0];
1537 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1538 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1539 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1541 if (error
= namei(&nd
))
1545 /* Flags == 0 means only check for existence. */
1548 if (uap
->flags
& R_OK
)
1550 if (uap
->flags
& W_OK
)
1552 if (uap
->flags
& X_OK
)
1554 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1555 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1559 cred
->cr_uid
= t_uid
;
1560 cred
->cr_groups
[0] = t_gid
;
1566 * Get file status; this version follows links.
1574 ostat(p
, uap
, retval
)
1576 register struct ostat_args
*uap
;
1582 struct nameidata nd
;
1584 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1586 if (error
= namei(&nd
))
1588 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1593 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1598 * Get file status; this version does not follow links.
1600 struct olstat_args
{
1606 olstat(p
, uap
, retval
)
1608 register struct olstat_args
*uap
;
1611 struct vnode
*vp
, *dvp
;
1612 struct stat sb
, sb1
;
1615 struct nameidata nd
;
1617 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1619 if (error
= namei(&nd
))
1622 * For symbolic links, always return the attributes of its
1623 * containing directory, except for mode, size, and links.
1627 if (vp
->v_type
!= VLNK
) {
1632 error
= vn_stat(vp
, &sb
, p
);
1637 error
= vn_stat(dvp
, &sb
, p
);
1643 error
= vn_stat(vp
, &sb1
, p
);
1647 sb
.st_mode
&= ~S_IFDIR
;
1648 sb
.st_mode
|= S_IFLNK
;
1649 sb
.st_nlink
= sb1
.st_nlink
;
1650 sb
.st_size
= sb1
.st_size
;
1651 sb
.st_blocks
= sb1
.st_blocks
;
1654 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1659 * Convert from an old to a new stat structure.
1667 ost
->st_dev
= st
->st_dev
;
1668 ost
->st_ino
= st
->st_ino
;
1669 ost
->st_mode
= st
->st_mode
;
1670 ost
->st_nlink
= st
->st_nlink
;
1671 ost
->st_uid
= st
->st_uid
;
1672 ost
->st_gid
= st
->st_gid
;
1673 ost
->st_rdev
= st
->st_rdev
;
1674 if (st
->st_size
< (quad_t
)1 << 32)
1675 ost
->st_size
= st
->st_size
;
1678 ost
->st_atime
= st
->st_atime
;
1679 ost
->st_mtime
= st
->st_mtime
;
1680 ost
->st_ctime
= st
->st_ctime
;
1681 ost
->st_blksize
= st
->st_blksize
;
1682 ost
->st_blocks
= st
->st_blocks
;
1683 ost
->st_flags
= st
->st_flags
;
1684 ost
->st_gen
= st
->st_gen
;
1686 #endif /* COMPAT_43 */
1689 * Get file status; this version follows links.
1697 stat(p
, uap
, retval
)
1699 register struct stat_args
*uap
;
1704 struct nameidata nd
;
1706 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1708 if (error
= namei(&nd
))
1710 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1714 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1719 * Get file status; this version does not follow links.
1727 lstat(p
, uap
, retval
)
1729 register struct lstat_args
*uap
;
1733 struct vnode
*vp
, *dvp
;
1734 struct stat sb
, sb1
;
1735 struct nameidata nd
;
1737 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1739 if (error
= namei(&nd
))
1742 * For symbolic links, always return the attributes of its containing
1743 * directory, except for mode, size, inode number, and links.
1747 if ((vp
->v_type
!= VLNK
) || ((vp
->v_type
== VLNK
) && (vp
->v_tag
== VT_NFS
))) {
1752 error
= vn_stat(vp
, &sb
, p
);
1756 if (vp
->v_type
== VLNK
)
1757 sb
.st_mode
|= S_IFLNK
;
1759 error
= vn_stat(dvp
, &sb
, p
);
1765 error
= vn_stat(vp
, &sb1
, p
);
1769 sb
.st_mode
&= ~S_IFDIR
;
1770 sb
.st_mode
|= S_IFLNK
;
1771 sb
.st_nlink
= sb1
.st_nlink
;
1772 sb
.st_size
= sb1
.st_size
;
1773 sb
.st_blocks
= sb1
.st_blocks
;
1774 sb
.st_ino
= sb1
.st_ino
;
1776 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, sizeof (sb
));
1781 * Get configurable pathname variables.
1783 struct pathconf_args
{
1789 pathconf(p
, uap
, retval
)
1791 register struct pathconf_args
*uap
;
1795 struct nameidata nd
;
1797 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1799 if (error
= namei(&nd
))
1801 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1807 * Return target name of a symbolic link.
1809 struct readlink_args
{
1816 readlink(p
, uap
, retval
)
1818 register struct readlink_args
*uap
;
1821 register struct vnode
*vp
;
1825 struct nameidata nd
;
1827 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1829 if (error
= namei(&nd
))
1832 if (vp
->v_type
!= VLNK
)
1835 aiov
.iov_base
= uap
->buf
;
1836 aiov
.iov_len
= uap
->count
;
1837 auio
.uio_iov
= &aiov
;
1838 auio
.uio_iovcnt
= 1;
1839 auio
.uio_offset
= 0;
1840 auio
.uio_rw
= UIO_READ
;
1841 auio
.uio_segflg
= UIO_USERSPACE
;
1843 auio
.uio_resid
= uap
->count
;
1844 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
1847 *retval
= uap
->count
- auio
.uio_resid
;
1852 * Change flags of a file given a path name.
1854 struct chflags_args
{
1860 chflags(p
, uap
, retval
)
1862 register struct chflags_args
*uap
;
1865 register struct vnode
*vp
;
1868 struct nameidata nd
;
1870 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1871 if (error
= namei(&nd
))
1874 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1875 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1877 vattr
.va_flags
= uap
->flags
;
1878 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1884 * Change flags of a file given a file descriptor.
1886 struct fchflags_args
{
1892 fchflags(p
, uap
, retval
)
1894 register struct fchflags_args
*uap
;
1902 if (error
= getvnode(p
, uap
->fd
, &fp
))
1904 vp
= (struct vnode
*)fp
->f_data
;
1905 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1906 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1908 vattr
.va_flags
= uap
->flags
;
1909 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1910 VOP_UNLOCK(vp
, 0, p
);
1915 * Change mode of a file given path name.
1923 chmod(p
, uap
, retval
)
1925 register struct chmod_args
*uap
;
1928 register struct vnode
*vp
;
1931 struct nameidata nd
;
1933 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1934 if (error
= namei(&nd
))
1937 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1938 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1940 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1941 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1947 * Change mode of a file given a file descriptor.
1949 struct fchmod_args
{
1955 fchmod(p
, uap
, retval
)
1957 register struct fchmod_args
*uap
;
1965 if (error
= getvnode(p
, uap
->fd
, &fp
))
1967 vp
= (struct vnode
*)fp
->f_data
;
1968 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1969 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1971 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
1972 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
1973 VOP_UNLOCK(vp
, 0, p
);
1978 * Set ownership given a path name.
1987 chown(p
, uap
, retval
)
1989 register struct chown_args
*uap
;
1992 register struct vnode
*vp
;
1995 struct nameidata nd
;
1997 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1998 if (error
= namei(&nd
))
2003 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2004 * by looking for chown() calls on /dev/console from a console process.
2006 if ((vp
) && (vp
->v_specinfo
) &&
2007 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2008 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2009 console_user
= uap
->uid
;
2012 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2013 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2015 vattr
.va_uid
= uap
->uid
;
2016 vattr
.va_gid
= uap
->gid
;
2017 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2023 * Set ownership given a file descriptor.
2025 struct fchown_args
{
2032 fchown(p
, uap
, retval
)
2034 register struct fchown_args
*uap
;
2042 if (error
= getvnode(p
, uap
->fd
, &fp
))
2044 vp
= (struct vnode
*)fp
->f_data
;
2045 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2046 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2048 vattr
.va_uid
= uap
->uid
;
2049 vattr
.va_gid
= uap
->gid
;
2050 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2051 VOP_UNLOCK(vp
, 0, p
);
2056 getutimes(usrtvp
, tsp
)
2057 const struct timeval
*usrtvp
;
2058 struct timespec
*tsp
;
2060 struct timeval tv
[2];
2063 if (usrtvp
== NULL
) {
2065 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2068 if ((error
= copyin(usrtvp
, tv
, sizeof (tv
))) != 0)
2070 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2071 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
2077 setutimes(p
, vp
, ts
, nullflag
)
2080 const struct timespec
*ts
;
2086 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2087 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2091 vattr
.va_atime
= ts
[0];
2092 vattr
.va_mtime
= ts
[1];
2094 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
2095 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2096 VOP_UNLOCK(vp
, 0, p
);
2102 * Set the access and modification times of a file.
2104 struct utimes_args
{
2106 struct timeval
*tptr
;
2110 utimes(p
, uap
, retval
)
2112 register struct utimes_args
*uap
;
2115 struct timespec ts
[2];
2116 struct timeval
*usrtvp
;
2118 struct nameidata nd
;
2121 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2123 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2124 if ((error
= namei(&nd
)) != 0)
2126 error
= setutimes(p
, nd
.ni_vp
, ts
, usrtvp
== NULL
);
2132 * Set the access and modification times of a file.
2134 struct futimes_args
{
2136 struct timeval
*tptr
;
2140 futimes(p
, uap
, retval
)
2142 register struct futimes_args
*uap
;
2145 struct timespec ts
[2];
2147 struct timeval
*usrtvp
;
2151 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2153 if ((error
= getvnode(p
, uap
->fd
, &fp
)) != 0)
2155 return setutimes(p
, (struct vnode
*)fp
->f_data
, ts
, usrtvp
== NULL
);
2159 * Truncate a file given its path name.
2161 struct truncate_args
{
2163 #ifdef DOUBLE_ALIGN_PARAMS
2170 truncate(p
, uap
, retval
)
2172 register struct truncate_args
*uap
;
2175 register struct vnode
*vp
;
2178 struct nameidata nd
;
2180 if (uap
->length
< 0)
2182 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
2183 if (error
= namei(&nd
))
2186 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2187 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2188 if (vp
->v_type
== VDIR
)
2190 else if ((error
= vn_writechk(vp
)) == 0 &&
2191 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2193 vattr
.va_size
= uap
->length
;
2194 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2201 * Truncate a file given a file descriptor.
2203 struct ftruncate_args
{
2205 #ifdef DOUBLE_ALIGN_PARAMS
2212 ftruncate(p
, uap
, retval
)
2214 register struct ftruncate_args
*uap
;
2222 if (uap
->length
< 0)
2225 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2228 if (fp
->f_type
== DTYPE_PSXSHM
) {
2229 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2231 if (fp
->f_type
!= DTYPE_VNODE
)
2234 if ((fp
->f_flag
& FWRITE
) == 0)
2236 vp
= (struct vnode
*)fp
->f_data
;
2237 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2238 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2239 if (vp
->v_type
== VDIR
)
2241 else if ((error
= vn_writechk(vp
)) == 0) {
2243 vattr
.va_size
= uap
->length
;
2244 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2246 VOP_UNLOCK(vp
, 0, p
);
2252 * Truncate a file given its path name.
2254 struct otruncate_args
{
2260 otruncate(p
, uap
, retval
)
2262 register struct otruncate_args
*uap
;
2265 struct truncate_args
/* {
2266 syscallarg(char *) path;
2267 #ifdef DOUBLE_ALIGN_PARAMS
2268 syscallarg(int) pad;
2270 syscallarg(off_t) length;
2273 nuap
.path
= uap
->path
;
2274 nuap
.length
= uap
->length
;
2275 return (truncate(p
, &nuap
, retval
));
2279 * Truncate a file given a file descriptor.
2281 struct oftruncate_args
{
2287 oftruncate(p
, uap
, retval
)
2289 register struct oftruncate_args
*uap
;
2292 struct ftruncate_args
/* {
2294 #ifdef DOUBLE_ALIGN_PARAMS
2295 syscallarg(int) pad;
2297 syscallarg(off_t) length;
2301 nuap
.length
= uap
->length
;
2302 return (ftruncate(p
, &nuap
, retval
));
2304 #endif /* COMPAT_43 */
2307 * Sync an open file.
2314 fsync(p
, uap
, retval
)
2316 struct fsync_args
*uap
;
2319 register struct vnode
*vp
;
2323 if (error
= getvnode(p
, uap
->fd
, &fp
))
2325 vp
= (struct vnode
*)fp
->f_data
;
2326 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2327 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2328 VOP_UNLOCK(vp
, 0, p
);
2333 * Duplicate files. Source must be a file, target must be a file or
2337 struct copyfile_args
{
2345 copyfile(p
, uap
, retval
)
2347 register struct copyfile_args
*uap
;
2350 register struct vnode
*tvp
, *fvp
, *tdvp
;
2351 register struct ucred
*cred
= p
->p_ucred
;
2352 struct nameidata fromnd
, tond
;
2355 /* Check that the flags are valid.
2358 if (uap
->flags
& ~CPF_MASK
) {
2362 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2364 if (error
= namei(&fromnd
))
2368 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2369 UIO_USERSPACE
, uap
->to
, p
);
2370 if (error
= namei(&tond
)) {
2377 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2383 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2388 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2394 * If source is the same as the destination (that is the
2395 * same inode number) then there is nothing to do.
2396 * (fixed to have POSIX semantics - CSM 3/2/98)
2402 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2404 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2413 vrele(tond
.ni_startdir
);
2414 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2416 if (fromnd
.ni_startdir
)
2417 vrele(fromnd
.ni_startdir
);
2418 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2425 * Rename files. Source and destination must either both be directories,
2426 * or both not be directories. If target is a directory, it must be empty.
2428 struct rename_args
{
2434 rename(p
, uap
, retval
)
2436 register struct rename_args
*uap
;
2439 register struct vnode
*tvp
, *fvp
, *tdvp
;
2440 struct nameidata fromnd
, tond
;
2443 int casesense
,casepres
;
2448 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
, UIO_USERSPACE
,
2450 if (error
= namei(&fromnd
))
2454 NDINIT(&tond
, RENAME
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2455 UIO_USERSPACE
, uap
->to
, p
);
2456 if (fromnd
.ni_vp
->v_type
== VDIR
)
2457 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2458 if (error
= namei(&tond
)) {
2459 /* Translate error code for rename("dir1", "dir2/."). */
2460 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
2462 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2463 vrele(fromnd
.ni_dvp
);
2471 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2474 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2482 * If source is the same as the destination (that is the
2483 * same inode number) then there is nothing to do... EXCEPT if the
2484 * underlying file system supports case insensitivity and is case
2485 * preserving. Then a special case is made, i.e. foo -> Foo.
2487 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2488 * and _PC_CASE_PRESERVING can have this exception, and they need to
2489 * handle the special case of getting the same vnode as target and
2490 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2491 * so not to cause locking problems. There is a single reference on tvp.
2493 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2494 * that correct behaviour then is just to remove the source (link)
2496 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
) {
2497 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2498 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2499 fromnd
.ni_cnd
.cn_namelen
)) {
2500 error
= -1; /* Default "unix" behavior */
2501 } else { /* probe for file system specifics */
2502 if (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
))
2504 if (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
))
2506 if (!casesense
&& casepres
)
2507 vput(tvp
); /* Unlock target and drop ref */
2512 * Allow the renaming of mount points.
2513 * - target must not exist
2514 * - target must reside in the same directory as source
2515 * - union mounts cannot be renamed
2516 * - "/" cannot be renamed
2519 (fvp
->v_flag
& VROOT
) &&
2520 (fvp
->v_type
== VDIR
) &&
2522 (fvp
->v_mountedhere
== NULL
) &&
2523 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2524 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2525 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2527 /* switch fvp to the covered vnode */
2528 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2536 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2537 if (fromnd
.ni_dvp
!= tdvp
)
2538 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2540 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2541 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2542 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2547 * update filesystem's mount point data
2550 char *cp
, *pathend
, *mpname
;
2557 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2558 mp
= fvp
->v_mountedhere
;
2560 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2565 VOP_UNLOCK(fvp
, 0, p
);
2567 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2568 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2570 /* find current mount point prefix */
2571 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2572 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2576 /* find last component of target name */
2577 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2581 /* append name to prefix */
2582 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2583 bzero(pathend
, maxlen
);
2584 strncpy(pathend
, mpname
, maxlen
- 1);
2586 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2592 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2599 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2600 vrele(fromnd
.ni_dvp
);
2604 vrele(tond
.ni_startdir
);
2605 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2607 if (fromnd
.ni_startdir
)
2608 vrele(fromnd
.ni_startdir
);
2609 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2616 * Make a directory file.
2624 mkdir(p
, uap
, retval
)
2626 register struct mkdir_args
*uap
;
2629 register struct vnode
*vp
;
2632 struct nameidata nd
;
2635 NDINIT(&nd
, CREATE
, LOCKPARENT
, UIO_USERSPACE
, uap
->path
, p
);
2636 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2637 if (error
= namei(&nd
))
2641 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2642 if (nd
.ni_dvp
== vp
)
2650 vattr
.va_type
= VDIR
;
2651 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2652 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2653 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2660 * Remove a directory file.
2667 rmdir(p
, uap
, retval
)
2669 struct rmdir_args
*uap
;
2672 register struct vnode
*vp
;
2674 struct nameidata nd
;
2677 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
, UIO_USERSPACE
,
2679 if (error
= namei(&nd
))
2682 if (vp
->v_type
!= VDIR
) {
2687 * No rmdir "." please.
2689 if (nd
.ni_dvp
== vp
) {
2694 * The root of a mounted filesystem cannot be deleted.
2696 if (vp
->v_flag
& VROOT
)
2700 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2701 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2702 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2704 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2705 if (nd
.ni_dvp
== vp
)
2716 * Read a block of directory entries in a file system independent format.
2718 struct ogetdirentries_args
{
2725 ogetdirentries(p
, uap
, retval
)
2727 register struct ogetdirentries_args
*uap
;
2730 register struct vnode
*vp
;
2732 struct uio auio
, kuio
;
2733 struct iovec aiov
, kiov
;
2734 struct dirent
*dp
, *edp
;
2736 int error
, eofflag
, readcnt
;
2739 if (error
= getvnode(p
, uap
->fd
, &fp
))
2741 if ((fp
->f_flag
& FREAD
) == 0)
2743 vp
= (struct vnode
*)fp
->f_data
;
2745 if (vp
->v_type
!= VDIR
)
2747 aiov
.iov_base
= uap
->buf
;
2748 aiov
.iov_len
= uap
->count
;
2749 auio
.uio_iov
= &aiov
;
2750 auio
.uio_iovcnt
= 1;
2751 auio
.uio_rw
= UIO_READ
;
2752 auio
.uio_segflg
= UIO_USERSPACE
;
2754 auio
.uio_resid
= uap
->count
;
2755 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2756 loff
= auio
.uio_offset
= fp
->f_offset
;
2757 # if (BYTE_ORDER != LITTLE_ENDIAN)
2758 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
2759 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2760 (int *)0, (u_long
*)0);
2761 fp
->f_offset
= auio
.uio_offset
;
2766 kuio
.uio_iov
= &kiov
;
2767 kuio
.uio_segflg
= UIO_SYSSPACE
;
2768 kiov
.iov_len
= uap
->count
;
2769 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
2770 kiov
.iov_base
= dirbuf
;
2771 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
2772 (int *)0, (u_long
*)0);
2773 fp
->f_offset
= kuio
.uio_offset
;
2775 readcnt
= uap
->count
- kuio
.uio_resid
;
2776 edp
= (struct dirent
*)&dirbuf
[readcnt
];
2777 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
2778 # if (BYTE_ORDER == LITTLE_ENDIAN)
2780 * The expected low byte of
2781 * dp->d_namlen is our dp->d_type.
2782 * The high MBZ byte of dp->d_namlen
2783 * is our dp->d_namlen.
2785 dp
->d_type
= dp
->d_namlen
;
2789 * The dp->d_type is the high byte
2790 * of the expected dp->d_namlen,
2791 * so must be zero'ed.
2795 if (dp
->d_reclen
> 0) {
2796 dp
= (struct dirent
*)
2797 ((char *)dp
+ dp
->d_reclen
);
2804 error
= uiomove(dirbuf
, readcnt
, &auio
);
2806 FREE(dirbuf
, M_TEMP
);
2808 VOP_UNLOCK(vp
, 0, p
);
2814 extern int (**union_vnodeop_p
)(void *);
2815 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2817 if ((uap
->count
== auio
.uio_resid
) &&
2818 (vp
->v_op
== union_vnodeop_p
)) {
2821 lvp
= union_dircache(vp
, p
);
2822 if (lvp
!= NULLVP
) {
2826 * If the directory is opaque,
2827 * then don't show lower entries
2829 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2830 if (va
.va_flags
& OPAQUE
) {
2836 if (lvp
!= NULLVP
) {
2837 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2842 VOP_UNLOCK(lvp
, 0, p
);
2843 fp
->f_data
= (caddr_t
) lvp
;
2845 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2856 if ((uap
->count
== auio
.uio_resid
) &&
2857 (vp
->v_flag
& VROOT
) &&
2858 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2859 struct vnode
*tvp
= vp
;
2860 vp
= vp
->v_mount
->mnt_vnodecovered
;
2862 fp
->f_data
= (caddr_t
) vp
;
2867 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2869 *retval
= uap
->count
- auio
.uio_resid
;
2872 #endif /* COMPAT_43 */
2875 * Read a block of directory entries in a file system independent format.
2877 struct getdirentries_args
{
2884 getdirentries(p
, uap
, retval
)
2886 register struct getdirentries_args
*uap
;
2889 register struct vnode
*vp
;
2896 if (error
= getvnode(p
, uap
->fd
, &fp
))
2898 if ((fp
->f_flag
& FREAD
) == 0)
2900 vp
= (struct vnode
*)fp
->f_data
;
2902 if (vp
->v_type
!= VDIR
)
2904 aiov
.iov_base
= uap
->buf
;
2905 aiov
.iov_len
= uap
->count
;
2906 auio
.uio_iov
= &aiov
;
2907 auio
.uio_iovcnt
= 1;
2908 auio
.uio_rw
= UIO_READ
;
2909 auio
.uio_segflg
= UIO_USERSPACE
;
2911 auio
.uio_resid
= uap
->count
;
2912 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2913 loff
= auio
.uio_offset
= fp
->f_offset
;
2914 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
2915 (int *)0, (u_long
*)0);
2916 fp
->f_offset
= auio
.uio_offset
;
2917 VOP_UNLOCK(vp
, 0, p
);
2923 extern int (**union_vnodeop_p
)(void *);
2924 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
2926 if ((uap
->count
== auio
.uio_resid
) &&
2927 (vp
->v_op
== union_vnodeop_p
)) {
2930 lvp
= union_dircache(vp
, p
);
2931 if (lvp
!= NULLVP
) {
2935 * If the directory is opaque,
2936 * then don't show lower entries
2938 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
2939 if (va
.va_flags
& OPAQUE
) {
2945 if (lvp
!= NULLVP
) {
2946 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
2951 VOP_UNLOCK(lvp
, 0, p
);
2952 fp
->f_data
= (caddr_t
) lvp
;
2954 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
2965 if ((uap
->count
== auio
.uio_resid
) &&
2966 (vp
->v_flag
& VROOT
) &&
2967 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
2968 struct vnode
*tvp
= vp
;
2969 vp
= vp
->v_mount
->mnt_vnodecovered
;
2971 fp
->f_data
= (caddr_t
) vp
;
2976 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
2978 *retval
= uap
->count
- auio
.uio_resid
;
2983 * Set the mode mask for creation of filesystem nodes.
2989 umask(p
, uap
, retval
)
2991 struct umask_args
*uap
;
2994 register struct filedesc
*fdp
;
2997 *retval
= fdp
->fd_cmask
;
2998 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
3003 * Void all references to file by ripping underlying filesystem
3006 struct revoke_args
{
3011 revoke(p
, uap
, retval
)
3013 register struct revoke_args
*uap
;
3016 register struct vnode
*vp
;
3019 struct nameidata nd
;
3021 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
3022 if (error
= namei(&nd
))
3025 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
3027 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
3028 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
3030 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
3031 VOP_REVOKE(vp
, REVOKEALL
);
3038 * Convert a user file descriptor to a kernel file entry.
3041 getvnode(p
, fd
, fpp
)
3049 if (error
= fdgetf(p
, fd
, &fp
))
3051 if (fp
->f_type
!= DTYPE_VNODE
)
3058 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3059 * The following system calls are designed to support features
3060 * which are specific to the HFS & HFS Plus volume formats
3063 #ifdef __APPLE_API_OBSOLETE
3065 /************************************************/
3066 /* *** Following calls will be deleted soon *** */
3067 /************************************************/
3070 * Make a complex file. A complex file is one with multiple forks (data streams)
3072 struct mkcomplex_args
{
3073 const char *path
; /* pathname of the file to be created */
3074 mode_t mode
; /* access mode for the newly created file */
3075 u_long type
; /* format of the complex file */
3079 mkcomplex(p
,uap
,retval
)
3081 register struct mkcomplex_args
*uap
;
3087 struct nameidata nd
;
3089 /* mkcomplex wants the directory vnode locked so do that here */
3091 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3092 if (error
= namei(&nd
))
3095 /* Set the attributes as specified by the user */
3098 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
3099 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
3101 /* The mkcomplex call promises to release the parent vnode pointer
3102 * even an an error case so don't do it here unless the operation
3103 * is not supported. In that case, there isn't anyone to unlock the parent
3104 * The vnode pointer to the file will also be released.
3109 if (error
== EOPNOTSUPP
)
3116 } /* end of mkcomplex system call */
3119 * Extended stat call which returns volumeid and vnodeid as well as other info
3122 const char *path
; /* pathname of the target file */
3123 struct vstat
*vsb
; /* vstat structure for returned info */
3129 register struct statv_args
*uap
;
3133 return (EOPNOTSUPP
); /* We'll just return an error for now */
3135 } /* end of statv system call */
3138 * Extended lstat call which returns volumeid and vnodeid as well as other info
3140 struct lstatv_args
{
3141 const char *path
; /* pathname of the target file */
3142 struct vstat
*vsb
; /* vstat structure for returned info */
3146 lstatv(p
,uap
,retval
)
3148 register struct lstatv_args
*uap
;
3152 return (EOPNOTSUPP
); /* We'll just return an error for now */
3153 } /* end of lstatv system call */
3156 * Extended fstat call which returns volumeid and vnodeid as well as other info
3158 struct fstatv_args
{
3159 int fd
; /* file descriptor of the target file */
3160 struct vstat
*vsb
; /* vstat structure for returned info */
3164 fstatv(p
,uap
,retval
)
3166 register struct fstatv_args
*uap
;
3170 return (EOPNOTSUPP
); /* We'll just return an error for now */
3171 } /* end of fstatv system call */
3174 /************************************************/
3175 /* *** Preceding calls will be deleted soon *** */
3176 /************************************************/
3178 #endif /* __APPLE_API_OBSOLETE */
3182 * Obtain attribute information about a file system object
3185 struct getattrlist_args
{
3186 const char *path
; /* pathname of the target object */
3187 struct attrlist
* alist
; /* Attributes desired by the user */
3188 void * attributeBuffer
; /* buffer to hold returned attributes */
3189 size_t bufferSize
; /* size of the return buffer */
3190 unsigned long options
; /* options (follow/don't follow) */
3194 getattrlist (p
,uap
,retval
)
3196 register struct getattrlist_args
*uap
;
3201 struct nameidata nd
;
3204 struct attrlist attributelist
;
3207 /* Get the attributes desire and do our parameter checking */
3209 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3210 sizeof (attributelist
)))
3215 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3217 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3218 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3219 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3220 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3221 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3228 /* Get the vnode for the file we are getting info on. */
3229 nameiflags
= LOCKLEAF
;
3230 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3231 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3233 if (error
= namei(&nd
))
3236 /* Set up the UIO structure for use by the vfs routine */
3239 aiov
.iov_base
= uap
->attributeBuffer
;
3240 aiov
.iov_len
= uap
->bufferSize
;
3241 auio
.uio_iov
= &aiov
;
3242 auio
.uio_iovcnt
= 1;
3243 auio
.uio_offset
= 0;
3244 auio
.uio_rw
= UIO_READ
;
3245 auio
.uio_segflg
= UIO_USERSPACE
;
3247 auio
.uio_resid
= uap
->bufferSize
;
3250 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3252 /* Unlock and release the vnode which will have been locked by namei */
3256 /* return the effort if we got one, otherwise return success */
3265 } /* end of getattrlist system call */
3270 * Set attribute information about a file system object
3273 struct setattrlist_args
{
3274 const char *path
; /* pathname of the target object */
3275 struct attrlist
* alist
; /* Attributes being set by the user */
3276 void * attributeBuffer
; /* buffer with attribute values to be set */
3277 size_t bufferSize
; /* size of the return buffer */
3278 unsigned long options
; /* options (follow/don't follow) */
3282 setattrlist (p
,uap
,retval
)
3284 register struct setattrlist_args
*uap
;
3289 struct nameidata nd
;
3292 struct attrlist alist
;
3295 /* Get the attributes desired and do our parameter checking */
3297 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3302 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3305 /* Get the vnode for the file whose attributes are being set. */
3306 nameiflags
= LOCKLEAF
;
3307 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3308 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3309 if (error
= namei(&nd
))
3312 /* Set up the UIO structure for use by the vfs routine */
3313 aiov
.iov_base
= uap
->attributeBuffer
;
3314 aiov
.iov_len
= uap
->bufferSize
;
3315 auio
.uio_iov
= &aiov
;
3316 auio
.uio_iovcnt
= 1;
3317 auio
.uio_offset
= 0;
3318 auio
.uio_rw
= UIO_WRITE
;
3319 auio
.uio_segflg
= UIO_USERSPACE
;
3321 auio
.uio_resid
= uap
->bufferSize
;
3323 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3329 } /* end of setattrlist system call */
3333 * Obtain attribute information on objects in a directory while enumerating
3334 * the directory. This call does not yet support union mounted directories.
3336 * 1.union mounted directories.
3339 struct getdirentriesattr_args
{
3340 int fd
; /* file descriptor */
3341 struct attrlist
*alist
; /* bit map of requested attributes */
3342 void *buffer
; /* buffer to hold returned attribute info */
3343 size_t buffersize
; /* size of the return buffer */
3344 u_long
*count
; /* the count of entries requested/returned */
3345 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3346 u_long
*newstate
; /* a flag to inform of changes in directory */
3347 u_long options
; /* maybe unused for now */
3351 getdirentriesattr (p
,uap
,retval
)
3353 register struct getdirentriesattr_args
*uap
;
3357 register struct vnode
*vp
;
3365 struct attrlist attributelist
;
3367 /* Get the attributes into kernel space */
3368 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3370 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3373 if (error
= getvnode(p
, uap
->fd
, &fp
))
3375 if ((fp
->f_flag
& FREAD
) == 0)
3377 vp
= (struct vnode
*)fp
->f_data
;
3379 if (vp
->v_type
!= VDIR
)
3382 /* set up the uio structure which will contain the users return buffer */
3383 aiov
.iov_base
= uap
->buffer
;
3384 aiov
.iov_len
= uap
->buffersize
;
3385 auio
.uio_iov
= &aiov
;
3386 auio
.uio_iovcnt
= 1;
3387 auio
.uio_rw
= UIO_READ
;
3388 auio
.uio_segflg
= UIO_USERSPACE
;
3390 auio
.uio_resid
= uap
->buffersize
;
3392 loff
= auio
.uio_offset
= fp
->f_offset
;
3393 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3394 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3395 actualcount
, uap
->options
, &newstate
, &eofflag
,
3396 &actualcount
, ((u_long
**)0), p
->p_cred
);
3398 VOP_UNLOCK(vp
, 0, p
);
3399 if (error
) return (error
);
3400 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3402 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3404 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3406 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3409 *retval
= eofflag
; /* similar to getdirentries */
3410 return (0); /* return error earlier, an retval of 0 or 1 now */
3412 } /* end of getdirentryattr system call */
3415 * Exchange data between two files
3418 struct exchangedata_args
{
3419 const char *path1
; /* pathname of the first swapee */
3420 const char *path2
; /* pathname of the second swapee */
3421 unsigned long options
; /* options */
3425 exchangedata (p
,uap
,retval
)
3427 register struct exchangedata_args
*uap
;
3432 struct nameidata fnd
, snd
;
3433 struct vnode
*fvp
, *svp
;
3438 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3440 /* Global lock, to prevent race condition, only one exchange at a time */
3441 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3443 NDINIT(&fnd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *) uap
->path1
, p
);
3445 if (error
= namei(&fnd
))
3450 NDINIT(&snd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path2
, p
);
3452 if (error
= namei(&snd
)) {
3459 /* if the files are the same, return an inval error */
3467 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3468 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3470 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3471 if (error
) goto out
;
3473 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3474 if (error
) goto out
;
3476 /* Ok, make the call */
3477 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3484 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3492 } /* end of exchangedata system call */
3494 #ifdef __APPLE_API_OBSOLETE
3496 /************************************************/
3497 /* *** Following calls will be deleted soon *** */
3498 /************************************************/
3501 * Check users access to a file
3504 struct checkuseraccess_args
{
3505 const char *path
; /* pathname of the target file */
3506 uid_t userid
; /* user for whom we are checking access */
3507 gid_t
*groups
; /* Group that we are checking for */
3508 int ngroups
; /* Number of groups being checked */
3509 int accessrequired
; /* needed access to the file */
3510 unsigned long options
; /* options */
3515 checkuseraccess (p
,uap
,retval
)
3517 register struct checkuseraccess_args
*uap
;
3521 register struct vnode
*vp
;
3523 struct nameidata nd
;
3525 int flags
; /*what will actually get passed to access*/
3528 /* Make sure that the number of groups is correct before we do anything */
3530 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3533 /* Verify that the caller is root */
3535 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3538 /* Fill in the credential structure */
3541 cred
.cr_uid
= uap
->userid
;
3542 cred
.cr_ngroups
= uap
->ngroups
;
3543 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3546 /* Get our hands on the file */
3548 nameiflags
= LOCKLEAF
;
3549 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3550 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3552 if (error
= namei(&nd
))
3556 /* Flags == 0 means only check for existence. */
3560 if (uap
->accessrequired
) {
3561 if (uap
->accessrequired
& R_OK
)
3563 if (uap
->accessrequired
& W_OK
)
3565 if (uap
->accessrequired
& X_OK
)
3568 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3577 } /* end of checkuseraccess system call */
3579 /************************************************/
3580 /* *** Preceding calls will be deleted soon *** */
3581 /************************************************/
3583 #endif /* __APPLE_API_OBSOLETE */
3587 struct searchfs_args
{
3589 struct fssearchblock
*searchblock
;
3593 struct searchstate
*state
;
3598 searchfs (p
,uap
,retval
)
3600 register struct searchfs_args
*uap
;
3604 register struct vnode
*vp
;
3607 struct nameidata nd
;
3608 struct fssearchblock searchblock
;
3609 struct searchstate
*state
;
3610 struct attrlist
*returnattrs
;
3611 void *searchparams1
,*searchparams2
;
3619 /* Start by copying in fsearchblock paramater list */
3621 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3624 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3625 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3626 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3629 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3630 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3632 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3634 /* Now set up the various pointers to the correct place in our newly allocated memory */
3636 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3637 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3638 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3640 /* Now copy in the stuff given our local variables. */
3642 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3645 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3648 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3651 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3654 /* set up the uio structure which will contain the users return buffer */
3656 aiov
.iov_base
= searchblock
.returnbuffer
;
3657 aiov
.iov_len
= searchblock
.returnbuffersize
;
3658 auio
.uio_iov
= &aiov
;
3659 auio
.uio_iovcnt
= 1;
3660 auio
.uio_rw
= UIO_READ
;
3661 auio
.uio_segflg
= UIO_USERSPACE
;
3663 auio
.uio_resid
= searchblock
.returnbuffersize
;
3665 nameiflags
= LOCKLEAF
;
3666 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3667 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3669 if (error
= namei(&nd
))
3676 * If searchblock.maxmatches == 0, then skip the search. This has happened
3677 * before and sometimes the underlyning code doesnt deal with it well.
3679 if (searchblock
.maxmatches
== 0) {
3685 Allright, we have everything we need, so lets make that call.
3687 We keep special track of the return value from the file system:
3688 EAGAIN is an acceptable error condition that shouldn't keep us
3689 from copying out any results...
3692 fserror
= VOP_SEARCHFS(vp
,
3695 &searchblock
.searchattrs
,
3696 searchblock
.maxmatches
,
3697 &searchblock
.timelimit
,
3709 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3710 search state. Everything was already put into he return buffer by the vop call. */
3712 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
3715 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
3722 FREE(searchparams1
,M_TEMP
);
3727 } /* end of searchfs system call */
3731 * Make a filesystem-specific control call:
3734 const char *path
; /* pathname of the target object */
3735 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
3736 caddr_t data
; /* pointer to argument buffer */
3737 u_long options
; /* options for fsctl processing */
3741 fsctl (p
,uap
,retval
)
3743 struct fsctl_args
*uap
;
3748 struct nameidata nd
;
3750 u_long cmd
= uap
->cmd
;
3751 register u_int size
;
3752 #define STK_PARAMS 128
3753 char stkbuf
[STK_PARAMS
];
3756 size
= IOCPARM_LEN(cmd
);
3757 if (size
> IOCPARM_MAX
) return (EINVAL
);
3760 if (size
> sizeof (stkbuf
)) {
3761 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
3769 error
= copyin(uap
->data
, data
, (u_int
)size
);
3770 if (error
) goto FSCtl_Exit
;
3772 *(caddr_t
*)data
= uap
->data
;
3774 } else if ((cmd
& IOC_OUT
) && size
) {
3776 * Zero the buffer so the user always
3777 * gets back something deterministic.
3780 } else if (cmd
& IOC_VOID
)
3781 *(caddr_t
*)data
= uap
->data
;
3783 /* Get the vnode for the file we are getting info on: */
3784 nameiflags
= LOCKLEAF
;
3785 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3786 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3787 if (error
= namei(&nd
)) goto FSCtl_Exit
;
3789 /* Invoke the filesystem-specific code */
3790 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
3795 * Copy any data to user, size was
3796 * already set and checked above.
3798 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
3801 if (memp
) kfree(memp
, size
);
3805 /* end of fsctl system call */
3808 * An in-kernel sync for power management to call.
3810 __private_extern__
int
3813 boolean_t funnel_state
;
3816 struct sync_args data
;
3820 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
3822 error
= sync(current_proc(), &data
, &retval
);
3824 thread_funnel_set(kernel_flock
, funnel_state
);
3827 } /* end of sync_internal call */