2 * Copyright (c) 1995-2003 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 <sys/kern_audit.h>
83 #include <sys/bsm_kevents.h>
84 #include <machine/cons.h>
85 #include <miscfs/specfs/specdev.h>
87 #include <architecture/byte_order.h>
89 struct lock__bsd__ exchangelock
;
92 * The currently logged-in user, for ownership of files/directories whose on-disk
93 * permissions are ignored:
97 static int change_dir
__P((struct nameidata
*ndp
, struct proc
*p
));
98 static void checkdirs
__P((struct vnode
*olddp
));
99 static void enablequotas
__P((struct proc
*p
, struct mount
*mp
));
101 /* counts number of mount and unmount operations */
102 unsigned int vfs_nummntops
=0;
105 * Virtual File System System Calls
109 * Mount a file system.
119 mount(p
, uap
, retval
)
121 register struct mount_args
*uap
;
126 struct vfsconf
*vfsp
;
127 int error
, flag
, err2
;
131 char fstypename
[MFSNAMELEN
];
134 AUDIT_ARG(fflags
, uap
->flags
);
137 * Get vnode to be covered
139 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
146 if ((vp
->v_flag
& VROOT
) &&
147 (vp
->v_mount
->mnt_flag
& MNT_ROOTFS
))
148 uap
->flags
|= MNT_UPDATE
;
150 if (uap
->flags
& MNT_UPDATE
) {
151 if ((vp
->v_flag
& VROOT
) == 0) {
157 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
162 * We only allow the filesystem to be reloaded if it
163 * is currently mounted read-only.
165 if ((uap
->flags
& MNT_RELOAD
) &&
166 ((mp
->mnt_flag
& MNT_RDONLY
) == 0)) {
169 return (EOPNOTSUPP
); /* Needs translation */
172 * Only root, or the user that did the original mount is
173 * permitted to update it.
175 if (mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
&&
176 (error
= suser(p
->p_ucred
, &p
->p_acflag
))) {
182 * Do not allow NFS export by non-root users. FOr non-root
183 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
184 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
186 if (p
->p_ucred
->cr_uid
!= 0) {
187 if (uap
->flags
& MNT_EXPORTED
) {
192 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
193 if (mp
->mnt_flag
& MNT_NOEXEC
)
194 uap
->flags
|= MNT_NOEXEC
;
199 uap
->flags
& (MNT_RELOAD
| MNT_FORCE
| MNT_UPDATE
);
201 VOP_UNLOCK(vp
, 0, p
);
206 * If the user is not root, ensure that they own the directory
207 * onto which we are attempting to mount.
209 if ((error
= VOP_GETATTR(vp
, &va
, p
->p_ucred
, p
)) ||
210 (va
.va_uid
!= p
->p_ucred
->cr_uid
&&
211 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))) {
216 * Do not allow NFS export by non-root users. FOr non-root
217 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
218 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
220 if (p
->p_ucred
->cr_uid
!= 0) {
221 if (uap
->flags
& MNT_EXPORTED
) {
225 uap
->flags
|= MNT_NOSUID
| MNT_NODEV
;
226 if (vp
->v_mount
->mnt_flag
& MNT_NOEXEC
)
227 uap
->flags
|= MNT_NOEXEC
;
229 if (error
= vinvalbuf(vp
, V_SAVE
, p
->p_ucred
, p
, 0, 0)) {
233 if (vp
->v_type
!= VDIR
) {
239 * Historically filesystem types were identified by number. If we
240 * get an integer for the filesystem type instead of a string, we
241 * check to see if it matches one of the historic filesystem types.
243 fstypenum
= (u_long
)uap
->type
;
244 if (fstypenum
< maxvfsconf
) {
245 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
246 if (vfsp
->vfc_typenum
== fstypenum
)
252 strncpy(fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
254 #endif /* COMPAT_43 */
255 if (error
= copyinstr(uap
->type
, fstypename
, MFSNAMELEN
, &dummy
)) {
259 /* XXXAUDIT: Should we capture the type on the error path as well? */
260 AUDIT_ARG(text
, fstypename
);
261 for (vfsp
= vfsconf
; vfsp
; vfsp
= vfsp
->vfc_next
)
262 if (!strcmp(vfsp
->vfc_name
, fstypename
))
268 simple_lock(&vp
->v_interlock
);
269 if (ISSET(vp
->v_flag
, VMOUNT
) && (vp
->v_mountedhere
!= NULL
)) {
270 simple_unlock(&vp
->v_interlock
);
274 SET(vp
->v_flag
, VMOUNT
);
275 simple_unlock(&vp
->v_interlock
);
278 * Allocate and initialize the filesystem.
280 MALLOC_ZONE(mp
, struct mount
*, (u_long
)sizeof(struct mount
),
282 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
284 /* Initialize the default IO constraints */
285 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
286 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
288 lockinit(&mp
->mnt_lock
, PVFS
, "vfslock", 0, 0);
289 (void)vfs_busy(mp
, LK_NOWAIT
, 0, p
);
290 mp
->mnt_op
= vfsp
->vfc_vfsops
;
292 vfsp
->vfc_refcount
++;
293 mp
->mnt_stat
.f_type
= vfsp
->vfc_typenum
;
294 mp
->mnt_flag
|= vfsp
->vfc_flags
& MNT_VISFLAGMASK
;
295 strncpy(mp
->mnt_stat
.f_fstypename
, vfsp
->vfc_name
, MFSNAMELEN
);
296 mp
->mnt_vnodecovered
= vp
;
297 mp
->mnt_stat
.f_owner
= p
->p_ucred
->cr_uid
;
298 VOP_UNLOCK(vp
, 0, p
);
302 * Set the mount level flags.
304 if (uap
->flags
& MNT_RDONLY
)
305 mp
->mnt_flag
|= MNT_RDONLY
;
306 else if (mp
->mnt_flag
& MNT_RDONLY
)
307 mp
->mnt_kern_flag
|= MNTK_WANTRDWR
;
308 mp
->mnt_flag
&= ~(MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
309 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
310 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
311 mp
->mnt_flag
|= uap
->flags
& (MNT_NOSUID
| MNT_NOEXEC
| MNT_NODEV
|
312 MNT_SYNCHRONOUS
| MNT_UNION
| MNT_ASYNC
|
313 MNT_UNKNOWNPERMISSIONS
| MNT_DONTBROWSE
| MNT_AUTOMOUNTED
);
315 * Mount the filesystem.
317 error
= VFS_MOUNT(mp
, uap
->path
, uap
->data
, &nd
, p
);
319 if (uap
->flags
& MNT_UPDATE
) {
321 if (mp
->mnt_kern_flag
& MNTK_WANTRDWR
)
322 mp
->mnt_flag
&= ~MNT_RDONLY
;
324 (MNT_UPDATE
| MNT_RELOAD
| MNT_FORCE
);
325 mp
->mnt_kern_flag
&=~ MNTK_WANTRDWR
;
334 /* get the vnode lock */
335 err2
= vn_lock(vp
, LK_EXCLUSIVE
|LK_RETRY
, p
);
338 * Put the new filesystem on the mount list after root.
341 if (!error
&& !err2
) {
342 simple_lock(&vp
->v_interlock
);
343 CLR(vp
->v_flag
, VMOUNT
);
344 vp
->v_mountedhere
=mp
;
345 simple_unlock(&vp
->v_interlock
);
346 simple_lock(&mountlist_slock
);
347 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
348 simple_unlock(&mountlist_slock
);
349 vfs_event_signal(NULL
, VQ_MOUNT
, NULL
);
351 VOP_UNLOCK(vp
, 0, p
);
353 if (error
= VFS_START(mp
, 0, p
))
356 /* increment the operations count */
362 simple_lock(&vp
->v_interlock
);
363 CLR(vp
->v_flag
, VMOUNT
);
364 simple_unlock(&vp
->v_interlock
);
365 mp
->mnt_vfc
->vfc_refcount
--;
367 if (mp
->mnt_kern_flag
& MNTK_IO_XINFO
)
368 FREE(mp
->mnt_xinfo_ptr
, M_TEMP
);
370 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
385 struct nameidata qnd
;
387 char qfpath
[MAXPATHLEN
];
388 char *qfname
= QUOTAFILENAME
;
389 char *qfopsname
= QUOTAOPSNAME
;
390 char *qfextension
[] = INITQFNAMES
;
393 if ((strcmp(mp
->mnt_stat
.f_fstypename
, "hfs") != 0 )
394 && (strcmp( mp
->mnt_stat
.f_fstypename
, "ufs") != 0))
398 * Enable filesystem disk quotas if necessary.
399 * We ignore errors as this should not interfere with final mount
401 for (type
=0; type
< MAXQUOTAS
; type
++) {
402 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfopsname
, qfextension
[type
]);
403 NDINIT(&qnd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, qfpath
, p
);
404 if (namei(&qnd
) != 0)
405 continue; /* option file to trigger quotas is not present */
407 sprintf(qfpath
, "%s/%s.%s", mp
->mnt_stat
.f_mntonname
, qfname
, qfextension
[type
]);
408 if (vp
->v_tag
== VT_HFS
) {
410 (void)hfs_quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
411 } else if (vp
->v_tag
== VT_UFS
) {
413 (void)quotaon(p
, mp
, type
, qfpath
, UIO_SYSSPACE
);
422 * Scan all active processes to see if any of them have a current
423 * or root directory onto which the new filesystem has just been
424 * mounted. If so, replace them with the new mount point.
430 struct filedesc
*fdp
;
435 if (olddp
->v_usecount
== 1)
437 if (VFS_ROOT(olddp
->v_mountedhere
, &newdp
))
438 panic("mount: lost mount");
439 for (p
= allproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
) {
441 if (fdp
->fd_cdir
== olddp
) {
444 fdp
->fd_cdir
= newdp
;
447 if (fdp
->fd_rdir
== olddp
) {
450 fdp
->fd_rdir
= newdp
;
454 if (rootvnode
== olddp
) {
464 * Unmount a file system.
466 * Note: unmount takes a path to the vnode mounted on as argument,
467 * not special file (as before).
469 struct unmount_args
{
475 unmount(p
, uap
, retval
)
477 register struct unmount_args
*uap
;
480 register struct vnode
*vp
;
485 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
494 * Must be the root of the filesystem
496 if ((vp
->v_flag
& VROOT
) == 0) {
501 return (safedounmount(mp
, uap
->flags
, p
));
505 * Do the actual file system unmount, prevent some common foot shooting.
508 safedounmount(mp
, flags
, p
)
516 * Only root, or the user that did the original mount is
517 * permitted to unmount this filesystem.
519 if ((mp
->mnt_stat
.f_owner
!= p
->p_ucred
->cr_uid
) &&
520 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
524 * Don't allow unmounting the root file system.
526 if (mp
->mnt_flag
& MNT_ROOTFS
)
527 return (EBUSY
); /* the root is always busy */
529 return (dounmount(mp
, flags
, p
));
533 * Do the actual file system unmount.
536 dounmount(mp
, flags
, p
)
537 register struct mount
*mp
;
541 struct vnode
*coveredvp
;
544 simple_lock(&mountlist_slock
);
545 /* XXX post jaguar fix LK_DRAIN - then clean this up */
546 if ((flags
& MNT_FORCE
))
547 mp
->mnt_kern_flag
|= MNTK_FRCUNMOUNT
;
548 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
549 simple_unlock(&mountlist_slock
);
550 mp
->mnt_kern_flag
|= MNTK_MWAIT
;
551 if ((error
= tsleep((void *)mp
, PRIBIO
, "dounmount", 0)))
554 * The prior unmount attempt has probably succeeded.
555 * Do not dereference mp here - returning EBUSY is safest.
559 mp
->mnt_kern_flag
|= MNTK_UNMOUNT
;
560 error
= lockmgr(&mp
->mnt_lock
, LK_DRAIN
| LK_INTERLOCK
,
561 &mountlist_slock
, p
);
563 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
566 mp
->mnt_flag
&=~ MNT_ASYNC
;
567 ubc_umount(mp
); /* release cached vnodes */
568 cache_purgevfs(mp
); /* remove cache entries for this file sys */
569 if (((mp
->mnt_flag
& MNT_RDONLY
) ||
570 (error
= VFS_SYNC(mp
, MNT_WAIT
, p
->p_ucred
, p
)) == 0) ||
572 error
= VFS_UNMOUNT(mp
, flags
, p
);
573 simple_lock(&mountlist_slock
);
575 mp
->mnt_kern_flag
&= ~MNTK_UNMOUNT
;
576 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
| LK_REENABLE
,
577 &mountlist_slock
, p
);
581 /* increment the operations count */
584 CIRCLEQ_REMOVE(&mountlist
, mp
, mnt_list
);
585 if ((coveredvp
= mp
->mnt_vnodecovered
) != NULLVP
) {
586 coveredvp
->v_mountedhere
= (struct mount
*)0;
587 simple_unlock(&mountlist_slock
);
589 simple_lock(&mountlist_slock
);
591 mp
->mnt_vfc
->vfc_refcount
--;
592 if (mp
->mnt_vnodelist
.lh_first
!= NULL
) {
593 panic("unmount: dangling vnode");
595 lockmgr(&mp
->mnt_lock
, LK_RELEASE
| LK_INTERLOCK
, &mountlist_slock
, p
);
596 vfs_event_signal(NULL
, VQ_UNMOUNT
, NULL
);
598 if (mp
->mnt_kern_flag
& MNTK_MWAIT
)
601 if (mp
->mnt_kern_flag
& MNTK_IO_XINFO
)
602 FREE(mp
->mnt_xinfo_ptr
, M_TEMP
);
603 FREE_ZONE((caddr_t
)mp
, sizeof (struct mount
), M_MOUNT
);
609 * Sync each mounted filesystem.
613 struct ctldebug debug0
= { "syncprt", &syncprt
};
619 int print_vmpage_stat
=0;
625 struct sync_args
*uap
;
628 register struct mount
*mp
, *nmp
;
631 simple_lock(&mountlist_slock
);
632 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
633 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
634 nmp
= mp
->mnt_list
.cqe_next
;
637 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
638 asyncflag
= mp
->mnt_flag
& MNT_ASYNC
;
639 mp
->mnt_flag
&= ~MNT_ASYNC
;
640 VFS_SYNC(mp
, MNT_NOWAIT
, p
->p_ucred
, p
);
642 mp
->mnt_flag
|= MNT_ASYNC
;
644 simple_lock(&mountlist_slock
);
645 nmp
= mp
->mnt_list
.cqe_next
;
648 simple_unlock(&mountlist_slock
);
651 extern void vm_countdirtypages(void);
652 extern unsigned int vp_pagein
, vp_pgodirty
, vp_pgoclean
;
653 extern unsigned int dp_pgins
, dp_pgouts
;
654 if(print_vmpage_stat
) {
655 vm_countdirtypages();
656 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty
, vp_pgoclean
, vp_pagein
,
657 dp_pgins
, dp_pgouts
);
663 #endif /* DIAGNOSTIC */
668 * Change filesystem quotas.
670 struct quotactl_args
{
678 quotactl(p
, uap
, retval
)
680 register struct quotactl_args
*uap
;
683 register struct mount
*mp
;
687 AUDIT_ARG(uid
, uap
->uid
, 0, 0, 0);
688 AUDIT_ARG(cmd
, uap
->cmd
);
689 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
693 mp
= nd
.ni_vp
->v_mount
;
695 return (VFS_QUOTACTL(mp
, uap
->cmd
, uap
->uid
,
700 * Get filesystem statistics.
708 statfs(p
, uap
, retval
)
710 register struct statfs_args
*uap
;
713 register struct mount
*mp
;
714 register struct statfs
*sp
;
718 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
722 mp
= nd
.ni_vp
->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 filesystem statistics.
735 struct fstatfs_args
{
741 fstatfs(p
, uap
, retval
)
743 register struct fstatfs_args
*uap
;
748 register struct statfs
*sp
;
751 AUDIT_ARG(fd
, uap
->fd
);
753 if (error
= getvnode(p
, uap
->fd
, &fp
))
756 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
758 mp
= ((struct vnode
*)fp
->f_data
)->v_mount
;
762 if (error
= VFS_STATFS(mp
, sp
, p
))
764 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
765 return (copyout((caddr_t
)sp
, (caddr_t
)uap
->buf
,
766 sizeof(*sp
)-sizeof(sp
->f_reserved3
)-sizeof(sp
->f_reserved4
)));
770 * Get statistics on all filesystems.
772 struct getfsstat_args
{
778 getfsstat(p
, uap
, retval
)
780 register struct getfsstat_args
*uap
;
783 register struct mount
*mp
, *nmp
;
784 register struct statfs
*sp
;
786 long count
, maxcount
, error
;
788 maxcount
= uap
->bufsize
/ sizeof(struct statfs
);
789 sfsp
= (caddr_t
)uap
->buf
;
791 simple_lock(&mountlist_slock
);
792 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
793 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
794 nmp
= mp
->mnt_list
.cqe_next
;
797 if (sfsp
&& count
< maxcount
) {
800 * If MNT_NOWAIT is specified, do not refresh the
801 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
803 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
804 (uap
->flags
& MNT_WAIT
)) &&
805 (error
= VFS_STATFS(mp
, sp
, p
))) {
806 simple_lock(&mountlist_slock
);
807 nmp
= mp
->mnt_list
.cqe_next
;
811 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
812 if (error
= copyout((caddr_t
)sp
, sfsp
, sizeof(*sp
))) {
819 simple_lock(&mountlist_slock
);
820 nmp
= mp
->mnt_list
.cqe_next
;
823 simple_unlock(&mountlist_slock
);
824 if (sfsp
&& count
> maxcount
)
832 ogetfsstat(p
, uap
, retval
)
834 register struct getfsstat_args
*uap
;
837 register struct mount
*mp
, *nmp
;
838 register struct statfs
*sp
;
840 long count
, maxcount
, error
;
842 maxcount
= uap
->bufsize
/ (sizeof(struct statfs
) - sizeof(sp
->f_reserved4
));
843 sfsp
= (caddr_t
)uap
->buf
;
845 simple_lock(&mountlist_slock
);
846 for (mp
= mountlist
.cqh_first
; mp
!= (void *)&mountlist
; mp
= nmp
) {
847 if (vfs_busy(mp
, LK_NOWAIT
, &mountlist_slock
, p
)) {
848 nmp
= mp
->mnt_list
.cqe_next
;
851 if (sfsp
&& count
< maxcount
) {
854 * If MNT_NOWAIT is specified, do not refresh the
855 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
857 if (((uap
->flags
& MNT_NOWAIT
) == 0 ||
858 (uap
->flags
& MNT_WAIT
)) &&
859 (error
= VFS_STATFS(mp
, sp
, p
))) {
860 simple_lock(&mountlist_slock
);
861 nmp
= mp
->mnt_list
.cqe_next
;
865 sp
->f_flags
= mp
->mnt_flag
& MNT_VISFLAGMASK
;
866 error
= copyout((caddr_t
)sp
, sfsp
,
867 sizeof(*sp
) - sizeof(sp
->f_reserved3
)
868 - sizeof(sp
->f_reserved4
));
873 sfsp
+= sizeof(*sp
) - sizeof(sp
->f_reserved4
);
876 simple_lock(&mountlist_slock
);
877 nmp
= mp
->mnt_list
.cqe_next
;
880 simple_unlock(&mountlist_slock
);
881 if (sfsp
&& count
> maxcount
)
890 * Change current working directory to a given file descriptor.
897 fchdir(p
, uap
, retval
)
899 struct fchdir_args
*uap
;
902 register struct filedesc
*fdp
= p
->p_fd
;
903 struct vnode
*vp
, *tdp
, *tvp
;
908 if (error
= getvnode(p
, uap
->fd
, &fp
))
910 vp
= (struct vnode
*)fp
->f_data
;
912 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
914 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
916 if (vp
->v_type
!= VDIR
)
919 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
920 while (!error
&& (mp
= vp
->v_mountedhere
) != NULL
) {
921 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
925 error
= VFS_ROOT(mp
, &tdp
);
936 VOP_UNLOCK(vp
, 0, p
);
944 * Change current working directory (``.'').
951 chdir(p
, uap
, retval
)
953 struct chdir_args
*uap
;
956 register struct filedesc
*fdp
= p
->p_fd
;
961 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
963 error
= change_dir(&nd
, p
);
967 fdp
->fd_cdir
= nd
.ni_vp
;
973 * Change notion of root (``/'') directory.
980 chroot(p
, uap
, retval
)
982 struct chroot_args
*uap
;
985 register struct filedesc
*fdp
= p
->p_fd
;
988 boolean_t shared_regions_active
;
991 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
994 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
996 error
= change_dir(&nd
, p
);
1000 if(p
->p_flag
& P_NOSHLIB
) {
1001 shared_regions_active
= FALSE
;
1003 shared_regions_active
= TRUE
;
1006 if(error
= clone_system_shared_regions(shared_regions_active
, nd
.ni_vp
)) {
1012 fdp
->fd_rdir
= nd
.ni_vp
;
1019 * Common routine for chroot and chdir.
1023 register struct nameidata
*ndp
;
1029 if (error
= namei(ndp
))
1032 if (vp
->v_type
!= VDIR
)
1035 error
= VOP_ACCESS(vp
, VEXEC
, p
->p_ucred
, p
);
1039 VOP_UNLOCK(vp
, 0, p
);
1044 * Check permissions, allocate an open file structure,
1045 * and call the device open routine if any.
1053 open(p
, uap
, retval
)
1055 register struct open_args
*uap
;
1058 register struct filedesc
*fdp
= p
->p_fd
;
1059 register struct file
*fp
;
1060 register struct vnode
*vp
;
1061 int flags
, cmode
, oflags
;
1063 int type
, indx
, error
;
1065 struct nameidata nd
;
1066 extern struct fileops vnops
;
1068 oflags
= uap
->flags
;
1069 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1071 flags
= FFLAGS(uap
->flags
);
1072 AUDIT_ARG(fflags
, oflags
);
1073 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
1074 if (error
= falloc(p
, &nfp
, &indx
))
1077 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, uap
->path
, p
);
1078 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1079 if (error
= vn_open_modflags(&nd
, &flags
, cmode
)) {
1081 if ((error
== ENODEV
|| error
== ENXIO
) &&
1082 p
->p_dupfd
>= 0 && /* XXX from fdopen */
1084 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1088 if (error
== ERESTART
)
1095 fp
->f_flag
= flags
& FMASK
;
1096 fp
->f_type
= DTYPE_VNODE
;
1098 fp
->f_data
= (caddr_t
)vp
;
1100 VOP_UNLOCK(vp
, 0, p
);
1101 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1102 lf
.l_whence
= SEEK_SET
;
1105 if (flags
& O_EXLOCK
)
1106 lf
.l_type
= F_WRLCK
;
1108 lf
.l_type
= F_RDLCK
;
1110 if ((flags
& FNONBLOCK
) == 0)
1112 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
))
1114 fp
->f_flag
|= FHASLOCK
;
1117 if (flags
& O_TRUNC
) {
1119 struct vattr
*vap
= &vat
;
1121 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1122 (void)vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
); /* XXX */
1125 /* try to truncate by setting the size attribute */
1126 error
= VOP_SETATTR(vp
, vap
, p
->p_ucred
, p
);
1127 VOP_UNLOCK(vp
, 0, p
); /* XXX */
1132 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1136 vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
1146 struct ocreat_args
{
1151 ocreat(p
, uap
, retval
)
1153 register struct ocreat_args
*uap
;
1156 struct open_args nuap
;
1158 nuap
.path
= uap
->path
;
1159 nuap
.mode
= uap
->mode
;
1160 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1161 return (open(p
, &nuap
, retval
));
1163 #endif /* COMPAT_43 */
1166 * Create a special file.
1175 mknod(p
, uap
, retval
)
1177 register struct mknod_args
*uap
;
1180 register struct vnode
*vp
;
1184 struct nameidata nd
;
1186 AUDIT_ARG(mode
, uap
->mode
);
1187 AUDIT_ARG(dev
, uap
->dev
);
1188 cmode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1189 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1192 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1201 vattr
.va_mode
= cmode
;
1202 vattr
.va_rdev
= uap
->dev
;
1205 switch (uap
->mode
& S_IFMT
) {
1206 case S_IFMT
: /* used by badsect to flag bad sectors */
1207 vattr
.va_type
= VBAD
;
1210 vattr
.va_type
= VCHR
;
1213 vattr
.va_type
= VBLK
;
1225 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
1226 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1228 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1230 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1233 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1234 &nd
.ni_cnd
, &vattr
);
1237 if (error
== 0 && nd
.ni_vp
) {
1238 if (VNAME(nd
.ni_vp
) == NULL
) {
1239 VNAME(nd
.ni_vp
) = nameptr
;
1242 if (VPARENT(nd
.ni_vp
) == NULL
) {
1243 if (vget(nd
.ni_dvp
, 0, p
) == 0) {
1244 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1249 remove_name(nameptr
);
1253 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1254 if (nd
.ni_dvp
== vp
)
1265 * Create a named pipe.
1267 struct mkfifo_args
{
1273 mkfifo(p
, uap
, retval
)
1275 register struct mkfifo_args
*uap
;
1280 struct nameidata nd
;
1285 return (EOPNOTSUPP
);
1288 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1292 if (nd
.ni_vp
!= NULL
) {
1293 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1294 if (nd
.ni_dvp
== nd
.ni_vp
)
1302 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
,
1303 nd
.ni_cnd
.cn_namelen
,
1304 nd
.ni_cnd
.cn_hash
, 0);
1306 vattr
.va_type
= VFIFO
;
1307 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1308 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1309 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
1311 if (error
== 0 && nd
.ni_vp
&& nd
.ni_vp
->v_type
== VFIFO
) {
1312 int vpid
= nd
.ni_vp
->v_id
;
1313 if (vget(nd
.ni_vp
, 0, p
) == 0) {
1314 if (vpid
== nd
.ni_vp
->v_id
&& nd
.ni_vp
->v_type
== VFIFO
) {
1315 VNAME(nd
.ni_vp
) = nameptr
;
1318 if (VPARENT(nd
.ni_vp
) == NULL
) {
1319 if (vget(nd
.ni_dvp
, 0, p
) == 0) {
1320 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1327 remove_name(nameptr
);
1334 * Make a hard file link.
1342 link(p
, uap
, retval
)
1344 register struct link_args
*uap
;
1347 register struct vnode
*vp
;
1348 struct nameidata nd
;
1352 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1357 if (vp
->v_type
== VDIR
)
1358 error
= EPERM
; /* POSIX */
1360 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1361 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1362 nd
.ni_dirp
= uap
->link
;
1365 if (nd
.ni_vp
!= NULL
)
1368 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1370 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1371 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1373 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1374 if (nd
.ni_dvp
== nd
.ni_vp
)
1388 * Make a symbolic link.
1390 struct symlink_args
{
1396 symlink(p
, uap
, retval
)
1398 register struct symlink_args
*uap
;
1402 char *path
, *nameptr
;
1404 struct nameidata nd
;
1408 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1409 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1411 AUDIT_ARG(text
, path
); /* This is the link string */
1413 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->link
, p
);
1418 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1419 if (nd
.ni_dvp
== nd
.ni_vp
)
1428 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1429 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1431 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
1433 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1435 // have to do this little dance because nd.ni_vp is not locked
1436 // on return from the VOP_SYMLINK() call.
1438 if (error
== 0 && nd
.ni_vp
&& nd
.ni_vp
->v_type
== VLNK
) {
1439 vpid
= nd
.ni_vp
->v_id
;
1440 if (vget(nd
.ni_vp
, 0, p
) == 0) {
1441 if (vpid
== nd
.ni_vp
->v_id
&& nd
.ni_vp
->v_type
== VLNK
) {
1442 VNAME(nd
.ni_vp
) = nameptr
;
1445 if (VPARENT(nd
.ni_vp
) == NULL
&& vget(nd
.ni_dvp
, 0, p
) == 0) {
1446 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1452 if (nameptr
) { // only true if we didn't add it to the vnode
1453 remove_name(nameptr
);
1456 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1461 * Delete a whiteout from the filesystem.
1463 struct undelete_args
{
1468 undelete(p
, uap
, retval
)
1470 register struct undelete_args
*uap
;
1474 struct nameidata nd
;
1477 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
, UIO_USERSPACE
,
1483 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1484 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1485 if (nd
.ni_dvp
== nd
.ni_vp
)
1494 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1495 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1496 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1502 * Delete a name from the filesystem.
1504 struct unlink_args
{
1509 _unlink(p
, uap
, retval
, nodelbusy
)
1511 struct unlink_args
*uap
;
1515 register struct vnode
*vp
;
1517 struct nameidata nd
;
1520 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1521 /* with Carbon semantics, busy files cannot be deleted */
1523 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1529 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1530 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1532 if (vp
->v_type
== VDIR
)
1533 error
= EPERM
; /* POSIX */
1536 * The root of a mounted filesystem cannot be deleted.
1538 * XXX: can this only be a VDIR case?
1540 if (vp
->v_flag
& VROOT
)
1545 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1546 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1548 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1549 if (nd
.ni_dvp
== vp
)
1560 * Delete a name from the filesystem using POSIX semantics.
1563 unlink(p
, uap
, retval
)
1565 struct unlink_args
*uap
;
1568 return _unlink(p
, uap
, retval
, 0);
1572 * Delete a name from the filesystem using Carbon semantics.
1575 delete(p
, uap
, retval
)
1577 struct unlink_args
*uap
;
1580 return _unlink(p
, uap
, retval
, 1);
1584 * Reposition read/write file offset.
1588 #ifdef DOUBLE_ALIGN_PARAMS
1595 lseek(p
, uap
, retval
)
1597 register struct lseek_args
*uap
;
1600 struct ucred
*cred
= p
->p_ucred
;
1604 off_t offset
= uap
->offset
;
1607 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1611 if (fp
->f_type
!= DTYPE_VNODE
) {
1615 vp
= (struct vnode
*)fp
->f_data
;
1616 switch (uap
->whence
) {
1618 offset
+= fp
->f_offset
;
1621 if (error
= VOP_GETATTR(vp
, &vattr
, cred
, p
))
1623 offset
+= vattr
.va_size
;
1631 if (uap
->offset
> 0 && offset
< 0) {
1632 /* Incremented/relative move past max size */
1636 * Allow negative offsets on character devices, per
1637 * POSIX 1003.1-2001. Most likely for writing disk
1640 if (offset
< 0 && vp
->v_type
!= VCHR
) {
1641 /* Decremented/relative move before start */
1645 fp
->f_offset
= offset
;
1646 *(off_t
*)retval
= fp
->f_offset
;
1656 * Reposition read/write file offset.
1658 struct olseek_args
{
1664 olseek(p
, uap
, retval
)
1666 register struct olseek_args
*uap
;
1669 struct lseek_args
/* {
1671 #ifdef DOUBLE_ALIGN_PARAMS
1672 syscallarg(int) pad;
1674 syscallarg(off_t) offset;
1675 syscallarg(int) whence;
1681 nuap
.offset
= uap
->offset
;
1682 nuap
.whence
= uap
->whence
;
1683 error
= lseek(p
, &nuap
, &qret
);
1684 *(long *)retval
= qret
;
1687 #endif /* COMPAT_43 */
1690 * Check access permissions.
1692 struct access_args
{
1697 access(p
, uap
, retval
)
1699 register struct access_args
*uap
;
1702 register struct ucred
*cred
= p
->p_ucred
;
1703 register struct vnode
*vp
;
1704 int error
, flags
, t_gid
, t_uid
;
1705 struct nameidata nd
;
1707 t_uid
= cred
->cr_uid
;
1708 t_gid
= cred
->cr_groups
[0];
1709 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1710 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1711 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1718 /* Flags == 0 means only check for existence. */
1721 if (uap
->flags
& R_OK
)
1723 if (uap
->flags
& W_OK
)
1725 if (uap
->flags
& X_OK
)
1727 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1728 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1732 cred
->cr_uid
= t_uid
;
1733 cred
->cr_groups
[0] = t_gid
;
1739 * Get file status; this version follows links.
1747 ostat(p
, uap
, retval
)
1749 register struct ostat_args
*uap
;
1755 struct nameidata nd
;
1757 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
1759 if (error
= namei(&nd
))
1761 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1766 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1771 * Get file status; this version does not follow links.
1773 struct olstat_args
{
1779 olstat(p
, uap
, retval
)
1781 register struct olstat_args
*uap
;
1784 struct vnode
*vp
, *dvp
;
1785 struct stat sb
, sb1
;
1788 struct nameidata nd
;
1790 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
, UIO_USERSPACE
,
1792 if (error
= namei(&nd
))
1795 * For symbolic links, always return the attributes of its
1796 * containing directory, except for mode, size, and links.
1800 if (vp
->v_type
!= VLNK
) {
1805 error
= vn_stat(vp
, &sb
, p
);
1810 error
= vn_stat(dvp
, &sb
, p
);
1816 error
= vn_stat(vp
, &sb1
, p
);
1820 sb
.st_mode
&= ~S_IFDIR
;
1821 sb
.st_mode
|= S_IFLNK
;
1822 sb
.st_nlink
= sb1
.st_nlink
;
1823 sb
.st_size
= sb1
.st_size
;
1824 sb
.st_blocks
= sb1
.st_blocks
;
1827 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1832 * Convert from an old to a new stat structure.
1840 ost
->st_dev
= st
->st_dev
;
1841 ost
->st_ino
= st
->st_ino
;
1842 ost
->st_mode
= st
->st_mode
;
1843 ost
->st_nlink
= st
->st_nlink
;
1844 ost
->st_uid
= st
->st_uid
;
1845 ost
->st_gid
= st
->st_gid
;
1846 ost
->st_rdev
= st
->st_rdev
;
1847 if (st
->st_size
< (quad_t
)1 << 32)
1848 ost
->st_size
= st
->st_size
;
1851 ost
->st_atime
= st
->st_atime
;
1852 ost
->st_mtime
= st
->st_mtime
;
1853 ost
->st_ctime
= st
->st_ctime
;
1854 ost
->st_blksize
= st
->st_blksize
;
1855 ost
->st_blocks
= st
->st_blocks
;
1856 ost
->st_flags
= st
->st_flags
;
1857 ost
->st_gen
= st
->st_gen
;
1859 #endif /* COMPAT_43 */
1862 * The stat buffer spare fields are uninitialized
1863 * so don't include them in the copyout.
1865 #define STATBUFSIZE \
1866 (sizeof(struct stat) - sizeof(int32_t) - 2 * sizeof(int64_t))
1868 * Get file status; this version follows links.
1876 stat(p
, uap
, retval
)
1878 register struct stat_args
*uap
;
1883 struct nameidata nd
;
1885 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| SHAREDLEAF
| AUDITVNPATH1
,
1886 UIO_USERSPACE
, uap
->path
, p
);
1890 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1894 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, STATBUFSIZE
);
1899 * Get file status; this version does not follow links.
1907 lstat(p
, uap
, retval
)
1909 register struct lstat_args
*uap
;
1915 struct nameidata nd
;
1917 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1923 error
= vn_stat(vp
, &sb
, p
);
1927 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, STATBUFSIZE
);
1932 * Get configurable pathname variables.
1934 struct pathconf_args
{
1940 pathconf(p
, uap
, retval
)
1942 register struct pathconf_args
*uap
;
1946 struct nameidata nd
;
1948 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1953 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1959 * Return target name of a symbolic link.
1961 struct readlink_args
{
1968 readlink(p
, uap
, retval
)
1970 register struct readlink_args
*uap
;
1973 register struct vnode
*vp
;
1977 struct nameidata nd
;
1979 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1985 if (vp
->v_type
!= VLNK
)
1988 aiov
.iov_base
= uap
->buf
;
1989 aiov
.iov_len
= uap
->count
;
1990 auio
.uio_iov
= &aiov
;
1991 auio
.uio_iovcnt
= 1;
1992 auio
.uio_offset
= 0;
1993 auio
.uio_rw
= UIO_READ
;
1994 auio
.uio_segflg
= UIO_USERSPACE
;
1996 auio
.uio_resid
= uap
->count
;
1997 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
2000 *retval
= uap
->count
- auio
.uio_resid
;
2005 * Change flags of a file given a path name.
2007 struct chflags_args
{
2013 chflags(p
, uap
, retval
)
2015 register struct chflags_args
*uap
;
2018 register struct vnode
*vp
;
2021 struct nameidata nd
;
2023 AUDIT_ARG(fflags
, uap
->flags
);
2024 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2029 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2030 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2032 vattr
.va_flags
= uap
->flags
;
2033 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2039 * Change flags of a file given a file descriptor.
2041 struct fchflags_args
{
2047 fchflags(p
, uap
, retval
)
2049 register struct fchflags_args
*uap
;
2057 AUDIT_ARG(fd
, uap
->fd
);
2058 AUDIT_ARG(fflags
, uap
->flags
);
2059 if (error
= getvnode(p
, uap
->fd
, &fp
))
2062 vp
= (struct vnode
*)fp
->f_data
;
2064 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2066 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2067 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2069 vattr
.va_flags
= uap
->flags
;
2070 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2071 VOP_UNLOCK(vp
, 0, p
);
2076 * Change mode of a file given path name.
2084 chmod(p
, uap
, retval
)
2086 register struct chmod_args
*uap
;
2089 register struct vnode
*vp
;
2092 struct nameidata nd
;
2094 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2096 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2101 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2102 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2104 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2105 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2111 * Change mode of a file given a file descriptor.
2113 struct fchmod_args
{
2119 fchmod(p
, uap
, retval
)
2121 register struct fchmod_args
*uap
;
2129 AUDIT_ARG(fd
, uap
->fd
);
2130 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2131 if (error
= getvnode(p
, uap
->fd
, &fp
))
2134 vp
= (struct vnode
*)fp
->f_data
;
2135 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2136 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2138 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2141 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2142 AUDIT_ARG(mode
, (mode_t
)vattr
.va_mode
);
2143 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2144 VOP_UNLOCK(vp
, 0, p
);
2150 * Set ownership given a path name.
2159 chown(p
, uap
, retval
)
2161 register struct chown_args
*uap
;
2164 register struct vnode
*vp
;
2167 struct nameidata nd
;
2169 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2171 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2178 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2179 * by looking for chown() calls on /dev/console from a console process.
2181 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2182 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2183 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2184 console_user
= uap
->uid
;
2187 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2188 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2190 vattr
.va_uid
= uap
->uid
;
2191 vattr
.va_gid
= uap
->gid
;
2192 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2198 * Set ownership given a file descriptor.
2200 struct fchown_args
{
2207 fchown(p
, uap
, retval
)
2209 register struct fchown_args
*uap
;
2217 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2218 AUDIT_ARG(fd
, uap
->fd
);
2220 if (error
= getvnode(p
, uap
->fd
, &fp
))
2223 vp
= (struct vnode
*)fp
->f_data
;
2224 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2225 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2227 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2230 vattr
.va_uid
= uap
->uid
;
2231 vattr
.va_gid
= uap
->gid
;
2232 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2233 VOP_UNLOCK(vp
, 0, p
);
2238 getutimes(usrtvp
, tsp
)
2239 const struct timeval
*usrtvp
;
2240 struct timespec
*tsp
;
2242 struct timeval tv
[2];
2245 if (usrtvp
== NULL
) {
2247 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2250 if ((error
= copyin((void *)usrtvp
, (void *)tv
, sizeof (tv
))) != 0)
2252 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2253 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
2259 setutimes(p
, vp
, ts
, nullflag
)
2262 const struct timespec
*ts
;
2268 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2269 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2273 vattr
.va_atime
= ts
[0];
2274 vattr
.va_mtime
= ts
[1];
2276 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
2277 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2278 VOP_UNLOCK(vp
, 0, p
);
2284 * Set the access and modification times of a file.
2286 struct utimes_args
{
2288 struct timeval
*tptr
;
2292 utimes(p
, uap
, retval
)
2294 register struct utimes_args
*uap
;
2297 struct timespec ts
[2];
2298 struct timeval
*usrtvp
;
2300 struct nameidata nd
;
2302 /* AUDIT: Needed to change the order of operations to do the
2303 * name lookup first because auditing wants the path.
2305 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2311 if ((error
= getutimes(usrtvp
, ts
)) != 0) {
2315 error
= setutimes(p
, nd
.ni_vp
, ts
, usrtvp
== NULL
);
2321 * Set the access and modification times of a file.
2323 struct futimes_args
{
2325 struct timeval
*tptr
;
2329 futimes(p
, uap
, retval
)
2331 register struct futimes_args
*uap
;
2334 struct timespec ts
[2];
2336 struct timeval
*usrtvp
;
2339 AUDIT_ARG(fd
, uap
->fd
);
2341 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2343 if ((error
= getvnode(p
, uap
->fd
, &fp
)) != 0)
2346 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
2348 return setutimes(p
, (struct vnode
*)fp
->f_data
, ts
, usrtvp
== NULL
);
2352 * Truncate a file given its path name.
2354 struct truncate_args
{
2356 #ifdef DOUBLE_ALIGN_PARAMS
2363 truncate(p
, uap
, retval
)
2365 register struct truncate_args
*uap
;
2368 register struct vnode
*vp
;
2371 struct nameidata nd
;
2373 if (uap
->length
< 0)
2375 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2376 if (error
= namei(&nd
))
2379 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2380 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2381 if (vp
->v_type
== VDIR
)
2383 else if ((error
= vn_writechk(vp
)) == 0 &&
2384 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2386 vattr
.va_size
= uap
->length
;
2387 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2394 * Truncate a file given a file descriptor.
2396 struct ftruncate_args
{
2398 #ifdef DOUBLE_ALIGN_PARAMS
2405 ftruncate(p
, uap
, retval
)
2407 register struct ftruncate_args
*uap
;
2415 AUDIT_ARG(fd
, uap
->fd
);
2416 if (uap
->length
< 0)
2419 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2422 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
2424 if (fp
->f_type
== DTYPE_PSXSHM
) {
2425 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2427 if (fp
->f_type
!= DTYPE_VNODE
)
2430 if ((fp
->f_flag
& FWRITE
) == 0)
2432 vp
= (struct vnode
*)fp
->f_data
;
2433 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2434 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2435 if (vp
->v_type
== VDIR
)
2437 else if ((error
= vn_writechk(vp
)) == 0) {
2439 vattr
.va_size
= uap
->length
;
2440 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2442 VOP_UNLOCK(vp
, 0, p
);
2448 * Truncate a file given its path name.
2450 struct otruncate_args
{
2456 otruncate(p
, uap
, retval
)
2458 register struct otruncate_args
*uap
;
2461 struct truncate_args
/* {
2462 syscallarg(char *) path;
2463 #ifdef DOUBLE_ALIGN_PARAMS
2464 syscallarg(int) pad;
2466 syscallarg(off_t) length;
2469 nuap
.path
= uap
->path
;
2470 nuap
.length
= uap
->length
;
2471 return (truncate(p
, &nuap
, retval
));
2475 * Truncate a file given a file descriptor.
2477 struct oftruncate_args
{
2483 oftruncate(p
, uap
, retval
)
2485 register struct oftruncate_args
*uap
;
2488 struct ftruncate_args
/* {
2490 #ifdef DOUBLE_ALIGN_PARAMS
2491 syscallarg(int) pad;
2493 syscallarg(off_t) length;
2497 nuap
.length
= uap
->length
;
2498 return (ftruncate(p
, &nuap
, retval
));
2500 #endif /* COMPAT_43 */
2503 * Sync an open file.
2510 fsync(p
, uap
, retval
)
2512 struct fsync_args
*uap
;
2515 register struct vnode
*vp
;
2519 if (error
= getvnode(p
, uap
->fd
, &fp
))
2523 vp
= (struct vnode
*)fp
->f_data
;
2524 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2525 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2526 VOP_UNLOCK(vp
, 0, p
);
2532 * Duplicate files. Source must be a file, target must be a file or
2536 struct copyfile_args
{
2544 copyfile(p
, uap
, retval
)
2546 register struct copyfile_args
*uap
;
2549 register struct vnode
*tvp
, *fvp
, *tdvp
;
2550 register struct ucred
*cred
= p
->p_ucred
;
2551 struct nameidata fromnd
, tond
;
2554 /* Check that the flags are valid. */
2556 if (uap
->flags
& ~CPF_MASK
) {
2560 NDINIT(&fromnd
, LOOKUP
, SAVESTART
, UIO_USERSPACE
,
2562 if (error
= namei(&fromnd
))
2566 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
,
2567 UIO_USERSPACE
, uap
->to
, p
);
2568 if (error
= namei(&tond
)) {
2575 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2581 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2586 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2592 * If source is the same as the destination (that is the
2593 * same inode number) then there is nothing to do.
2594 * (fixed to have POSIX semantics - CSM 3/2/98)
2600 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2602 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2611 vrele(tond
.ni_startdir
);
2612 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2614 if (fromnd
.ni_startdir
)
2615 vrele(fromnd
.ni_startdir
);
2616 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2623 * Rename files. Source and destination must either both be directories,
2624 * or both not be directories. If target is a directory, it must be empty.
2626 struct rename_args
{
2632 rename(p
, uap
, retval
)
2634 register struct rename_args
*uap
;
2637 register struct vnode
*tvp
, *fvp
, *tdvp
;
2638 struct nameidata fromnd
, tond
;
2641 int casesense
,casepres
;
2642 char *nameptr
=NULL
, *oname
;
2643 struct vnode
*oparent
;
2648 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
| AUDITVNPATH1
,
2649 UIO_USERSPACE
, uap
->from
, p
);
2650 error
= namei(&fromnd
);
2655 NDINIT(&tond
, RENAME
,
2656 LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
2657 UIO_USERSPACE
, uap
->to
, p
);
2658 if (fromnd
.ni_vp
->v_type
== VDIR
)
2659 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2660 if (error
= namei(&tond
)) {
2661 /* Translate error code for rename("dir1", "dir2/."). */
2662 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
2664 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2665 vrele(fromnd
.ni_dvp
);
2673 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2676 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2684 * If source is the same as the destination (that is the
2685 * same inode number) then there is nothing to do... EXCEPT if the
2686 * underlying file system supports case insensitivity and is case
2687 * preserving. Then a special case is made, i.e. foo -> Foo.
2689 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2690 * and _PC_CASE_PRESERVING can have this exception, and they need to
2691 * handle the special case of getting the same vnode as target and
2692 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2693 * so not to cause locking problems. There is a single reference on tvp.
2695 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2696 * that correct behaviour then is just to remove the source (link)
2698 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
) {
2699 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2700 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2701 fromnd
.ni_cnd
.cn_namelen
)) {
2702 error
= -1; /* Default "unix" behavior */
2703 } else { /* probe for file system specifics */
2704 if (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
))
2706 if (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
))
2708 if (!casesense
&& casepres
)
2709 vput(tvp
); /* Unlock target and drop ref */
2714 * Allow the renaming of mount points.
2715 * - target must not exist
2716 * - target must reside in the same directory as source
2717 * - union mounts cannot be renamed
2718 * - "/" cannot be renamed
2721 (fvp
->v_flag
& VROOT
) &&
2722 (fvp
->v_type
== VDIR
) &&
2724 (fvp
->v_mountedhere
== NULL
) &&
2725 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2726 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2727 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2729 /* switch fvp to the covered vnode */
2730 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2738 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2739 if (fromnd
.ni_dvp
!= tdvp
)
2740 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2742 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2744 // XXXdbg - so that the fs won't block when it vrele()'s
2745 // these nodes before returning
2746 if (fromnd
.ni_dvp
!= tdvp
) {
2750 // save these off so we can later verify that fvp is the same
2752 oparent
= VPARENT(fvp
);
2754 nameptr
= add_name(tond
.ni_cnd
.cn_nameptr
,
2755 tond
.ni_cnd
.cn_namelen
,
2756 tond
.ni_cnd
.cn_hash
, 0);
2759 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2760 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2762 remove_name(nameptr
);
2764 if (fromnd
.ni_dvp
!= tdvp
) {
2772 * update filesystem's mount point data
2775 char *cp
, *pathend
, *mpname
;
2782 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2783 mp
= fvp
->v_mountedhere
;
2785 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2790 VOP_UNLOCK(fvp
, 0, p
);
2792 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2793 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2795 /* find current mount point prefix */
2796 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2797 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2801 /* find last component of target name */
2802 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2806 /* append name to prefix */
2807 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2808 bzero(pathend
, maxlen
);
2809 strncpy(pathend
, mpname
, maxlen
- 1);
2811 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2818 // fix up name & parent pointers. note that we first
2819 // check that fvp has the same name/parent pointers it
2820 // had before the rename call and then we lock fvp so
2821 // that it won't go away on us when we hit blocking
2822 // points like remove_name() or vrele() where fvp could
2824 if (oname
== VNAME(fvp
) && oparent
== VPARENT(fvp
) && vget(fvp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
) == 0) {
2826 char *tmp
= VNAME(fvp
);
2831 VNAME(fvp
) = nameptr
;
2834 if (fromnd
.ni_dvp
!= tdvp
) {
2835 struct vnode
*tmpvp
;
2837 tmpvp
= VPARENT(fvp
);
2838 VPARENT(fvp
) = NULL
;
2841 VPARENT(fvp
) = tdvp
;
2843 // note: we don't vrele() tdvp because we want to keep
2844 // the reference until fvp gets recycled
2850 // if fvp isn't kosher anymore and we locked tdvp,
2852 if (fromnd
.ni_dvp
!= tdvp
) {
2855 remove_name(nameptr
);
2860 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2867 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2868 vrele(fromnd
.ni_dvp
);
2872 vrele(tond
.ni_startdir
);
2873 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2875 if (fromnd
.ni_startdir
)
2876 vrele(fromnd
.ni_startdir
);
2877 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2884 * Make a directory file.
2892 mkdir(p
, uap
, retval
)
2894 register struct mkdir_args
*uap
;
2897 register struct vnode
*vp
;
2900 struct nameidata nd
;
2903 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2905 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2906 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2912 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2913 if (nd
.ni_dvp
== vp
)
2921 vattr
.va_type
= VDIR
;
2922 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2923 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2925 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
2927 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2929 VNAME(nd
.ni_vp
) = nameptr
;
2930 if (VPARENT(nd
.ni_vp
) == NULL
&& vget(nd
.ni_dvp
, 0, p
) == 0) {
2931 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
2940 * Remove a directory file.
2947 rmdir(p
, uap
, retval
)
2949 struct rmdir_args
*uap
;
2952 register struct vnode
*vp
;
2954 struct nameidata nd
;
2957 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
2963 if (vp
->v_type
!= VDIR
) {
2968 * No rmdir "." please.
2970 if (nd
.ni_dvp
== vp
) {
2975 * The root of a mounted filesystem cannot be deleted.
2977 if (vp
->v_flag
& VROOT
)
2981 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2982 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2983 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2985 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2986 if (nd
.ni_dvp
== vp
)
2997 * Read a block of directory entries in a file system independent format.
2999 struct ogetdirentries_args
{
3006 ogetdirentries(p
, uap
, retval
)
3008 register struct ogetdirentries_args
*uap
;
3011 register struct vnode
*vp
;
3013 struct uio auio
, kuio
;
3014 struct iovec aiov
, kiov
;
3015 struct dirent
*dp
, *edp
;
3017 int error
, eofflag
, readcnt
;
3020 if (error
= getvnode(p
, uap
->fd
, &fp
))
3022 if ((fp
->f_flag
& FREAD
) == 0)
3024 vp
= (struct vnode
*)fp
->f_data
;
3026 if (vp
->v_type
!= VDIR
)
3028 aiov
.iov_base
= uap
->buf
;
3029 aiov
.iov_len
= uap
->count
;
3030 auio
.uio_iov
= &aiov
;
3031 auio
.uio_iovcnt
= 1;
3032 auio
.uio_rw
= UIO_READ
;
3033 auio
.uio_segflg
= UIO_USERSPACE
;
3035 auio
.uio_resid
= uap
->count
;
3036 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3037 loff
= auio
.uio_offset
= fp
->f_offset
;
3038 # if (BYTE_ORDER != LITTLE_ENDIAN)
3039 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
3040 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3041 (int *)0, (u_long
**)0);
3042 fp
->f_offset
= auio
.uio_offset
;
3047 kuio
.uio_iov
= &kiov
;
3048 kuio
.uio_segflg
= UIO_SYSSPACE
;
3049 kiov
.iov_len
= uap
->count
;
3050 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
3051 kiov
.iov_base
= dirbuf
;
3052 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
3053 (int *)0, (u_long
**)0);
3054 fp
->f_offset
= kuio
.uio_offset
;
3056 readcnt
= uap
->count
- kuio
.uio_resid
;
3057 edp
= (struct dirent
*)&dirbuf
[readcnt
];
3058 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
3059 # if (BYTE_ORDER == LITTLE_ENDIAN)
3061 * The expected low byte of
3062 * dp->d_namlen is our dp->d_type.
3063 * The high MBZ byte of dp->d_namlen
3064 * is our dp->d_namlen.
3066 dp
->d_type
= dp
->d_namlen
;
3070 * The dp->d_type is the high byte
3071 * of the expected dp->d_namlen,
3072 * so must be zero'ed.
3076 if (dp
->d_reclen
> 0) {
3077 dp
= (struct dirent
*)
3078 ((char *)dp
+ dp
->d_reclen
);
3085 error
= uiomove(dirbuf
, readcnt
, &auio
);
3087 FREE(dirbuf
, M_TEMP
);
3089 VOP_UNLOCK(vp
, 0, p
);
3095 extern int (**union_vnodeop_p
)(void *);
3096 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3098 if ((uap
->count
== auio
.uio_resid
) &&
3099 (vp
->v_op
== union_vnodeop_p
)) {
3102 lvp
= union_dircache(vp
, p
);
3103 if (lvp
!= NULLVP
) {
3107 * If the directory is opaque,
3108 * then don't show lower entries
3110 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3111 if (va
.va_flags
& OPAQUE
) {
3117 if (lvp
!= NULLVP
) {
3118 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3123 VOP_UNLOCK(lvp
, 0, p
);
3124 fp
->f_data
= (caddr_t
) lvp
;
3126 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3137 if ((uap
->count
== auio
.uio_resid
) &&
3138 (vp
->v_flag
& VROOT
) &&
3139 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3140 struct vnode
*tvp
= vp
;
3141 vp
= vp
->v_mount
->mnt_vnodecovered
;
3143 fp
->f_data
= (caddr_t
) vp
;
3148 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3150 *retval
= uap
->count
- auio
.uio_resid
;
3153 #endif /* COMPAT_43 */
3156 * Read a block of directory entries in a file system independent format.
3158 struct getdirentries_args
{
3165 getdirentries(p
, uap
, retval
)
3167 register struct getdirentries_args
*uap
;
3170 register struct vnode
*vp
;
3177 AUDIT_ARG(fd
, uap
->fd
);
3178 error
= getvnode(p
, uap
->fd
, &fp
);
3182 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3184 if ((fp
->f_flag
& FREAD
) == 0)
3186 vp
= (struct vnode
*)fp
->f_data
;
3188 if (vp
->v_type
!= VDIR
)
3190 aiov
.iov_base
= uap
->buf
;
3191 aiov
.iov_len
= uap
->count
;
3192 auio
.uio_iov
= &aiov
;
3193 auio
.uio_iovcnt
= 1;
3194 auio
.uio_rw
= UIO_READ
;
3195 auio
.uio_segflg
= UIO_USERSPACE
;
3197 auio
.uio_resid
= uap
->count
;
3198 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3199 loff
= auio
.uio_offset
= fp
->f_offset
;
3200 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3201 (int *)0, (u_long
**)0);
3202 fp
->f_offset
= auio
.uio_offset
;
3203 VOP_UNLOCK(vp
, 0, p
);
3209 extern int (**union_vnodeop_p
)(void *);
3210 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3212 if ((uap
->count
== auio
.uio_resid
) &&
3213 (vp
->v_op
== union_vnodeop_p
)) {
3216 lvp
= union_dircache(vp
, p
);
3217 if (lvp
!= NULLVP
) {
3221 * If the directory is opaque,
3222 * then don't show lower entries
3224 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3225 if (va
.va_flags
& OPAQUE
) {
3231 if (lvp
!= NULLVP
) {
3232 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3237 VOP_UNLOCK(lvp
, 0, p
);
3238 fp
->f_data
= (caddr_t
) lvp
;
3240 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3251 if ((uap
->count
== auio
.uio_resid
) &&
3252 (vp
->v_flag
& VROOT
) &&
3253 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3254 struct vnode
*tvp
= vp
;
3255 vp
= vp
->v_mount
->mnt_vnodecovered
;
3257 fp
->f_data
= (caddr_t
) vp
;
3262 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3264 *retval
= uap
->count
- auio
.uio_resid
;
3269 * Set the mode mask for creation of filesystem nodes.
3275 umask(p
, uap
, retval
)
3277 struct umask_args
*uap
;
3280 register struct filedesc
*fdp
;
3282 AUDIT_ARG(mask
, uap
->newmask
);
3284 *retval
= fdp
->fd_cmask
;
3285 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
3290 * Void all references to file by ripping underlying filesystem
3293 struct revoke_args
{
3298 revoke(p
, uap
, retval
)
3300 register struct revoke_args
*uap
;
3303 register struct vnode
*vp
;
3306 struct nameidata nd
;
3308 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
3313 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
3315 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
3316 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
3318 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
3319 VOP_REVOKE(vp
, REVOKEALL
);
3326 * Convert a user file descriptor to a kernel file entry.
3329 getvnode(p
, fd
, fpp
)
3337 if (error
= fdgetf(p
, fd
, &fp
))
3339 if (fp
->f_type
!= DTYPE_VNODE
)
3346 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3347 * The following system calls are designed to support features
3348 * which are specific to the HFS & HFS Plus volume formats
3351 #ifdef __APPLE_API_OBSOLETE
3353 /************************************************/
3354 /* *** Following calls will be deleted soon *** */
3355 /************************************************/
3358 * Make a complex file. A complex file is one with multiple forks (data streams)
3360 struct mkcomplex_args
{
3361 const char *path
; /* pathname of the file to be created */
3362 mode_t mode
; /* access mode for the newly created file */
3363 u_long type
; /* format of the complex file */
3367 mkcomplex(p
,uap
,retval
)
3369 register struct mkcomplex_args
*uap
;
3375 struct nameidata nd
;
3377 /* mkcomplex wants the directory vnode locked so do that here */
3379 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3380 if (error
= namei(&nd
))
3383 /* Set the attributes as specified by the user */
3386 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
3387 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
3389 /* The mkcomplex call promises to release the parent vnode pointer
3390 * even an an error case so don't do it here unless the operation
3391 * is not supported. In that case, there isn't anyone to unlock the parent
3392 * The vnode pointer to the file will also be released.
3397 if (error
== EOPNOTSUPP
)
3404 } /* end of mkcomplex system call */
3407 * Extended stat call which returns volumeid and vnodeid as well as other info
3410 const char *path
; /* pathname of the target file */
3411 struct vstat
*vsb
; /* vstat structure for returned info */
3417 register struct statv_args
*uap
;
3421 return (EOPNOTSUPP
); /* We'll just return an error for now */
3423 } /* end of statv system call */
3426 * Extended lstat call which returns volumeid and vnodeid as well as other info
3428 struct lstatv_args
{
3429 const char *path
; /* pathname of the target file */
3430 struct vstat
*vsb
; /* vstat structure for returned info */
3434 lstatv(p
,uap
,retval
)
3436 register struct lstatv_args
*uap
;
3440 return (EOPNOTSUPP
); /* We'll just return an error for now */
3441 } /* end of lstatv system call */
3444 * Extended fstat call which returns volumeid and vnodeid as well as other info
3446 struct fstatv_args
{
3447 int fd
; /* file descriptor of the target file */
3448 struct vstat
*vsb
; /* vstat structure for returned info */
3452 fstatv(p
,uap
,retval
)
3454 register struct fstatv_args
*uap
;
3458 return (EOPNOTSUPP
); /* We'll just return an error for now */
3459 } /* end of fstatv system call */
3462 /************************************************/
3463 /* *** Preceding calls will be deleted soon *** */
3464 /************************************************/
3466 #endif /* __APPLE_API_OBSOLETE */
3470 * Obtain attribute information about a file system object
3473 struct getattrlist_args
{
3474 const char *path
; /* pathname of the target object */
3475 struct attrlist
* alist
; /* Attributes desired by the user */
3476 void * attributeBuffer
; /* buffer to hold returned attributes */
3477 size_t bufferSize
; /* size of the return buffer */
3478 unsigned long options
; /* options (follow/don't follow) */
3482 getattrlist (p
,uap
,retval
)
3484 register struct getattrlist_args
*uap
;
3489 struct nameidata nd
;
3492 struct attrlist attributelist
;
3495 /* Get the attributes desire and do our parameter checking */
3497 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3498 sizeof (attributelist
)))
3503 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3505 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3506 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3507 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3508 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3509 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3516 /* Get the vnode for the file we are getting info on. */
3517 nameiflags
= LOCKLEAF
| SHAREDLEAF
;
3518 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3519 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3520 (char *)uap
->path
, p
);
3526 /* Set up the UIO structure for use by the vfs routine */
3528 aiov
.iov_base
= uap
->attributeBuffer
;
3529 aiov
.iov_len
= uap
->bufferSize
;
3530 auio
.uio_iov
= &aiov
;
3531 auio
.uio_iovcnt
= 1;
3532 auio
.uio_offset
= 0;
3533 auio
.uio_rw
= UIO_READ
;
3534 auio
.uio_segflg
= UIO_USERSPACE
;
3536 auio
.uio_resid
= uap
->bufferSize
;
3539 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3541 /* Unlock and release the vnode which will have been locked by namei */
3545 /* return the effort if we got one, otherwise return success */
3554 } /* end of getattrlist system call */
3559 * Set attribute information about a file system object
3562 struct setattrlist_args
{
3563 const char *path
; /* pathname of the target object */
3564 struct attrlist
* alist
; /* Attributes being set by the user */
3565 void * attributeBuffer
; /* buffer with attribute values to be set */
3566 size_t bufferSize
; /* size of the return buffer */
3567 unsigned long options
; /* options (follow/don't follow) */
3571 setattrlist (p
,uap
,retval
)
3573 register struct setattrlist_args
*uap
;
3578 struct nameidata nd
;
3581 struct attrlist alist
;
3584 /* Get the attributes desired and do our parameter checking */
3586 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3591 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3594 /* Get the vnode for the file whose attributes are being set. */
3595 nameiflags
= LOCKLEAF
;
3596 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3597 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3598 (char *)uap
->path
, p
);
3603 /* Set up the UIO structure for use by the vfs routine */
3604 aiov
.iov_base
= uap
->attributeBuffer
;
3605 aiov
.iov_len
= uap
->bufferSize
;
3606 auio
.uio_iov
= &aiov
;
3607 auio
.uio_iovcnt
= 1;
3608 auio
.uio_offset
= 0;
3609 auio
.uio_rw
= UIO_WRITE
;
3610 auio
.uio_segflg
= UIO_USERSPACE
;
3612 auio
.uio_resid
= uap
->bufferSize
;
3614 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3620 } /* end of setattrlist system call */
3624 * Obtain attribute information on objects in a directory while enumerating
3625 * the directory. This call does not yet support union mounted directories.
3627 * 1.union mounted directories.
3630 struct getdirentriesattr_args
{
3631 int fd
; /* file descriptor */
3632 struct attrlist
*alist
; /* bit map of requested attributes */
3633 void *buffer
; /* buffer to hold returned attribute info */
3634 size_t buffersize
; /* size of the return buffer */
3635 u_long
*count
; /* the count of entries requested/returned */
3636 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3637 u_long
*newstate
; /* a flag to inform of changes in directory */
3638 u_long options
; /* maybe unused for now */
3642 getdirentriesattr (p
,uap
,retval
)
3644 register struct getdirentriesattr_args
*uap
;
3648 register struct vnode
*vp
;
3656 struct attrlist attributelist
;
3658 AUDIT_ARG(fd
, uap
->fd
);
3660 /* Get the attributes into kernel space */
3661 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3663 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3666 if (error
= getvnode(p
, uap
->fd
, &fp
))
3669 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3671 if ((fp
->f_flag
& FREAD
) == 0)
3673 vp
= (struct vnode
*)fp
->f_data
;
3675 if (vp
->v_type
!= VDIR
)
3678 /* set up the uio structure which will contain the users return buffer */
3679 aiov
.iov_base
= uap
->buffer
;
3680 aiov
.iov_len
= uap
->buffersize
;
3681 auio
.uio_iov
= &aiov
;
3682 auio
.uio_iovcnt
= 1;
3683 auio
.uio_rw
= UIO_READ
;
3684 auio
.uio_segflg
= UIO_USERSPACE
;
3686 auio
.uio_resid
= uap
->buffersize
;
3688 loff
= auio
.uio_offset
= fp
->f_offset
;
3689 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3690 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3691 actualcount
, uap
->options
, &newstate
, &eofflag
,
3692 &actualcount
, ((u_long
**)0), p
->p_ucred
);
3694 VOP_UNLOCK(vp
, 0, p
);
3695 if (error
) return (error
);
3696 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3698 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3700 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3702 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3705 *retval
= eofflag
; /* similar to getdirentries */
3706 return (0); /* return error earlier, an retval of 0 or 1 now */
3708 } /* end of getdirentryattr system call */
3711 * Exchange data between two files
3714 struct exchangedata_args
{
3715 const char *path1
; /* pathname of the first swapee */
3716 const char *path2
; /* pathname of the second swapee */
3717 unsigned long options
; /* options */
3721 exchangedata (p
,uap
,retval
)
3723 register struct exchangedata_args
*uap
;
3728 struct nameidata fnd
, snd
;
3729 struct vnode
*fvp
, *svp
;
3734 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3736 /* Global lock, to prevent race condition, only one exchange at a time */
3737 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3739 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3740 (char *) uap
->path1
, p
);
3742 error
= namei(&fnd
);
3748 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
, UIO_USERSPACE
,
3749 (char *)uap
->path2
, p
);
3751 error
= namei(&snd
);
3759 /* if the files are the same, return an inval error */
3767 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3768 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3770 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3771 if (error
) goto out
;
3773 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3774 if (error
) goto out
;
3776 /* Ok, make the call */
3777 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3779 if (error
== 0 && VPARENT(fvp
) != VPARENT(svp
)) {
3783 VPARENT(fvp
) = VPARENT(svp
);
3792 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3800 } /* end of exchangedata system call */
3802 #ifdef __APPLE_API_OBSOLETE
3804 /************************************************/
3805 /* *** Following calls will be deleted soon *** */
3806 /************************************************/
3809 * Check users access to a file
3812 struct checkuseraccess_args
{
3813 const char *path
; /* pathname of the target file */
3814 uid_t userid
; /* user for whom we are checking access */
3815 gid_t
*groups
; /* Group that we are checking for */
3816 int ngroups
; /* Number of groups being checked */
3817 int accessrequired
; /* needed access to the file */
3818 unsigned long options
; /* options */
3823 checkuseraccess (p
,uap
,retval
)
3825 register struct checkuseraccess_args
*uap
;
3829 register struct vnode
*vp
;
3831 struct nameidata nd
;
3833 int flags
; /*what will actually get passed to access*/
3836 /* Make sure that the number of groups is correct before we do anything */
3838 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3841 /* Verify that the caller is root */
3843 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3846 /* Fill in the credential structure */
3849 cred
.cr_uid
= uap
->userid
;
3850 cred
.cr_ngroups
= uap
->ngroups
;
3851 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3854 /* Get our hands on the file */
3856 nameiflags
= LOCKLEAF
;
3857 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3858 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3860 if (error
= namei(&nd
))
3864 /* Flags == 0 means only check for existence. */
3868 if (uap
->accessrequired
) {
3869 if (uap
->accessrequired
& R_OK
)
3871 if (uap
->accessrequired
& W_OK
)
3873 if (uap
->accessrequired
& X_OK
)
3876 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3885 } /* end of checkuseraccess system call */
3887 /************************************************/
3888 /* *** Preceding calls will be deleted soon *** */
3889 /************************************************/
3891 #endif /* __APPLE_API_OBSOLETE */
3895 struct searchfs_args
{
3897 struct fssearchblock
*searchblock
;
3901 struct searchstate
*state
;
3906 searchfs (p
,uap
,retval
)
3908 register struct searchfs_args
*uap
;
3912 register struct vnode
*vp
;
3915 struct nameidata nd
;
3916 struct fssearchblock searchblock
;
3917 struct searchstate
*state
;
3918 struct attrlist
*returnattrs
;
3919 void *searchparams1
,*searchparams2
;
3927 /* Start by copying in fsearchblock paramater list */
3929 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3932 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3933 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3934 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3937 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3938 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3940 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3942 /* Now set up the various pointers to the correct place in our newly allocated memory */
3944 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3945 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3946 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3948 /* Now copy in the stuff given our local variables. */
3950 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3953 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3956 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3959 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3962 /* set up the uio structure which will contain the users return buffer */
3964 aiov
.iov_base
= searchblock
.returnbuffer
;
3965 aiov
.iov_len
= searchblock
.returnbuffersize
;
3966 auio
.uio_iov
= &aiov
;
3967 auio
.uio_iovcnt
= 1;
3968 auio
.uio_rw
= UIO_READ
;
3969 auio
.uio_segflg
= UIO_USERSPACE
;
3971 auio
.uio_resid
= searchblock
.returnbuffersize
;
3973 nameiflags
= LOCKLEAF
;
3974 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3975 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3976 (char *)uap
->path
, p
);
3986 * If searchblock.maxmatches == 0, then skip the search. This has happened
3987 * before and sometimes the underlyning code doesnt deal with it well.
3989 if (searchblock
.maxmatches
== 0) {
3995 Allright, we have everything we need, so lets make that call.
3997 We keep special track of the return value from the file system:
3998 EAGAIN is an acceptable error condition that shouldn't keep us
3999 from copying out any results...
4002 fserror
= VOP_SEARCHFS(vp
,
4005 &searchblock
.searchattrs
,
4006 searchblock
.maxmatches
,
4007 &searchblock
.timelimit
,
4019 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4020 search state. Everything was already put into he return buffer by the vop call. */
4022 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
4025 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
4032 FREE(searchparams1
,M_TEMP
);
4037 } /* end of searchfs system call */
4041 * Make a filesystem-specific control call:
4044 const char *path
; /* pathname of the target object */
4045 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
4046 caddr_t data
; /* pointer to argument buffer */
4047 u_long options
; /* options for fsctl processing */
4051 fsctl (p
,uap
,retval
)
4053 struct fsctl_args
*uap
;
4058 struct nameidata nd
;
4060 u_long cmd
= uap
->cmd
;
4061 register u_int size
;
4062 #define STK_PARAMS 128
4063 char stkbuf
[STK_PARAMS
];
4066 size
= IOCPARM_LEN(cmd
);
4067 if (size
> IOCPARM_MAX
) return (EINVAL
);
4070 if (size
> sizeof (stkbuf
)) {
4071 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4079 error
= copyin(uap
->data
, data
, (u_int
)size
);
4080 if (error
) goto FSCtl_Exit
;
4082 *(caddr_t
*)data
= uap
->data
;
4084 } else if ((cmd
& IOC_OUT
) && size
) {
4086 * Zero the buffer so the user always
4087 * gets back something deterministic.
4090 } else if (cmd
& IOC_VOID
)
4091 *(caddr_t
*)data
= uap
->data
;
4093 /* Get the vnode for the file we are getting info on: */
4094 nameiflags
= LOCKLEAF
;
4095 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4096 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
4097 if (error
= namei(&nd
)) goto FSCtl_Exit
;
4099 /* Invoke the filesystem-specific code */
4100 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
4105 * Copy any data to user, size was
4106 * already set and checked above.
4108 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
4111 if (memp
) kfree(memp
, size
);
4115 /* end of fsctl system call */
4118 * An in-kernel sync for power management to call.
4120 __private_extern__
int
4123 boolean_t funnel_state
;
4126 struct sync_args data
;
4130 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4132 error
= sync(current_proc(), &data
, &retval
);
4134 thread_funnel_set(kernel_flock
, funnel_state
);
4137 } /* end of sync_internal call */
4141 // XXXdbg fmod watching calls
4142 #define NUM_CHANGE_NODES 256
4143 static int changed_init
=0;
4144 static volatile int fmod_watch_enabled
= 0;
4145 static simple_lock_data_t changed_nodes_lock
; // guard access
4146 static volatile struct vnode
*changed_nodes
[NUM_CHANGE_NODES
];
4147 static volatile pid_t changed_nodes_pid
[NUM_CHANGE_NODES
];
4148 static volatile int changed_rd_index
=0, changed_wr_index
=0;
4149 static volatile int notifier_sleeping
=0;
4153 notify_filemod_watchers(struct vnode
*vp
, struct proc
*p
)
4157 // only want notification on regular files.
4158 if (vp
->v_type
!= VREG
|| fmod_watch_enabled
== 0) {
4162 // grab a reference so it doesn't go away
4163 if (vget(vp
, 0, p
) != 0) {
4168 simple_lock(&changed_nodes_lock
);
4170 // If the table is full, block until it clears up
4171 if (((changed_wr_index
+1) % NUM_CHANGE_NODES
) == changed_rd_index
) {
4172 simple_unlock(&changed_nodes_lock
);
4174 notifier_sleeping
++;
4175 // wait up to 10 seconds for the queue to drain
4176 ret
= tsleep((caddr_t
)&changed_wr_index
, PINOD
, "changed_nodes_full", 10*hz
);
4177 if (ret
!= 0 || fmod_watch_enabled
== 0) {
4178 notifier_sleeping
--;
4179 printf("notify_filemod: err %d from tsleep/enabled %d. bailing out (vp 0x%x).\n",
4180 ret
, fmod_watch_enabled
, vp
);
4185 notifier_sleeping
--;
4189 // insert our new guy
4190 if (changed_nodes
[changed_wr_index
] != NULL
) {
4191 panic("notify_fmod_watchers: index %d is 0x%x, not null!\n",
4192 changed_wr_index
, changed_nodes
[changed_wr_index
]);
4194 changed_nodes
[changed_wr_index
] = vp
;
4195 changed_nodes_pid
[changed_wr_index
] = current_proc()->p_pid
;
4196 changed_wr_index
= (changed_wr_index
+ 1) % NUM_CHANGE_NODES
;
4198 simple_unlock(&changed_nodes_lock
);
4200 wakeup((caddr_t
)&changed_rd_index
);
4204 struct fmod_watch_args
{
4212 fmod_watch(struct proc
*p
, struct fmod_watch_args
*uap
, register_t
*retval
)
4214 int fd
, didhold
= 0;
4215 struct filedesc
*fdp
;
4219 int type
, indx
, error
, need_wakeup
=0;
4221 struct nameidata nd
;
4222 extern struct fileops vnops
;
4225 if (fmod_watch_enabled
== 0) {
4232 if (changed_init
== 0) {
4234 simple_lock_init(&changed_nodes_lock
);
4237 if (changed_rd_index
== changed_wr_index
) {
4238 // there's nothing to do, go to sleep
4239 error
= tsleep((caddr_t
)&changed_rd_index
, PUSER
|PCATCH
, "changed_nodes_empty", 0);
4241 // XXXdbg - what if after we unblock the changed_nodes
4242 // table is full? We should wakeup() the writer.
4248 simple_lock(&changed_nodes_lock
);
4250 vp
= (struct vnode
*)changed_nodes
[changed_rd_index
];
4251 pid
= changed_nodes_pid
[changed_rd_index
];
4253 changed_nodes
[changed_rd_index
] = NULL
;
4254 changed_rd_index
= (changed_rd_index
+ 1) % NUM_CHANGE_NODES
;
4257 panic("watch_file_changes: Someone put a null vnode in my table! (%d %d)\n",
4258 changed_rd_index
, changed_wr_index
);
4261 simple_unlock(&changed_nodes_lock
);
4263 // if the writers are blocked, wake them up as we just freed up
4264 // some space for them.
4265 if (notifier_sleeping
> 0) {
4266 wakeup((caddr_t
)&changed_wr_index
);
4269 if (vp
->v_type
!= VREG
) {
4274 if ((error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
)) != 0) {
4275 printf("fmod_watch: vn_lock returned %d\n", error
);
4279 // first copy out the name
4284 MALLOC(buff
, char *, len
, M_TEMP
, M_WAITOK
);
4285 error
= vn_getpath(vp
, buff
, &len
);
4288 error
= copyout(buff
, (void *)uap
->pathbuf
, len
);
4298 // now copy out the pid of the person that changed the file
4300 if ((error
= copyout((caddr_t
)&pid
, (void *)uap
->pid
, sizeof(pid_t
))) != 0) {
4301 printf("fmod_watch: failed to copy out the pid (%d)\n", pid
);
4306 // now create a file descriptor for this vnode
4309 if (error
= falloc(p
, &fp
, &indx
)) {
4310 printf("fmod_watch: failed to allocate an fd...\n");
4314 if ((error
= copyout((caddr_t
)&indx
, (void *)uap
->new_fd
, sizeof(int))) != 0) {
4315 printf("fmod_watch: failed to copy out the new fd (%d)\n", indx
);
4319 fp
->f_flag
= flags
& FMASK
;
4320 fp
->f_type
= DTYPE_VNODE
;
4322 fp
->f_data
= (caddr_t
)vp
;
4324 if (UBCINFOEXISTS(vp
) && ((didhold
= ubc_hold(vp
)) == 0)) {
4328 error
= VOP_OPEN(vp
, flags
, p
->p_ucred
, p
);
4333 VOP_UNLOCK(vp
, 0, p
);
4335 *fdflags(p
, indx
) &= ~UF_RESERVED
;
4337 // note: we explicitly don't vrele() here because it
4338 // happens when the fd is closed.
4350 VOP_UNLOCK(vp
, 0, p
);
4352 vrele(vp
); // undoes the vref() in notify_filemod_watchers()
4359 enable_fmod_watching(register_t
*retval
)
4367 // XXXdbg for now we only allow one watcher at a time.
4368 if (fmod_watch_enabled
) {
4372 fmod_watch_enabled
++;
4378 disable_fmod_watching(register_t
*retval
)
4380 fmod_watch_enabled
--;
4381 if (fmod_watch_enabled
< 0) {
4382 panic("fmod_watching: too many disables! (%d)\n", fmod_watch_enabled
);
4385 // if we're the last guy, clear out any remaining vnodes
4386 // in the table so they don't remain referenced.
4388 if (fmod_watch_enabled
== 0) {
4390 for(i
=changed_rd_index
; i
!= changed_wr_index
; ) {
4391 if (changed_nodes
[i
] == NULL
) {
4392 panic("disable_fmod_watch: index %d is NULL!\n", i
);
4394 vrele((struct vnode
*)changed_nodes
[i
]);
4395 changed_nodes
[i
] = NULL
;
4396 i
= (i
+ 1) % NUM_CHANGE_NODES
;
4398 changed_wr_index
= changed_rd_index
= 0;
4401 // wake up anyone that may be waiting for the
4402 // queue to clear out.
4404 while(notifier_sleeping
) {
4405 wakeup((caddr_t
)&changed_wr_index
);
4407 // yield the cpu so the notifiers can run
4408 tsleep((caddr_t
)&fmod_watch_enabled
, PINOD
, "disable_fmod_watch", 1);
4416 struct fmod_watch_enable_args
{
4421 fmod_watch_enable(struct proc
*p
, struct fmod_watch_enable_args
*uap
, register_t
*retval
)
4425 if (uap
->on_or_off
!= 0) {
4426 ret
= enable_fmod_watching(retval
);
4428 ret
= disable_fmod_watching(retval
);