2 * Copyright (c) 1995-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
69 #include <sys/vnode.h>
70 #include <sys/mount.h>
73 #include <sys/malloc.h>
74 #include <sys/dirent.h>
76 #include <sys/sysctl.h>
78 #include <sys/quota.h>
80 #include <bsm/audit_kernel.h>
81 #include <bsm/audit_kevents.h>
83 #include <machine/cons.h>
84 #include <miscfs/specfs/specdev.h>
86 #include <architecture/byte_order.h>
88 struct lock__bsd__ exchangelock
;
91 * The currently logged-in user, for ownership of files/directories whose on-disk
92 * permissions are ignored:
96 static int change_dir
__P((struct nameidata
*ndp
, struct proc
*p
));
97 static void checkdirs
__P((struct vnode
*olddp
));
98 static void enablequotas
__P((struct proc
*p
, struct mount
*mp
));
99 void notify_filemod_watchers(struct vnode
*vp
, struct proc
*p
);
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
| AUDITVNPATH1
, 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
| AUDITVNPATH1
,
1791 UIO_USERSPACE
, uap
->path
, p
);
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 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2065 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2067 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2070 vattr
.va_flags
= uap
->flags
;
2071 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2072 VOP_UNLOCK(vp
, 0, p
);
2077 * Change mode of a file given path name.
2085 chmod(p
, uap
, retval
)
2087 register struct chmod_args
*uap
;
2090 register struct vnode
*vp
;
2093 struct nameidata nd
;
2095 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2097 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2102 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2103 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2105 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2106 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2113 * Change mode of a file given a file descriptor.
2115 struct fchmod_args
{
2121 fchmod(p
, uap
, retval
)
2123 register struct fchmod_args
*uap
;
2131 AUDIT_ARG(fd
, uap
->fd
);
2132 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2133 if (error
= getvnode(p
, uap
->fd
, &fp
))
2136 vp
= (struct vnode
*)fp
->f_data
;
2137 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2138 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2140 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2143 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2144 AUDIT_ARG(mode
, (mode_t
)vattr
.va_mode
);
2145 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2147 VOP_UNLOCK(vp
, 0, p
);
2153 * Set ownership given a path name.
2162 chown(p
, uap
, retval
)
2164 register struct chown_args
*uap
;
2167 register struct vnode
*vp
;
2170 struct nameidata nd
;
2172 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2174 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2181 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2182 * by looking for chown() calls on /dev/console from a console process.
2184 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2185 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2186 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2187 console_user
= uap
->uid
;
2190 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2191 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2193 vattr
.va_uid
= uap
->uid
;
2194 vattr
.va_gid
= uap
->gid
;
2195 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2202 * Set ownership given a file descriptor.
2204 struct fchown_args
{
2211 fchown(p
, uap
, retval
)
2213 register struct fchown_args
*uap
;
2221 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2222 AUDIT_ARG(fd
, uap
->fd
);
2224 if (error
= getvnode(p
, uap
->fd
, &fp
))
2227 vp
= (struct vnode
*)fp
->f_data
;
2228 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2229 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2231 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2234 vattr
.va_uid
= uap
->uid
;
2235 vattr
.va_gid
= uap
->gid
;
2236 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2238 VOP_UNLOCK(vp
, 0, p
);
2243 getutimes(usrtvp
, tsp
)
2244 const struct timeval
*usrtvp
;
2245 struct timespec
*tsp
;
2247 struct timeval tv
[2];
2250 if (usrtvp
== NULL
) {
2252 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2255 if ((error
= copyin((void *)usrtvp
, (void *)tv
, sizeof (tv
))) != 0)
2257 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2258 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
2264 setutimes(p
, vp
, ts
, nullflag
)
2267 const struct timespec
*ts
;
2273 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2274 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2278 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2281 vattr
.va_atime
= ts
[0];
2282 vattr
.va_mtime
= ts
[1];
2284 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
2285 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2287 VOP_UNLOCK(vp
, 0, p
);
2293 * Set the access and modification times of a file.
2295 struct utimes_args
{
2297 struct timeval
*tptr
;
2301 utimes(p
, uap
, retval
)
2303 register struct utimes_args
*uap
;
2306 struct timespec ts
[2];
2307 struct timeval
*usrtvp
;
2309 struct nameidata nd
;
2311 /* AUDIT: Needed to change the order of operations to do the
2312 * name lookup first because auditing wants the path.
2314 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2320 if ((error
= getutimes(usrtvp
, ts
)) != 0) {
2324 error
= setutimes(p
, nd
.ni_vp
, ts
, usrtvp
== NULL
);
2330 * Set the access and modification times of a file.
2332 struct futimes_args
{
2334 struct timeval
*tptr
;
2338 futimes(p
, uap
, retval
)
2340 register struct futimes_args
*uap
;
2343 struct timespec ts
[2];
2345 struct timeval
*usrtvp
;
2348 AUDIT_ARG(fd
, uap
->fd
);
2350 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2352 if ((error
= getvnode(p
, uap
->fd
, &fp
)) != 0)
2355 return setutimes(p
, (struct vnode
*)fp
->f_data
, ts
, usrtvp
== NULL
);
2359 * Truncate a file given its path name.
2361 struct truncate_args
{
2363 #ifdef DOUBLE_ALIGN_PARAMS
2370 truncate(p
, uap
, retval
)
2372 register struct truncate_args
*uap
;
2375 register struct vnode
*vp
;
2378 struct nameidata nd
;
2380 if (uap
->length
< 0)
2382 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2383 if (error
= namei(&nd
))
2386 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2387 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2388 if (vp
->v_type
== VDIR
)
2390 else if ((error
= vn_writechk(vp
)) == 0 &&
2391 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2393 vattr
.va_size
= uap
->length
;
2394 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2401 * Truncate a file given a file descriptor.
2403 struct ftruncate_args
{
2405 #ifdef DOUBLE_ALIGN_PARAMS
2412 ftruncate(p
, uap
, retval
)
2414 register struct ftruncate_args
*uap
;
2422 AUDIT_ARG(fd
, uap
->fd
);
2423 if (uap
->length
< 0)
2426 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2429 if (fp
->f_type
== DTYPE_PSXSHM
) {
2430 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2432 if (fp
->f_type
!= DTYPE_VNODE
)
2435 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
2437 if ((fp
->f_flag
& FWRITE
) == 0)
2439 vp
= (struct vnode
*)fp
->f_data
;
2440 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2441 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2442 if (vp
->v_type
== VDIR
)
2444 else if ((error
= vn_writechk(vp
)) == 0) {
2446 vattr
.va_size
= uap
->length
;
2447 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2449 VOP_UNLOCK(vp
, 0, p
);
2455 * Truncate a file given its path name.
2457 struct otruncate_args
{
2463 otruncate(p
, uap
, retval
)
2465 register struct otruncate_args
*uap
;
2468 struct truncate_args
/* {
2469 syscallarg(char *) path;
2470 #ifdef DOUBLE_ALIGN_PARAMS
2471 syscallarg(int) pad;
2473 syscallarg(off_t) length;
2476 nuap
.path
= uap
->path
;
2477 nuap
.length
= uap
->length
;
2478 return (truncate(p
, &nuap
, retval
));
2482 * Truncate a file given a file descriptor.
2484 struct oftruncate_args
{
2490 oftruncate(p
, uap
, retval
)
2492 register struct oftruncate_args
*uap
;
2495 struct ftruncate_args
/* {
2497 #ifdef DOUBLE_ALIGN_PARAMS
2498 syscallarg(int) pad;
2500 syscallarg(off_t) length;
2504 nuap
.length
= uap
->length
;
2505 return (ftruncate(p
, &nuap
, retval
));
2507 #endif /* COMPAT_43 */
2510 * Sync an open file.
2517 fsync(p
, uap
, retval
)
2519 struct fsync_args
*uap
;
2522 register struct vnode
*vp
;
2526 if (error
= getvnode(p
, uap
->fd
, &fp
))
2530 vp
= (struct vnode
*)fp
->f_data
;
2531 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2532 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2533 VOP_UNLOCK(vp
, 0, p
);
2539 * Duplicate files. Source must be a file, target must be a file or
2543 struct copyfile_args
{
2551 copyfile(p
, uap
, retval
)
2553 register struct copyfile_args
*uap
;
2556 register struct vnode
*tvp
, *fvp
, *tdvp
;
2557 register struct ucred
*cred
= p
->p_ucred
;
2558 struct nameidata fromnd
, tond
;
2561 /* Check that the flags are valid. */
2563 if (uap
->flags
& ~CPF_MASK
) {
2567 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
2568 UIO_USERSPACE
, uap
->from
, p
);
2569 if (error
= namei(&fromnd
))
2573 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
2574 UIO_USERSPACE
, uap
->to
, p
);
2575 if (error
= namei(&tond
)) {
2582 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2588 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2593 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2599 * If source is the same as the destination (that is the
2600 * same inode number) then there is nothing to do.
2601 * (fixed to have POSIX semantics - CSM 3/2/98)
2607 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2609 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2618 vrele(tond
.ni_startdir
);
2619 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2621 if (fromnd
.ni_startdir
)
2622 vrele(fromnd
.ni_startdir
);
2623 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2630 * Rename files. Source and destination must either both be directories,
2631 * or both not be directories. If target is a directory, it must be empty.
2633 struct rename_args
{
2639 rename(p
, uap
, retval
)
2641 register struct rename_args
*uap
;
2644 register struct vnode
*tvp
, *fvp
, *tdvp
;
2645 struct nameidata fromnd
, tond
;
2648 int casesense
,casepres
;
2649 char *nameptr
=NULL
, *oname
;
2650 struct vnode
*oparent
;
2655 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
| AUDITVNPATH1
,
2656 UIO_USERSPACE
, uap
->from
, p
);
2657 error
= namei(&fromnd
);
2662 NDINIT(&tond
, RENAME
,
2663 LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
2664 UIO_USERSPACE
, uap
->to
, p
);
2665 if (fromnd
.ni_vp
->v_type
== VDIR
)
2666 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2667 if (error
= namei(&tond
)) {
2668 /* Translate error code for rename("dir1", "dir2/."). */
2669 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
2671 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2672 vrele(fromnd
.ni_dvp
);
2680 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2683 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2691 * If source is the same as the destination (that is the
2692 * same inode number) then there is nothing to do... EXCEPT if the
2693 * underlying file system supports case insensitivity and is case
2694 * preserving. Then a special case is made, i.e. foo -> Foo.
2696 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2697 * and _PC_CASE_PRESERVING can have this exception, and they need to
2698 * handle the special case of getting the same vnode as target and
2699 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2700 * so not to cause locking problems. There is a single reference on tvp.
2702 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2703 * that correct behaviour then is just to remove the source (link)
2705 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
) {
2706 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2707 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2708 fromnd
.ni_cnd
.cn_namelen
)) {
2709 error
= -1; /* Default "unix" behavior */
2710 } else { /* probe for file system specifics */
2711 if (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
))
2713 if (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
))
2715 if (!casesense
&& casepres
)
2716 vput(tvp
); /* Unlock target and drop ref */
2721 * Allow the renaming of mount points.
2722 * - target must not exist
2723 * - target must reside in the same directory as source
2724 * - union mounts cannot be renamed
2725 * - "/" cannot be renamed
2728 (fvp
->v_flag
& VROOT
) &&
2729 (fvp
->v_type
== VDIR
) &&
2731 (fvp
->v_mountedhere
== NULL
) &&
2732 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2733 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2734 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2736 /* switch fvp to the covered vnode */
2737 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2745 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2746 if (fromnd
.ni_dvp
!= tdvp
)
2747 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2749 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2751 // XXXdbg - so that the fs won't block when it vrele()'s
2752 // these nodes before returning
2753 if (fromnd
.ni_dvp
!= tdvp
) {
2757 // save these off so we can later verify that fvp is the same
2759 oparent
= VPARENT(fvp
);
2761 nameptr
= add_name(tond
.ni_cnd
.cn_nameptr
,
2762 tond
.ni_cnd
.cn_namelen
,
2763 tond
.ni_cnd
.cn_hash
, 0);
2766 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2767 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2769 remove_name(nameptr
);
2771 if (fromnd
.ni_dvp
!= tdvp
) {
2779 * update filesystem's mount point data
2782 char *cp
, *pathend
, *mpname
;
2789 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2790 mp
= fvp
->v_mountedhere
;
2792 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2797 VOP_UNLOCK(fvp
, 0, p
);
2799 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2800 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2802 /* find current mount point prefix */
2803 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2804 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2808 /* find last component of target name */
2809 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2813 /* append name to prefix */
2814 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2815 bzero(pathend
, maxlen
);
2816 strncpy(pathend
, mpname
, maxlen
- 1);
2818 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2825 // fix up name & parent pointers. note that we first
2826 // check that fvp has the same name/parent pointers it
2827 // had before the rename call and then we lock fvp so
2828 // that it won't go away on us when we hit blocking
2829 // points like remove_name() or vrele() where fvp could
2831 if (oname
== VNAME(fvp
) && oparent
== VPARENT(fvp
) && vget(fvp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
) == 0) {
2833 char *tmp
= VNAME(fvp
);
2838 VNAME(fvp
) = nameptr
;
2841 if (fromnd
.ni_dvp
!= tdvp
) {
2842 struct vnode
*tmpvp
;
2844 tmpvp
= VPARENT(fvp
);
2845 VPARENT(fvp
) = NULL
;
2848 VPARENT(fvp
) = tdvp
;
2850 // note: we don't vrele() tdvp because we want to keep
2851 // the reference until fvp gets recycled
2857 // if fvp isn't kosher anymore and we locked tdvp,
2859 if (fromnd
.ni_dvp
!= tdvp
) {
2862 remove_name(nameptr
);
2867 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2874 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2875 vrele(fromnd
.ni_dvp
);
2879 vrele(tond
.ni_startdir
);
2880 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2882 if (fromnd
.ni_startdir
)
2883 vrele(fromnd
.ni_startdir
);
2884 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2891 * Make a directory file.
2899 mkdir(p
, uap
, retval
)
2901 register struct mkdir_args
*uap
;
2904 register struct vnode
*vp
;
2907 struct nameidata nd
;
2910 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2912 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2913 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2919 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2920 if (nd
.ni_dvp
== vp
)
2928 vattr
.va_type
= VDIR
;
2929 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2930 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2932 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
2934 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2936 VNAME(nd
.ni_vp
) = nameptr
;
2937 if (VPARENT(nd
.ni_vp
) == NULL
&& vget(nd
.ni_dvp
, 0, p
) == 0) {
2938 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
2947 * Remove a directory file.
2954 rmdir(p
, uap
, retval
)
2956 struct rmdir_args
*uap
;
2959 register struct vnode
*vp
;
2961 struct nameidata nd
;
2964 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
2970 if (vp
->v_type
!= VDIR
) {
2975 * No rmdir "." please.
2977 if (nd
.ni_dvp
== vp
) {
2982 * The root of a mounted filesystem cannot be deleted.
2984 if (vp
->v_flag
& VROOT
)
2988 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2989 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2990 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2992 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2993 if (nd
.ni_dvp
== vp
)
3004 * Read a block of directory entries in a file system independent format.
3006 struct ogetdirentries_args
{
3013 ogetdirentries(p
, uap
, retval
)
3015 register struct ogetdirentries_args
*uap
;
3018 register struct vnode
*vp
;
3020 struct uio auio
, kuio
;
3021 struct iovec aiov
, kiov
;
3022 struct dirent
*dp
, *edp
;
3024 int error
, eofflag
, readcnt
;
3027 AUDIT_ARG(fd
, uap
->fd
);
3028 if (error
= getvnode(p
, uap
->fd
, &fp
))
3031 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3033 if ((fp
->f_flag
& FREAD
) == 0)
3035 vp
= (struct vnode
*)fp
->f_data
;
3037 if (vp
->v_type
!= VDIR
)
3039 aiov
.iov_base
= uap
->buf
;
3040 aiov
.iov_len
= uap
->count
;
3041 auio
.uio_iov
= &aiov
;
3042 auio
.uio_iovcnt
= 1;
3043 auio
.uio_rw
= UIO_READ
;
3044 auio
.uio_segflg
= UIO_USERSPACE
;
3046 auio
.uio_resid
= uap
->count
;
3047 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3048 loff
= auio
.uio_offset
= fp
->f_offset
;
3049 # if (BYTE_ORDER != LITTLE_ENDIAN)
3050 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
3051 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3052 (int *)0, (u_long
**)0);
3053 fp
->f_offset
= auio
.uio_offset
;
3058 kuio
.uio_iov
= &kiov
;
3059 kuio
.uio_segflg
= UIO_SYSSPACE
;
3060 kiov
.iov_len
= uap
->count
;
3061 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
3062 kiov
.iov_base
= dirbuf
;
3063 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
3064 (int *)0, (u_long
**)0);
3065 fp
->f_offset
= kuio
.uio_offset
;
3067 readcnt
= uap
->count
- kuio
.uio_resid
;
3068 edp
= (struct dirent
*)&dirbuf
[readcnt
];
3069 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
3070 # if (BYTE_ORDER == LITTLE_ENDIAN)
3072 * The expected low byte of
3073 * dp->d_namlen is our dp->d_type.
3074 * The high MBZ byte of dp->d_namlen
3075 * is our dp->d_namlen.
3077 dp
->d_type
= dp
->d_namlen
;
3081 * The dp->d_type is the high byte
3082 * of the expected dp->d_namlen,
3083 * so must be zero'ed.
3087 if (dp
->d_reclen
> 0) {
3088 dp
= (struct dirent
*)
3089 ((char *)dp
+ dp
->d_reclen
);
3096 error
= uiomove(dirbuf
, readcnt
, &auio
);
3098 FREE(dirbuf
, M_TEMP
);
3100 VOP_UNLOCK(vp
, 0, p
);
3106 extern int (**union_vnodeop_p
)(void *);
3107 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3109 if ((uap
->count
== auio
.uio_resid
) &&
3110 (vp
->v_op
== union_vnodeop_p
)) {
3113 lvp
= union_dircache(vp
, p
);
3114 if (lvp
!= NULLVP
) {
3118 * If the directory is opaque,
3119 * then don't show lower entries
3121 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3122 if (va
.va_flags
& OPAQUE
) {
3128 if (lvp
!= NULLVP
) {
3129 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3134 VOP_UNLOCK(lvp
, 0, p
);
3135 fp
->f_data
= (caddr_t
) lvp
;
3137 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3148 if ((uap
->count
== auio
.uio_resid
) &&
3149 (vp
->v_flag
& VROOT
) &&
3150 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3151 struct vnode
*tvp
= vp
;
3152 vp
= vp
->v_mount
->mnt_vnodecovered
;
3154 fp
->f_data
= (caddr_t
) vp
;
3159 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3161 *retval
= uap
->count
- auio
.uio_resid
;
3164 #endif /* COMPAT_43 */
3167 * Read a block of directory entries in a file system independent format.
3169 struct getdirentries_args
{
3176 getdirentries(p
, uap
, retval
)
3178 register struct getdirentries_args
*uap
;
3181 register struct vnode
*vp
;
3188 AUDIT_ARG(fd
, uap
->fd
);
3189 error
= getvnode(p
, uap
->fd
, &fp
);
3193 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3195 if ((fp
->f_flag
& FREAD
) == 0)
3197 vp
= (struct vnode
*)fp
->f_data
;
3199 if (vp
->v_type
!= VDIR
)
3201 aiov
.iov_base
= uap
->buf
;
3202 aiov
.iov_len
= uap
->count
;
3203 auio
.uio_iov
= &aiov
;
3204 auio
.uio_iovcnt
= 1;
3205 auio
.uio_rw
= UIO_READ
;
3206 auio
.uio_segflg
= UIO_USERSPACE
;
3208 auio
.uio_resid
= uap
->count
;
3209 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3210 loff
= auio
.uio_offset
= fp
->f_offset
;
3211 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3212 (int *)0, (u_long
**)0);
3213 fp
->f_offset
= auio
.uio_offset
;
3214 VOP_UNLOCK(vp
, 0, p
);
3220 extern int (**union_vnodeop_p
)(void *);
3221 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3223 if ((uap
->count
== auio
.uio_resid
) &&
3224 (vp
->v_op
== union_vnodeop_p
)) {
3227 lvp
= union_dircache(vp
, p
);
3228 if (lvp
!= NULLVP
) {
3232 * If the directory is opaque,
3233 * then don't show lower entries
3235 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3236 if (va
.va_flags
& OPAQUE
) {
3242 if (lvp
!= NULLVP
) {
3243 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3248 VOP_UNLOCK(lvp
, 0, p
);
3249 fp
->f_data
= (caddr_t
) lvp
;
3251 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3262 if ((uap
->count
== auio
.uio_resid
) &&
3263 (vp
->v_flag
& VROOT
) &&
3264 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3265 struct vnode
*tvp
= vp
;
3266 vp
= vp
->v_mount
->mnt_vnodecovered
;
3268 fp
->f_data
= (caddr_t
) vp
;
3273 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3275 *retval
= uap
->count
- auio
.uio_resid
;
3280 * Set the mode mask for creation of filesystem nodes.
3286 umask(p
, uap
, retval
)
3288 struct umask_args
*uap
;
3291 register struct filedesc
*fdp
;
3293 AUDIT_ARG(mask
, uap
->newmask
);
3295 *retval
= fdp
->fd_cmask
;
3296 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
3301 * Void all references to file by ripping underlying filesystem
3304 struct revoke_args
{
3309 revoke(p
, uap
, retval
)
3311 register struct revoke_args
*uap
;
3314 register struct vnode
*vp
;
3317 struct nameidata nd
;
3319 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
3324 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
3326 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
3327 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
3329 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
3330 VOP_REVOKE(vp
, REVOKEALL
);
3337 * Convert a user file descriptor to a kernel file entry.
3340 getvnode(p
, fd
, fpp
)
3348 if (error
= fdgetf(p
, fd
, &fp
))
3350 if (fp
->f_type
!= DTYPE_VNODE
)
3357 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3358 * The following system calls are designed to support features
3359 * which are specific to the HFS & HFS Plus volume formats
3362 #ifdef __APPLE_API_OBSOLETE
3364 /************************************************/
3365 /* *** Following calls will be deleted soon *** */
3366 /************************************************/
3369 * Make a complex file. A complex file is one with multiple forks (data streams)
3371 struct mkcomplex_args
{
3372 const char *path
; /* pathname of the file to be created */
3373 mode_t mode
; /* access mode for the newly created file */
3374 u_long type
; /* format of the complex file */
3378 mkcomplex(p
,uap
,retval
)
3380 register struct mkcomplex_args
*uap
;
3386 struct nameidata nd
;
3388 /* mkcomplex wants the directory vnode locked so do that here */
3390 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3391 if (error
= namei(&nd
))
3394 /* Set the attributes as specified by the user */
3397 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
3398 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
3400 /* The mkcomplex call promises to release the parent vnode pointer
3401 * even an an error case so don't do it here unless the operation
3402 * is not supported. In that case, there isn't anyone to unlock the parent
3403 * The vnode pointer to the file will also be released.
3408 if (error
== EOPNOTSUPP
)
3415 } /* end of mkcomplex system call */
3418 * Extended stat call which returns volumeid and vnodeid as well as other info
3421 const char *path
; /* pathname of the target file */
3422 struct vstat
*vsb
; /* vstat structure for returned info */
3428 register struct statv_args
*uap
;
3432 return (EOPNOTSUPP
); /* We'll just return an error for now */
3434 } /* end of statv system call */
3437 * Extended lstat call which returns volumeid and vnodeid as well as other info
3439 struct lstatv_args
{
3440 const char *path
; /* pathname of the target file */
3441 struct vstat
*vsb
; /* vstat structure for returned info */
3445 lstatv(p
,uap
,retval
)
3447 register struct lstatv_args
*uap
;
3451 return (EOPNOTSUPP
); /* We'll just return an error for now */
3452 } /* end of lstatv system call */
3455 * Extended fstat call which returns volumeid and vnodeid as well as other info
3457 struct fstatv_args
{
3458 int fd
; /* file descriptor of the target file */
3459 struct vstat
*vsb
; /* vstat structure for returned info */
3463 fstatv(p
,uap
,retval
)
3465 register struct fstatv_args
*uap
;
3469 return (EOPNOTSUPP
); /* We'll just return an error for now */
3470 } /* end of fstatv system call */
3473 /************************************************/
3474 /* *** Preceding calls will be deleted soon *** */
3475 /************************************************/
3477 #endif /* __APPLE_API_OBSOLETE */
3481 * Obtain attribute information about a file system object
3484 struct getattrlist_args
{
3485 const char *path
; /* pathname of the target object */
3486 struct attrlist
* alist
; /* Attributes desired by the user */
3487 void * attributeBuffer
; /* buffer to hold returned attributes */
3488 size_t bufferSize
; /* size of the return buffer */
3489 unsigned long options
; /* options (follow/don't follow) */
3493 getattrlist (p
,uap
,retval
)
3495 register struct getattrlist_args
*uap
;
3500 struct nameidata nd
;
3503 struct attrlist attributelist
;
3506 /* Get the attributes desire and do our parameter checking */
3508 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3509 sizeof (attributelist
)))
3514 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3516 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3517 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3518 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3519 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3520 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3527 /* Get the vnode for the file we are getting info on. */
3528 nameiflags
= LOCKLEAF
| SHAREDLEAF
;
3529 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3530 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3531 (char *)uap
->path
, p
);
3537 /* Set up the UIO structure for use by the vfs routine */
3539 aiov
.iov_base
= uap
->attributeBuffer
;
3540 aiov
.iov_len
= uap
->bufferSize
;
3541 auio
.uio_iov
= &aiov
;
3542 auio
.uio_iovcnt
= 1;
3543 auio
.uio_offset
= 0;
3544 auio
.uio_rw
= UIO_READ
;
3545 auio
.uio_segflg
= UIO_USERSPACE
;
3547 auio
.uio_resid
= uap
->bufferSize
;
3550 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3552 /* Unlock and release the vnode which will have been locked by namei */
3556 /* return the effort if we got one, otherwise return success */
3565 } /* end of getattrlist system call */
3570 * Set attribute information about a file system object
3573 struct setattrlist_args
{
3574 const char *path
; /* pathname of the target object */
3575 struct attrlist
* alist
; /* Attributes being set by the user */
3576 void * attributeBuffer
; /* buffer with attribute values to be set */
3577 size_t bufferSize
; /* size of the return buffer */
3578 unsigned long options
; /* options (follow/don't follow) */
3582 setattrlist (p
,uap
,retval
)
3584 register struct setattrlist_args
*uap
;
3589 struct nameidata nd
;
3592 struct attrlist alist
;
3595 /* Get the attributes desired and do our parameter checking */
3597 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3602 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3605 /* Get the vnode for the file whose attributes are being set. */
3606 nameiflags
= LOCKLEAF
;
3607 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3608 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3609 (char *)uap
->path
, p
);
3614 /* Set up the UIO structure for use by the vfs routine */
3615 aiov
.iov_base
= uap
->attributeBuffer
;
3616 aiov
.iov_len
= uap
->bufferSize
;
3617 auio
.uio_iov
= &aiov
;
3618 auio
.uio_iovcnt
= 1;
3619 auio
.uio_offset
= 0;
3620 auio
.uio_rw
= UIO_WRITE
;
3621 auio
.uio_segflg
= UIO_USERSPACE
;
3623 auio
.uio_resid
= uap
->bufferSize
;
3625 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3631 } /* end of setattrlist system call */
3635 * Obtain attribute information on objects in a directory while enumerating
3636 * the directory. This call does not yet support union mounted directories.
3638 * 1.union mounted directories.
3641 struct getdirentriesattr_args
{
3642 int fd
; /* file descriptor */
3643 struct attrlist
*alist
; /* bit map of requested attributes */
3644 void *buffer
; /* buffer to hold returned attribute info */
3645 size_t buffersize
; /* size of the return buffer */
3646 u_long
*count
; /* the count of entries requested/returned */
3647 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3648 u_long
*newstate
; /* a flag to inform of changes in directory */
3649 u_long options
; /* maybe unused for now */
3653 getdirentriesattr (p
,uap
,retval
)
3655 register struct getdirentriesattr_args
*uap
;
3659 register struct vnode
*vp
;
3667 struct attrlist attributelist
;
3669 AUDIT_ARG(fd
, uap
->fd
);
3671 /* Get the attributes into kernel space */
3672 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3674 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3677 if (error
= getvnode(p
, uap
->fd
, &fp
))
3680 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3682 if ((fp
->f_flag
& FREAD
) == 0)
3684 vp
= (struct vnode
*)fp
->f_data
;
3686 if (vp
->v_type
!= VDIR
)
3689 /* set up the uio structure which will contain the users return buffer */
3690 aiov
.iov_base
= uap
->buffer
;
3691 aiov
.iov_len
= uap
->buffersize
;
3692 auio
.uio_iov
= &aiov
;
3693 auio
.uio_iovcnt
= 1;
3694 auio
.uio_rw
= UIO_READ
;
3695 auio
.uio_segflg
= UIO_USERSPACE
;
3697 auio
.uio_resid
= uap
->buffersize
;
3699 loff
= auio
.uio_offset
= fp
->f_offset
;
3700 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3701 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3702 actualcount
, uap
->options
, &newstate
, &eofflag
,
3703 &actualcount
, ((u_long
**)0), p
->p_ucred
);
3705 VOP_UNLOCK(vp
, 0, p
);
3706 if (error
) return (error
);
3707 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3709 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3711 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3713 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3716 *retval
= eofflag
; /* similar to getdirentries */
3717 return (0); /* return error earlier, an retval of 0 or 1 now */
3719 } /* end of getdirentryattr system call */
3722 * Exchange data between two files
3725 struct exchangedata_args
{
3726 const char *path1
; /* pathname of the first swapee */
3727 const char *path2
; /* pathname of the second swapee */
3728 unsigned long options
; /* options */
3732 exchangedata (p
,uap
,retval
)
3734 register struct exchangedata_args
*uap
;
3739 struct nameidata fnd
, snd
;
3740 struct vnode
*fvp
, *svp
;
3745 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3747 /* Global lock, to prevent race condition, only one exchange at a time */
3748 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3750 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3751 (char *) uap
->path1
, p
);
3753 error
= namei(&fnd
);
3759 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
, UIO_USERSPACE
,
3760 (char *)uap
->path2
, p
);
3762 error
= namei(&snd
);
3770 /* if the files are the same, return an inval error */
3778 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3779 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3781 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3782 if (error
) goto out
;
3784 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3785 if (error
) goto out
;
3787 /* Ok, make the call */
3788 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3790 if (error
== 0 && VPARENT(fvp
) != VPARENT(svp
)) {
3794 VPARENT(fvp
) = VPARENT(svp
);
3803 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3811 } /* end of exchangedata system call */
3813 #ifdef __APPLE_API_OBSOLETE
3815 /************************************************/
3816 /* *** Following calls will be deleted soon *** */
3817 /************************************************/
3820 * Check users access to a file
3823 struct checkuseraccess_args
{
3824 const char *path
; /* pathname of the target file */
3825 uid_t userid
; /* user for whom we are checking access */
3826 gid_t
*groups
; /* Group that we are checking for */
3827 int ngroups
; /* Number of groups being checked */
3828 int accessrequired
; /* needed access to the file */
3829 unsigned long options
; /* options */
3834 checkuseraccess (p
,uap
,retval
)
3836 register struct checkuseraccess_args
*uap
;
3840 register struct vnode
*vp
;
3842 struct nameidata nd
;
3844 int flags
; /*what will actually get passed to access*/
3847 /* Make sure that the number of groups is correct before we do anything */
3849 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3852 /* Verify that the caller is root */
3854 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3857 /* Fill in the credential structure */
3860 cred
.cr_uid
= uap
->userid
;
3861 cred
.cr_ngroups
= uap
->ngroups
;
3862 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3865 /* Get our hands on the file */
3867 nameiflags
= LOCKLEAF
;
3868 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3869 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3871 if (error
= namei(&nd
))
3875 /* Flags == 0 means only check for existence. */
3879 if (uap
->accessrequired
) {
3880 if (uap
->accessrequired
& R_OK
)
3882 if (uap
->accessrequired
& W_OK
)
3884 if (uap
->accessrequired
& X_OK
)
3887 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3896 } /* end of checkuseraccess system call */
3898 /************************************************/
3899 /* *** Preceding calls will be deleted soon *** */
3900 /************************************************/
3902 #endif /* __APPLE_API_OBSOLETE */
3906 struct searchfs_args
{
3908 struct fssearchblock
*searchblock
;
3912 struct searchstate
*state
;
3917 searchfs (p
,uap
,retval
)
3919 register struct searchfs_args
*uap
;
3923 register struct vnode
*vp
;
3926 struct nameidata nd
;
3927 struct fssearchblock searchblock
;
3928 struct searchstate
*state
;
3929 struct attrlist
*returnattrs
;
3930 void *searchparams1
,*searchparams2
;
3938 /* Start by copying in fsearchblock paramater list */
3940 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3943 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3944 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3945 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3948 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3949 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3951 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3953 /* Now set up the various pointers to the correct place in our newly allocated memory */
3955 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3956 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3957 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3959 /* Now copy in the stuff given our local variables. */
3961 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3964 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3967 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3970 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3973 /* set up the uio structure which will contain the users return buffer */
3975 aiov
.iov_base
= searchblock
.returnbuffer
;
3976 aiov
.iov_len
= searchblock
.returnbuffersize
;
3977 auio
.uio_iov
= &aiov
;
3978 auio
.uio_iovcnt
= 1;
3979 auio
.uio_rw
= UIO_READ
;
3980 auio
.uio_segflg
= UIO_USERSPACE
;
3982 auio
.uio_resid
= searchblock
.returnbuffersize
;
3984 nameiflags
= LOCKLEAF
;
3985 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3986 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3987 (char *)uap
->path
, p
);
3997 * If searchblock.maxmatches == 0, then skip the search. This has happened
3998 * before and sometimes the underlyning code doesnt deal with it well.
4000 if (searchblock
.maxmatches
== 0) {
4006 Allright, we have everything we need, so lets make that call.
4008 We keep special track of the return value from the file system:
4009 EAGAIN is an acceptable error condition that shouldn't keep us
4010 from copying out any results...
4013 fserror
= VOP_SEARCHFS(vp
,
4016 &searchblock
.searchattrs
,
4017 searchblock
.maxmatches
,
4018 &searchblock
.timelimit
,
4030 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4031 search state. Everything was already put into he return buffer by the vop call. */
4033 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
4036 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
4043 FREE(searchparams1
,M_TEMP
);
4048 } /* end of searchfs system call */
4052 * Make a filesystem-specific control call:
4055 const char *path
; /* pathname of the target object */
4056 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
4057 caddr_t data
; /* pointer to argument buffer */
4058 u_long options
; /* options for fsctl processing */
4062 fsctl (p
,uap
,retval
)
4064 struct fsctl_args
*uap
;
4069 struct nameidata nd
;
4071 u_long cmd
= uap
->cmd
;
4072 register u_int size
;
4073 #define STK_PARAMS 128
4074 char stkbuf
[STK_PARAMS
];
4077 size
= IOCPARM_LEN(cmd
);
4078 if (size
> IOCPARM_MAX
) return (EINVAL
);
4081 if (size
> sizeof (stkbuf
)) {
4082 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4090 error
= copyin(uap
->data
, data
, (u_int
)size
);
4091 if (error
) goto FSCtl_Exit
;
4093 *(caddr_t
*)data
= uap
->data
;
4095 } else if ((cmd
& IOC_OUT
) && size
) {
4097 * Zero the buffer so the user always
4098 * gets back something deterministic.
4101 } else if (cmd
& IOC_VOID
)
4102 *(caddr_t
*)data
= uap
->data
;
4104 /* Get the vnode for the file we are getting info on: */
4105 nameiflags
= LOCKLEAF
;
4106 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4107 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
4108 if (error
= namei(&nd
)) goto FSCtl_Exit
;
4110 /* Invoke the filesystem-specific code */
4111 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
4116 * Copy any data to user, size was
4117 * already set and checked above.
4119 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
4122 if (memp
) kfree(memp
, size
);
4126 /* end of fsctl system call */
4129 * An in-kernel sync for power management to call.
4131 __private_extern__
int
4134 boolean_t funnel_state
;
4137 struct sync_args data
;
4141 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4143 error
= sync(current_proc(), &data
, &retval
);
4145 thread_funnel_set(kernel_flock
, funnel_state
);
4148 } /* end of sync_internal call */
4152 // XXXdbg fmod watching calls
4153 #define NUM_CHANGE_NODES 256
4154 static int changed_init
=0;
4155 static volatile int fmod_watch_enabled
= 0;
4156 static pid_t fmod_watch_owner
;
4157 static simple_lock_data_t changed_nodes_lock
; // guard access
4158 static volatile struct vnode
*changed_nodes
[NUM_CHANGE_NODES
];
4159 static volatile pid_t changed_nodes_pid
[NUM_CHANGE_NODES
];
4160 static volatile int changed_rd_index
=0, changed_wr_index
=0;
4161 static volatile int notifier_sleeping
=0;
4165 notify_filemod_watchers(struct vnode
*vp
, struct proc
*p
)
4169 // only want notification on regular files.
4170 if (fmod_watch_enabled
== 0 || (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
)) {
4174 // grab a reference so it doesn't go away
4175 if (vget(vp
, 0, p
) != 0) {
4180 simple_lock(&changed_nodes_lock
);
4182 // If the table is full, block until it clears up
4183 if (((changed_wr_index
+1) % NUM_CHANGE_NODES
) == changed_rd_index
) {
4184 simple_unlock(&changed_nodes_lock
);
4186 notifier_sleeping
++;
4187 // wait up to 10 seconds for the queue to drain
4188 ret
= tsleep((caddr_t
)&changed_wr_index
, PINOD
, "changed_nodes_full", 10*hz
);
4189 if (ret
!= 0 || fmod_watch_enabled
== 0) {
4190 notifier_sleeping
--;
4191 printf("notify_filemod: err %d from tsleep/enabled %d. bailing out (vp 0x%x).\n",
4192 ret
, fmod_watch_enabled
, vp
);
4197 notifier_sleeping
--;
4201 // insert our new guy
4202 if (changed_nodes
[changed_wr_index
] != NULL
) {
4203 panic("notify_fmod_watchers: index %d is 0x%x, not null!\n",
4204 changed_wr_index
, changed_nodes
[changed_wr_index
]);
4206 changed_nodes
[changed_wr_index
] = vp
;
4207 changed_nodes_pid
[changed_wr_index
] = current_proc()->p_pid
;
4208 changed_wr_index
= (changed_wr_index
+ 1) % NUM_CHANGE_NODES
;
4210 simple_unlock(&changed_nodes_lock
);
4212 wakeup((caddr_t
)&changed_rd_index
);
4216 struct fmod_watch_args
{
4224 fmod_watch(struct proc
*p
, struct fmod_watch_args
*uap
, register_t
*retval
)
4226 int fd
, didhold
= 0;
4227 struct filedesc
*fdp
;
4231 int type
, indx
, error
, need_wakeup
=0;
4233 struct nameidata nd
;
4234 extern struct fileops vnops
;
4237 if (fmod_watch_enabled
== 0) {
4244 if (changed_init
== 0) {
4246 simple_lock_init(&changed_nodes_lock
);
4249 if (changed_rd_index
== changed_wr_index
) {
4250 // there's nothing to do, go to sleep
4251 error
= tsleep((caddr_t
)&changed_rd_index
, PUSER
|PCATCH
, "changed_nodes_empty", 0);
4253 // XXXdbg - what if after we unblock the changed_nodes
4254 // table is full? We should wakeup() the writer.
4260 simple_lock(&changed_nodes_lock
);
4262 vp
= (struct vnode
*)changed_nodes
[changed_rd_index
];
4263 pid
= changed_nodes_pid
[changed_rd_index
];
4265 changed_nodes
[changed_rd_index
] = NULL
;
4266 changed_rd_index
= (changed_rd_index
+ 1) % NUM_CHANGE_NODES
;
4269 printf("watch_file_changes: Someone put a null vnode in my table! (%d %d)\n",
4270 changed_rd_index
, changed_wr_index
);
4275 simple_unlock(&changed_nodes_lock
);
4277 // if the writers are blocked, wake them up as we just freed up
4278 // some space for them.
4279 if (notifier_sleeping
> 0) {
4280 wakeup((caddr_t
)&changed_wr_index
);
4283 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
) {
4288 if ((error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
)) != 0) {
4289 printf("fmod_watch: vn_lock returned %d\n", error
);
4293 // first copy out the name
4298 MALLOC(buff
, char *, len
, M_TEMP
, M_WAITOK
);
4299 error
= vn_getpath(vp
, buff
, &len
);
4302 error
= copyout(buff
, (void *)uap
->pathbuf
, len
);
4312 // now copy out the pid of the person that changed the file
4314 if ((error
= copyout((caddr_t
)&pid
, (void *)uap
->pid
, sizeof(pid_t
))) != 0) {
4315 printf("fmod_watch: failed to copy out the pid (%d)\n", pid
);
4320 // now create a file descriptor for this vnode
4323 if (error
= falloc(p
, &fp
, &indx
)) {
4324 printf("fmod_watch: failed to allocate an fd...\n");
4328 if ((error
= copyout((caddr_t
)&indx
, (void *)uap
->new_fd
, sizeof(int))) != 0) {
4329 printf("fmod_watch: failed to copy out the new fd (%d)\n", indx
);
4333 fp
->f_flag
= flags
& FMASK
;
4334 fp
->f_type
= DTYPE_VNODE
;
4336 fp
->f_data
= (caddr_t
)vp
;
4338 if (UBCINFOEXISTS(vp
) && ((didhold
= ubc_hold(vp
)) == 0)) {
4342 error
= VOP_OPEN(vp
, flags
, p
->p_ucred
, p
);
4347 VOP_UNLOCK(vp
, 0, p
);
4349 *fdflags(p
, indx
) &= ~UF_RESERVED
;
4351 // note: we explicitly don't vrele() here because it
4352 // happens when the fd is closed.
4364 VOP_UNLOCK(vp
, 0, p
);
4366 vrele(vp
); // undoes the vref() in notify_filemod_watchers()
4374 enable_fmod_watching(register_t
*retval
)
4382 // XXXdbg for now we only allow one watcher at a time.
4383 if (fmod_watch_enabled
) {
4387 fmod_watch_enabled
++;
4388 fmod_watch_owner
= current_proc()->p_pid
;
4395 disable_fmod_watching(register_t
*retval
)
4401 if (fmod_watch_enabled
< 1) {
4402 printf("fmod_watching: too many disables! (%d)\n", fmod_watch_enabled
);
4406 fmod_watch_enabled
--;
4408 // if we're the last guy, clear out any remaining vnodes
4409 // in the table so they don't remain referenced.
4411 if (fmod_watch_enabled
== 0) {
4413 for(i
=changed_rd_index
; i
!= changed_wr_index
; ) {
4414 if (changed_nodes
[i
] == NULL
) {
4415 panic("disable_fmod_watch: index %d is NULL!\n", i
);
4417 vrele((struct vnode
*)changed_nodes
[i
]);
4418 changed_nodes
[i
] = NULL
;
4419 i
= (i
+ 1) % NUM_CHANGE_NODES
;
4421 changed_wr_index
= changed_rd_index
= 0;
4423 fmod_watch_owner
= 0;
4426 // wake up anyone that may be waiting for the
4427 // queue to clear out.
4429 while(notifier_sleeping
) {
4430 wakeup((caddr_t
)&changed_wr_index
);
4432 // yield the cpu so the notifiers can run
4433 tsleep((caddr_t
)&fmod_watch_enabled
, PINOD
, "disable_fmod_watch", 1);
4441 struct fmod_watch_enable_args
{
4446 fmod_watch_enable(struct proc
*p
, struct fmod_watch_enable_args
*uap
, register_t
*retval
)
4450 if (uap
->on_or_off
!= 0) {
4451 ret
= enable_fmod_watching(retval
);
4453 ret
= disable_fmod_watching(retval
);
4460 clean_up_fmod_watch(struct proc
*p
)
4462 if (fmod_watch_enabled
&& fmod_watch_owner
== p
->p_pid
) {
4465 disable_fmod_watching(&retval
);