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 flags
= FFLAGS(uap
->flags
);
1071 AUDIT_ARG(fflags
, oflags
);
1072 AUDIT_ARG(mode
, uap
->mode
);
1074 cmode
= ((uap
->mode
&~ fdp
->fd_cmask
) & ALLPERMS
) &~ S_ISTXT
;
1076 if ((oflags
& O_ACCMODE
) == O_ACCMODE
)
1078 if (error
= falloc(p
, &nfp
, &indx
))
1081 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1082 p
->p_dupfd
= -indx
- 1; /* XXX check for fdopen */
1083 if (error
= vn_open_modflags(&nd
, &flags
, cmode
)) {
1085 if ((error
== ENODEV
|| error
== ENXIO
) &&
1086 p
->p_dupfd
>= 0 && /* XXX from fdopen */
1088 dupfdopen(fdp
, indx
, p
->p_dupfd
, flags
, error
)) == 0) {
1092 if (error
== ERESTART
)
1099 fp
->f_flag
= flags
& FMASK
;
1100 fp
->f_type
= DTYPE_VNODE
;
1102 fp
->f_data
= (caddr_t
)vp
;
1104 VOP_UNLOCK(vp
, 0, p
);
1105 if (flags
& (O_EXLOCK
| O_SHLOCK
)) {
1106 lf
.l_whence
= SEEK_SET
;
1109 if (flags
& O_EXLOCK
)
1110 lf
.l_type
= F_WRLCK
;
1112 lf
.l_type
= F_RDLCK
;
1114 if ((flags
& FNONBLOCK
) == 0)
1116 if (error
= VOP_ADVLOCK(vp
, (caddr_t
)fp
, F_SETLK
, &lf
, type
))
1118 fp
->f_flag
|= FHASLOCK
;
1121 if (flags
& O_TRUNC
) {
1123 struct vattr
*vap
= &vat
;
1125 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1126 (void)vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
); /* XXX */
1129 /* try to truncate by setting the size attribute */
1130 error
= VOP_SETATTR(vp
, vap
, p
->p_ucred
, p
);
1131 VOP_UNLOCK(vp
, 0, p
); /* XXX */
1136 *fdflags(p
, indx
) &= ~UF_RESERVED
;
1140 vn_close(vp
, fp
->f_flag
, fp
->f_cred
, p
);
1150 struct ocreat_args
{
1155 ocreat(p
, uap
, retval
)
1157 register struct ocreat_args
*uap
;
1160 struct open_args nuap
;
1162 nuap
.path
= uap
->path
;
1163 nuap
.mode
= uap
->mode
;
1164 nuap
.flags
= O_WRONLY
| O_CREAT
| O_TRUNC
;
1165 return (open(p
, &nuap
, retval
));
1167 #endif /* COMPAT_43 */
1170 * Create a special file.
1179 mknod(p
, uap
, retval
)
1181 register struct mknod_args
*uap
;
1184 register struct vnode
*vp
;
1188 struct nameidata nd
;
1190 AUDIT_ARG(mode
, uap
->mode
);
1191 AUDIT_ARG(dev
, uap
->dev
);
1192 cmode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1193 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
1196 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1205 vattr
.va_mode
= cmode
;
1206 vattr
.va_rdev
= uap
->dev
;
1209 switch (uap
->mode
& S_IFMT
) {
1210 case S_IFMT
: /* used by badsect to flag bad sectors */
1211 vattr
.va_type
= VBAD
;
1214 vattr
.va_type
= VCHR
;
1217 vattr
.va_type
= VBLK
;
1229 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
1230 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1232 error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, CREATE
);
1234 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1237 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
,
1238 &nd
.ni_cnd
, &vattr
);
1241 if (error
== 0 && nd
.ni_vp
) {
1242 if (VNAME(nd
.ni_vp
) == NULL
) {
1243 VNAME(nd
.ni_vp
) = nameptr
;
1246 if (VPARENT(nd
.ni_vp
) == NULL
) {
1247 if (vget(nd
.ni_dvp
, 0, p
) == 0) {
1248 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1253 remove_name(nameptr
);
1257 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1258 if (nd
.ni_dvp
== vp
)
1269 * Create a named pipe.
1271 struct mkfifo_args
{
1277 mkfifo(p
, uap
, retval
)
1279 register struct mkfifo_args
*uap
;
1284 struct nameidata nd
;
1289 return (EOPNOTSUPP
);
1292 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1296 if (nd
.ni_vp
!= NULL
) {
1297 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1298 if (nd
.ni_dvp
== nd
.ni_vp
)
1306 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
,
1307 nd
.ni_cnd
.cn_namelen
,
1308 nd
.ni_cnd
.cn_hash
, 0);
1310 vattr
.va_type
= VFIFO
;
1311 vattr
.va_mode
= (uap
->mode
& ALLPERMS
) &~ p
->p_fd
->fd_cmask
;
1312 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1313 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
1315 if (error
== 0 && nd
.ni_vp
&& nd
.ni_vp
->v_type
== VFIFO
) {
1316 int vpid
= nd
.ni_vp
->v_id
;
1317 if (vget(nd
.ni_vp
, 0, p
) == 0) {
1318 if (vpid
== nd
.ni_vp
->v_id
&& nd
.ni_vp
->v_type
== VFIFO
) {
1319 VNAME(nd
.ni_vp
) = nameptr
;
1322 if (VPARENT(nd
.ni_vp
) == NULL
) {
1323 if (vget(nd
.ni_dvp
, 0, p
) == 0) {
1324 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1331 remove_name(nameptr
);
1338 * Make a hard file link.
1346 link(p
, uap
, retval
)
1348 register struct link_args
*uap
;
1351 register struct vnode
*vp
;
1352 struct nameidata nd
;
1356 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1361 if (vp
->v_type
== VDIR
)
1362 error
= EPERM
; /* POSIX */
1364 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1365 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| AUDITVNPATH2
;
1366 nd
.ni_dirp
= uap
->link
;
1369 if (nd
.ni_vp
!= NULL
)
1372 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
,
1374 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1375 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
1377 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1378 if (nd
.ni_dvp
== nd
.ni_vp
)
1392 * Make a symbolic link.
1394 struct symlink_args
{
1400 symlink(p
, uap
, retval
)
1402 register struct symlink_args
*uap
;
1406 char *path
, *nameptr
;
1408 struct nameidata nd
;
1412 MALLOC_ZONE(path
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
1413 if (error
= copyinstr(uap
->path
, path
, MAXPATHLEN
, &dummy
))
1415 AUDIT_ARG(text
, path
); /* This is the link string */
1417 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->link
, p
);
1422 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1423 if (nd
.ni_dvp
== nd
.ni_vp
)
1432 vattr
.va_mode
= ACCESSPERMS
&~ p
->p_fd
->fd_cmask
;
1433 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1435 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
1437 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
, path
);
1439 // have to do this little dance because nd.ni_vp is not locked
1440 // on return from the VOP_SYMLINK() call.
1442 if (error
== 0 && nd
.ni_vp
&& nd
.ni_vp
->v_type
== VLNK
) {
1443 vpid
= nd
.ni_vp
->v_id
;
1444 if (vget(nd
.ni_vp
, 0, p
) == 0) {
1445 if (vpid
== nd
.ni_vp
->v_id
&& nd
.ni_vp
->v_type
== VLNK
) {
1446 VNAME(nd
.ni_vp
) = nameptr
;
1449 if (VPARENT(nd
.ni_vp
) == NULL
&& vget(nd
.ni_dvp
, 0, p
) == 0) {
1450 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
1456 if (nameptr
) { // only true if we didn't add it to the vnode
1457 remove_name(nameptr
);
1460 FREE_ZONE(path
, MAXPATHLEN
, M_NAMEI
);
1465 * Delete a whiteout from the filesystem.
1467 struct undelete_args
{
1472 undelete(p
, uap
, retval
)
1474 register struct undelete_args
*uap
;
1478 struct nameidata nd
;
1481 NDINIT(&nd
, DELETE
, LOCKPARENT
|DOWHITEOUT
|AUDITVNPATH1
, UIO_USERSPACE
,
1487 if (nd
.ni_vp
!= NULLVP
|| !(nd
.ni_cnd
.cn_flags
& ISWHITEOUT
)) {
1488 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1489 if (nd
.ni_dvp
== nd
.ni_vp
)
1498 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1499 if (error
= VOP_WHITEOUT(nd
.ni_dvp
, &nd
.ni_cnd
, DELETE
))
1500 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1506 * Delete a name from the filesystem.
1508 struct unlink_args
{
1513 _unlink(p
, uap
, retval
, nodelbusy
)
1515 struct unlink_args
*uap
;
1519 register struct vnode
*vp
;
1521 struct nameidata nd
;
1524 NDINIT(&nd
, DELETE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
1525 /* with Carbon semantics, busy files cannot be deleted */
1527 nd
.ni_cnd
.cn_flags
|= NODELETEBUSY
;
1533 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
1534 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
1536 if (vp
->v_type
== VDIR
)
1537 error
= EPERM
; /* POSIX */
1540 * The root of a mounted filesystem cannot be deleted.
1542 * XXX: can this only be a VDIR case?
1544 if (vp
->v_flag
& VROOT
)
1549 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
1550 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1552 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1553 if (nd
.ni_dvp
== vp
)
1564 * Delete a name from the filesystem using POSIX semantics.
1567 unlink(p
, uap
, retval
)
1569 struct unlink_args
*uap
;
1572 return _unlink(p
, uap
, retval
, 0);
1576 * Delete a name from the filesystem using Carbon semantics.
1579 delete(p
, uap
, retval
)
1581 struct unlink_args
*uap
;
1584 return _unlink(p
, uap
, retval
, 1);
1588 * Reposition read/write file offset.
1592 #ifdef DOUBLE_ALIGN_PARAMS
1599 lseek(p
, uap
, retval
)
1601 register struct lseek_args
*uap
;
1604 struct ucred
*cred
= p
->p_ucred
;
1608 off_t offset
= uap
->offset
;
1611 if (error
= fdgetf(p
, uap
->fd
, &fp
))
1615 if (fp
->f_type
!= DTYPE_VNODE
) {
1619 vp
= (struct vnode
*)fp
->f_data
;
1620 switch (uap
->whence
) {
1622 offset
+= fp
->f_offset
;
1625 if (error
= VOP_GETATTR(vp
, &vattr
, cred
, p
))
1627 offset
+= vattr
.va_size
;
1635 if (uap
->offset
> 0 && offset
< 0) {
1636 /* Incremented/relative move past max size */
1640 * Allow negative offsets on character devices, per
1641 * POSIX 1003.1-2001. Most likely for writing disk
1644 if (offset
< 0 && vp
->v_type
!= VCHR
) {
1645 /* Decremented/relative move before start */
1649 fp
->f_offset
= offset
;
1650 *(off_t
*)retval
= fp
->f_offset
;
1660 * Reposition read/write file offset.
1662 struct olseek_args
{
1668 olseek(p
, uap
, retval
)
1670 register struct olseek_args
*uap
;
1673 struct lseek_args
/* {
1675 #ifdef DOUBLE_ALIGN_PARAMS
1676 syscallarg(int) pad;
1678 syscallarg(off_t) offset;
1679 syscallarg(int) whence;
1685 nuap
.offset
= uap
->offset
;
1686 nuap
.whence
= uap
->whence
;
1687 error
= lseek(p
, &nuap
, &qret
);
1688 *(long *)retval
= qret
;
1691 #endif /* COMPAT_43 */
1694 * Check access permissions.
1696 struct access_args
{
1701 access(p
, uap
, retval
)
1703 register struct access_args
*uap
;
1706 register struct ucred
*cred
= p
->p_ucred
;
1707 register struct vnode
*vp
;
1708 int error
, flags
, t_gid
, t_uid
;
1709 struct nameidata nd
;
1711 t_uid
= cred
->cr_uid
;
1712 t_gid
= cred
->cr_groups
[0];
1713 cred
->cr_uid
= p
->p_cred
->p_ruid
;
1714 cred
->cr_groups
[0] = p
->p_cred
->p_rgid
;
1715 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1722 /* Flags == 0 means only check for existence. */
1725 if (uap
->flags
& R_OK
)
1727 if (uap
->flags
& W_OK
)
1729 if (uap
->flags
& X_OK
)
1731 if ((flags
& VWRITE
) == 0 || (error
= vn_writechk(vp
)) == 0)
1732 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
1736 cred
->cr_uid
= t_uid
;
1737 cred
->cr_groups
[0] = t_gid
;
1743 * Get file status; this version follows links.
1751 ostat(p
, uap
, retval
)
1753 register struct ostat_args
*uap
;
1759 struct nameidata nd
;
1761 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1763 if (error
= namei(&nd
))
1765 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1770 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1775 * Get file status; this version does not follow links.
1777 struct olstat_args
{
1783 olstat(p
, uap
, retval
)
1785 register struct olstat_args
*uap
;
1788 struct vnode
*vp
, *dvp
;
1789 struct stat sb
, sb1
;
1792 struct nameidata nd
;
1794 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| LOCKPARENT
| AUDITVNPATH1
,
1795 UIO_USERSPACE
, uap
->path
, p
);
1796 if (error
= namei(&nd
))
1799 * For symbolic links, always return the attributes of its
1800 * containing directory, except for mode, size, and links.
1804 if (vp
->v_type
!= VLNK
) {
1809 error
= vn_stat(vp
, &sb
, p
);
1814 error
= vn_stat(dvp
, &sb
, p
);
1820 error
= vn_stat(vp
, &sb1
, p
);
1824 sb
.st_mode
&= ~S_IFDIR
;
1825 sb
.st_mode
|= S_IFLNK
;
1826 sb
.st_nlink
= sb1
.st_nlink
;
1827 sb
.st_size
= sb1
.st_size
;
1828 sb
.st_blocks
= sb1
.st_blocks
;
1831 error
= copyout((caddr_t
)&osb
, (caddr_t
)uap
->ub
, sizeof (osb
));
1836 * Convert from an old to a new stat structure.
1844 ost
->st_dev
= st
->st_dev
;
1845 ost
->st_ino
= st
->st_ino
;
1846 ost
->st_mode
= st
->st_mode
;
1847 ost
->st_nlink
= st
->st_nlink
;
1848 ost
->st_uid
= st
->st_uid
;
1849 ost
->st_gid
= st
->st_gid
;
1850 ost
->st_rdev
= st
->st_rdev
;
1851 if (st
->st_size
< (quad_t
)1 << 32)
1852 ost
->st_size
= st
->st_size
;
1855 ost
->st_atime
= st
->st_atime
;
1856 ost
->st_mtime
= st
->st_mtime
;
1857 ost
->st_ctime
= st
->st_ctime
;
1858 ost
->st_blksize
= st
->st_blksize
;
1859 ost
->st_blocks
= st
->st_blocks
;
1860 ost
->st_flags
= st
->st_flags
;
1861 ost
->st_gen
= st
->st_gen
;
1863 #endif /* COMPAT_43 */
1866 * The stat buffer spare fields are uninitialized
1867 * so don't include them in the copyout.
1869 #define STATBUFSIZE \
1870 (sizeof(struct stat) - sizeof(int32_t) - 2 * sizeof(int64_t))
1872 * Get file status; this version follows links.
1880 stat(p
, uap
, retval
)
1882 register struct stat_args
*uap
;
1887 struct nameidata nd
;
1889 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| SHAREDLEAF
| AUDITVNPATH1
,
1890 UIO_USERSPACE
, uap
->path
, p
);
1894 error
= vn_stat(nd
.ni_vp
, &sb
, p
);
1898 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, STATBUFSIZE
);
1903 * Get file status; this version does not follow links.
1911 lstat(p
, uap
, retval
)
1913 register struct lstat_args
*uap
;
1919 struct nameidata nd
;
1921 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1927 error
= vn_stat(vp
, &sb
, p
);
1931 error
= copyout((caddr_t
)&sb
, (caddr_t
)uap
->ub
, STATBUFSIZE
);
1936 * Get configurable pathname variables.
1938 struct pathconf_args
{
1944 pathconf(p
, uap
, retval
)
1946 register struct pathconf_args
*uap
;
1950 struct nameidata nd
;
1952 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1957 error
= VOP_PATHCONF(nd
.ni_vp
, uap
->name
, retval
);
1963 * Return target name of a symbolic link.
1965 struct readlink_args
{
1972 readlink(p
, uap
, retval
)
1974 register struct readlink_args
*uap
;
1977 register struct vnode
*vp
;
1981 struct nameidata nd
;
1983 NDINIT(&nd
, LOOKUP
, NOFOLLOW
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
1989 if (vp
->v_type
!= VLNK
)
1992 aiov
.iov_base
= uap
->buf
;
1993 aiov
.iov_len
= uap
->count
;
1994 auio
.uio_iov
= &aiov
;
1995 auio
.uio_iovcnt
= 1;
1996 auio
.uio_offset
= 0;
1997 auio
.uio_rw
= UIO_READ
;
1998 auio
.uio_segflg
= UIO_USERSPACE
;
2000 auio
.uio_resid
= uap
->count
;
2001 error
= VOP_READLINK(vp
, &auio
, p
->p_ucred
);
2004 *retval
= uap
->count
- auio
.uio_resid
;
2009 * Change flags of a file given a path name.
2011 struct chflags_args
{
2017 chflags(p
, uap
, retval
)
2019 register struct chflags_args
*uap
;
2022 register struct vnode
*vp
;
2025 struct nameidata nd
;
2027 AUDIT_ARG(fflags
, uap
->flags
);
2028 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2033 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2034 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2036 vattr
.va_flags
= uap
->flags
;
2037 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2043 * Change flags of a file given a file descriptor.
2045 struct fchflags_args
{
2051 fchflags(p
, uap
, retval
)
2053 register struct fchflags_args
*uap
;
2061 AUDIT_ARG(fd
, uap
->fd
);
2062 AUDIT_ARG(fflags
, uap
->flags
);
2063 if (error
= getvnode(p
, uap
->fd
, &fp
))
2066 vp
= (struct vnode
*)fp
->f_data
;
2068 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2069 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2071 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2074 vattr
.va_flags
= uap
->flags
;
2075 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2076 VOP_UNLOCK(vp
, 0, p
);
2081 * Change mode of a file given path name.
2089 chmod(p
, uap
, retval
)
2091 register struct chmod_args
*uap
;
2094 register struct vnode
*vp
;
2097 struct nameidata nd
;
2099 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2101 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2106 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2107 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2109 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2110 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2117 * Change mode of a file given a file descriptor.
2119 struct fchmod_args
{
2125 fchmod(p
, uap
, retval
)
2127 register struct fchmod_args
*uap
;
2135 AUDIT_ARG(fd
, uap
->fd
);
2136 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2137 if (error
= getvnode(p
, uap
->fd
, &fp
))
2140 vp
= (struct vnode
*)fp
->f_data
;
2141 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2142 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2144 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2147 vattr
.va_mode
= uap
->mode
& ALLPERMS
;
2148 AUDIT_ARG(mode
, (mode_t
)vattr
.va_mode
);
2149 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2151 VOP_UNLOCK(vp
, 0, p
);
2157 * Set ownership given a path name.
2166 chown(p
, uap
, retval
)
2168 register struct chown_args
*uap
;
2171 register struct vnode
*vp
;
2174 struct nameidata nd
;
2176 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2178 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2185 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2186 * by looking for chown() calls on /dev/console from a console process.
2188 if ((vp
) && (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
) && (vp
->v_specinfo
) &&
2189 (major(vp
->v_specinfo
->si_rdev
) == CONSMAJOR
) &&
2190 (minor(vp
->v_specinfo
->si_rdev
) == 0)) {
2191 console_user
= uap
->uid
;
2194 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2195 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2197 vattr
.va_uid
= uap
->uid
;
2198 vattr
.va_gid
= uap
->gid
;
2199 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2206 * Set ownership given a file descriptor.
2208 struct fchown_args
{
2215 fchown(p
, uap
, retval
)
2217 register struct fchown_args
*uap
;
2225 AUDIT_ARG(owner
, uap
->uid
, uap
->gid
);
2226 AUDIT_ARG(fd
, uap
->fd
);
2228 if (error
= getvnode(p
, uap
->fd
, &fp
))
2231 vp
= (struct vnode
*)fp
->f_data
;
2232 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2233 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2235 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2238 vattr
.va_uid
= uap
->uid
;
2239 vattr
.va_gid
= uap
->gid
;
2240 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2242 VOP_UNLOCK(vp
, 0, p
);
2247 getutimes(usrtvp
, tsp
)
2248 const struct timeval
*usrtvp
;
2249 struct timespec
*tsp
;
2251 struct timeval tv
[2];
2254 if (usrtvp
== NULL
) {
2256 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2259 if ((error
= copyin((void *)usrtvp
, (void *)tv
, sizeof (tv
))) != 0)
2261 TIMEVAL_TO_TIMESPEC(&tv
[0], &tsp
[0]);
2262 TIMEVAL_TO_TIMESPEC(&tv
[1], &tsp
[1]);
2268 setutimes(p
, vp
, ts
, nullflag
)
2271 const struct timespec
*ts
;
2277 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2278 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2282 AUDIT_ARG(vnpath
, vp
, ARG_VNODE1
);
2285 vattr
.va_atime
= ts
[0];
2286 vattr
.va_mtime
= ts
[1];
2288 vattr
.va_vaflags
|= VA_UTIMES_NULL
;
2289 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2291 VOP_UNLOCK(vp
, 0, p
);
2297 * Set the access and modification times of a file.
2299 struct utimes_args
{
2301 struct timeval
*tptr
;
2305 utimes(p
, uap
, retval
)
2307 register struct utimes_args
*uap
;
2310 struct timespec ts
[2];
2311 struct timeval
*usrtvp
;
2313 struct nameidata nd
;
2315 /* AUDIT: Needed to change the order of operations to do the
2316 * name lookup first because auditing wants the path.
2318 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2324 if ((error
= getutimes(usrtvp
, ts
)) != 0) {
2328 error
= setutimes(p
, nd
.ni_vp
, ts
, usrtvp
== NULL
);
2334 * Set the access and modification times of a file.
2336 struct futimes_args
{
2338 struct timeval
*tptr
;
2342 futimes(p
, uap
, retval
)
2344 register struct futimes_args
*uap
;
2347 struct timespec ts
[2];
2349 struct timeval
*usrtvp
;
2352 AUDIT_ARG(fd
, uap
->fd
);
2354 if ((error
= getutimes(usrtvp
, ts
)) != 0)
2356 if ((error
= getvnode(p
, uap
->fd
, &fp
)) != 0)
2359 return setutimes(p
, (struct vnode
*)fp
->f_data
, ts
, usrtvp
== NULL
);
2363 * Truncate a file given its path name.
2365 struct truncate_args
{
2367 #ifdef DOUBLE_ALIGN_PARAMS
2374 truncate(p
, uap
, retval
)
2376 register struct truncate_args
*uap
;
2379 register struct vnode
*vp
;
2382 struct nameidata nd
;
2384 if (uap
->length
< 0)
2386 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2387 if (error
= namei(&nd
))
2390 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2391 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2392 if (vp
->v_type
== VDIR
)
2394 else if ((error
= vn_writechk(vp
)) == 0 &&
2395 (error
= VOP_ACCESS(vp
, VWRITE
, p
->p_ucred
, p
)) == 0) {
2397 vattr
.va_size
= uap
->length
;
2398 error
= VOP_SETATTR(vp
, &vattr
, p
->p_ucred
, p
);
2405 * Truncate a file given a file descriptor.
2407 struct ftruncate_args
{
2409 #ifdef DOUBLE_ALIGN_PARAMS
2416 ftruncate(p
, uap
, retval
)
2418 register struct ftruncate_args
*uap
;
2426 AUDIT_ARG(fd
, uap
->fd
);
2427 if (uap
->length
< 0)
2430 if (error
= fdgetf(p
, uap
->fd
, &fp
))
2433 if (fp
->f_type
== DTYPE_PSXSHM
) {
2434 return(pshm_truncate(p
, fp
, uap
->fd
, uap
->length
, retval
));
2436 if (fp
->f_type
!= DTYPE_VNODE
)
2439 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
2441 if ((fp
->f_flag
& FWRITE
) == 0)
2443 vp
= (struct vnode
*)fp
->f_data
;
2444 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2445 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2446 if (vp
->v_type
== VDIR
)
2448 else if ((error
= vn_writechk(vp
)) == 0) {
2450 vattr
.va_size
= uap
->length
;
2451 error
= VOP_SETATTR(vp
, &vattr
, fp
->f_cred
, p
);
2453 VOP_UNLOCK(vp
, 0, p
);
2459 * Truncate a file given its path name.
2461 struct otruncate_args
{
2467 otruncate(p
, uap
, retval
)
2469 register struct otruncate_args
*uap
;
2472 struct truncate_args
/* {
2473 syscallarg(char *) path;
2474 #ifdef DOUBLE_ALIGN_PARAMS
2475 syscallarg(int) pad;
2477 syscallarg(off_t) length;
2480 nuap
.path
= uap
->path
;
2481 nuap
.length
= uap
->length
;
2482 return (truncate(p
, &nuap
, retval
));
2486 * Truncate a file given a file descriptor.
2488 struct oftruncate_args
{
2494 oftruncate(p
, uap
, retval
)
2496 register struct oftruncate_args
*uap
;
2499 struct ftruncate_args
/* {
2501 #ifdef DOUBLE_ALIGN_PARAMS
2502 syscallarg(int) pad;
2504 syscallarg(off_t) length;
2508 nuap
.length
= uap
->length
;
2509 return (ftruncate(p
, &nuap
, retval
));
2511 #endif /* COMPAT_43 */
2514 * Sync an open file.
2521 fsync(p
, uap
, retval
)
2523 struct fsync_args
*uap
;
2526 register struct vnode
*vp
;
2530 if (error
= getvnode(p
, uap
->fd
, &fp
))
2534 vp
= (struct vnode
*)fp
->f_data
;
2535 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2536 error
= VOP_FSYNC(vp
, fp
->f_cred
, MNT_WAIT
, p
);
2537 VOP_UNLOCK(vp
, 0, p
);
2543 * Duplicate files. Source must be a file, target must be a file or
2547 struct copyfile_args
{
2555 copyfile(p
, uap
, retval
)
2557 register struct copyfile_args
*uap
;
2560 register struct vnode
*tvp
, *fvp
, *tdvp
;
2561 register struct ucred
*cred
= p
->p_ucred
;
2562 struct nameidata fromnd
, tond
;
2565 /* Check that the flags are valid. */
2567 if (uap
->flags
& ~CPF_MASK
) {
2571 NDINIT(&fromnd
, LOOKUP
, SAVESTART
| AUDITVNPATH1
,
2572 UIO_USERSPACE
, uap
->from
, p
);
2573 if (error
= namei(&fromnd
))
2577 NDINIT(&tond
, CREATE
, LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
2578 UIO_USERSPACE
, uap
->to
, p
);
2579 if (error
= namei(&tond
)) {
2586 if (!(uap
->flags
& CPF_OVERWRITE
)) {
2592 if (fvp
->v_type
== VDIR
|| (tvp
&& tvp
->v_type
== VDIR
)) {
2597 if (error
= VOP_ACCESS(tdvp
, VWRITE
, cred
, p
))
2603 * If source is the same as the destination (that is the
2604 * same inode number) then there is nothing to do.
2605 * (fixed to have POSIX semantics - CSM 3/2/98)
2611 error
= VOP_COPYFILE(fvp
,tdvp
,tvp
,&tond
.ni_cnd
,uap
->mode
,uap
->flags
);
2613 VOP_ABORTOP(tdvp
, &tond
.ni_cnd
);
2622 vrele(tond
.ni_startdir
);
2623 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2625 if (fromnd
.ni_startdir
)
2626 vrele(fromnd
.ni_startdir
);
2627 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2634 * Rename files. Source and destination must either both be directories,
2635 * or both not be directories. If target is a directory, it must be empty.
2637 struct rename_args
{
2643 rename(p
, uap
, retval
)
2645 register struct rename_args
*uap
;
2648 register struct vnode
*tvp
, *fvp
, *tdvp
;
2649 struct nameidata fromnd
, tond
;
2652 int casesense
,casepres
;
2653 char *nameptr
=NULL
, *oname
;
2654 struct vnode
*oparent
;
2659 NDINIT(&fromnd
, DELETE
, WANTPARENT
| SAVESTART
| AUDITVNPATH1
,
2660 UIO_USERSPACE
, uap
->from
, p
);
2661 error
= namei(&fromnd
);
2666 NDINIT(&tond
, RENAME
,
2667 LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
| AUDITVNPATH2
,
2668 UIO_USERSPACE
, uap
->to
, p
);
2669 if (fromnd
.ni_vp
->v_type
== VDIR
)
2670 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2671 if (error
= namei(&tond
)) {
2672 /* Translate error code for rename("dir1", "dir2/."). */
2673 if (error
== EISDIR
&& fvp
->v_type
== VDIR
)
2675 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2676 vrele(fromnd
.ni_dvp
);
2684 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2687 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2695 * If source is the same as the destination (that is the
2696 * same inode number) then there is nothing to do... EXCEPT if the
2697 * underlying file system supports case insensitivity and is case
2698 * preserving. Then a special case is made, i.e. foo -> Foo.
2700 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2701 * and _PC_CASE_PRESERVING can have this exception, and they need to
2702 * handle the special case of getting the same vnode as target and
2703 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2704 * so not to cause locking problems. There is a single reference on tvp.
2706 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2707 * that correct behaviour then is just to remove the source (link)
2709 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
) {
2710 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2711 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2712 fromnd
.ni_cnd
.cn_namelen
)) {
2713 error
= -1; /* Default "unix" behavior */
2714 } else { /* probe for file system specifics */
2715 if (VOP_PATHCONF(tdvp
, _PC_CASE_SENSITIVE
, &casesense
))
2717 if (VOP_PATHCONF(tdvp
, _PC_CASE_PRESERVING
, &casepres
))
2719 if (!casesense
&& casepres
)
2720 vput(tvp
); /* Unlock target and drop ref */
2725 * Allow the renaming of mount points.
2726 * - target must not exist
2727 * - target must reside in the same directory as source
2728 * - union mounts cannot be renamed
2729 * - "/" cannot be renamed
2732 (fvp
->v_flag
& VROOT
) &&
2733 (fvp
->v_type
== VDIR
) &&
2735 (fvp
->v_mountedhere
== NULL
) &&
2736 (fromnd
.ni_dvp
== tond
.ni_dvp
) &&
2737 ((fvp
->v_mount
->mnt_flag
& (MNT_UNION
| MNT_ROOTFS
)) == 0) &&
2738 (fvp
->v_mount
->mnt_vnodecovered
!= NULLVP
)) {
2740 /* switch fvp to the covered vnode */
2741 fromnd
.ni_vp
= fvp
->v_mount
->mnt_vnodecovered
;
2749 VOP_LEASE(tdvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2750 if (fromnd
.ni_dvp
!= tdvp
)
2751 VOP_LEASE(fromnd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2753 VOP_LEASE(tvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2755 // XXXdbg - so that the fs won't block when it vrele()'s
2756 // these nodes before returning
2757 if (fromnd
.ni_dvp
!= tdvp
) {
2761 // save these off so we can later verify that fvp is the same
2763 oparent
= VPARENT(fvp
);
2765 nameptr
= add_name(tond
.ni_cnd
.cn_nameptr
,
2766 tond
.ni_cnd
.cn_namelen
,
2767 tond
.ni_cnd
.cn_hash
, 0);
2770 error
= VOP_RENAME(fromnd
.ni_dvp
, fvp
, &fromnd
.ni_cnd
,
2771 tond
.ni_dvp
, tvp
, &tond
.ni_cnd
);
2773 remove_name(nameptr
);
2775 if (fromnd
.ni_dvp
!= tdvp
) {
2783 * update filesystem's mount point data
2786 char *cp
, *pathend
, *mpname
;
2793 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2794 mp
= fvp
->v_mountedhere
;
2796 if (vfs_busy(mp
, LK_NOWAIT
, 0, p
)) {
2801 VOP_UNLOCK(fvp
, 0, p
);
2803 MALLOC_ZONE(tobuf
, char *, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2804 error
= copyinstr(uap
->to
, tobuf
, MAXPATHLEN
, &len
);
2806 /* find current mount point prefix */
2807 pathend
= &mp
->mnt_stat
.f_mntonname
[0];
2808 for (cp
= pathend
; *cp
!= '\0'; ++cp
) {
2812 /* find last component of target name */
2813 for (mpname
= cp
= tobuf
; *cp
!= '\0'; ++cp
) {
2817 /* append name to prefix */
2818 maxlen
= MNAMELEN
- (pathend
- mp
->mnt_stat
.f_mntonname
);
2819 bzero(pathend
, maxlen
);
2820 strncpy(pathend
, mpname
, maxlen
- 1);
2822 FREE_ZONE(tobuf
, MAXPATHLEN
, M_NAMEI
);
2829 // fix up name & parent pointers. note that we first
2830 // check that fvp has the same name/parent pointers it
2831 // had before the rename call and then we lock fvp so
2832 // that it won't go away on us when we hit blocking
2833 // points like remove_name() or vrele() where fvp could
2835 if (oname
== VNAME(fvp
) && oparent
== VPARENT(fvp
) && vget(fvp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
) == 0) {
2837 char *tmp
= VNAME(fvp
);
2842 VNAME(fvp
) = nameptr
;
2845 if (fromnd
.ni_dvp
!= tdvp
) {
2846 struct vnode
*tmpvp
;
2848 tmpvp
= VPARENT(fvp
);
2849 VPARENT(fvp
) = NULL
;
2852 VPARENT(fvp
) = tdvp
;
2854 // note: we don't vrele() tdvp because we want to keep
2855 // the reference until fvp gets recycled
2861 // if fvp isn't kosher anymore and we locked tdvp,
2863 if (fromnd
.ni_dvp
!= tdvp
) {
2866 remove_name(nameptr
);
2871 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2878 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2879 vrele(fromnd
.ni_dvp
);
2883 vrele(tond
.ni_startdir
);
2884 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2886 if (fromnd
.ni_startdir
)
2887 vrele(fromnd
.ni_startdir
);
2888 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2895 * Make a directory file.
2903 mkdir(p
, uap
, retval
)
2905 register struct mkdir_args
*uap
;
2908 register struct vnode
*vp
;
2911 struct nameidata nd
;
2914 AUDIT_ARG(mode
, (mode_t
)uap
->mode
);
2916 NDINIT(&nd
, CREATE
, LOCKPARENT
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
2917 nd
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2923 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2924 if (nd
.ni_dvp
== vp
)
2932 vattr
.va_type
= VDIR
;
2933 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
) &~ p
->p_fd
->fd_cmask
;
2934 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2936 nameptr
= add_name(nd
.ni_cnd
.cn_nameptr
, nd
.ni_cnd
.cn_namelen
, nd
.ni_cnd
.cn_hash
, 0);
2938 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &vattr
);
2940 VNAME(nd
.ni_vp
) = nameptr
;
2941 if (VPARENT(nd
.ni_vp
) == NULL
&& vget(nd
.ni_dvp
, 0, p
) == 0) {
2942 VPARENT(nd
.ni_vp
) = nd
.ni_dvp
;
2951 * Remove a directory file.
2958 rmdir(p
, uap
, retval
)
2960 struct rmdir_args
*uap
;
2963 register struct vnode
*vp
;
2965 struct nameidata nd
;
2968 NDINIT(&nd
, DELETE
, LOCKPARENT
| LOCKLEAF
| AUDITVNPATH1
, UIO_USERSPACE
,
2974 if (vp
->v_type
!= VDIR
) {
2979 * No rmdir "." please.
2981 if (nd
.ni_dvp
== vp
) {
2986 * The root of a mounted filesystem cannot be deleted.
2988 if (vp
->v_flag
& VROOT
)
2992 VOP_LEASE(nd
.ni_dvp
, p
, p
->p_ucred
, LEASE_WRITE
);
2993 VOP_LEASE(vp
, p
, p
->p_ucred
, LEASE_WRITE
);
2994 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2996 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2997 if (nd
.ni_dvp
== vp
)
3008 * Read a block of directory entries in a file system independent format.
3010 struct ogetdirentries_args
{
3017 ogetdirentries(p
, uap
, retval
)
3019 register struct ogetdirentries_args
*uap
;
3022 register struct vnode
*vp
;
3024 struct uio auio
, kuio
;
3025 struct iovec aiov
, kiov
;
3026 struct dirent
*dp
, *edp
;
3028 int error
, eofflag
, readcnt
;
3031 AUDIT_ARG(fd
, uap
->fd
);
3032 if (error
= getvnode(p
, uap
->fd
, &fp
))
3035 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3037 if ((fp
->f_flag
& FREAD
) == 0)
3039 vp
= (struct vnode
*)fp
->f_data
;
3041 if (vp
->v_type
!= VDIR
)
3043 aiov
.iov_base
= uap
->buf
;
3044 aiov
.iov_len
= uap
->count
;
3045 auio
.uio_iov
= &aiov
;
3046 auio
.uio_iovcnt
= 1;
3047 auio
.uio_rw
= UIO_READ
;
3048 auio
.uio_segflg
= UIO_USERSPACE
;
3050 auio
.uio_resid
= uap
->count
;
3051 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3052 loff
= auio
.uio_offset
= fp
->f_offset
;
3053 # if (BYTE_ORDER != LITTLE_ENDIAN)
3054 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
3055 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3056 (int *)0, (u_long
**)0);
3057 fp
->f_offset
= auio
.uio_offset
;
3062 kuio
.uio_iov
= &kiov
;
3063 kuio
.uio_segflg
= UIO_SYSSPACE
;
3064 kiov
.iov_len
= uap
->count
;
3065 MALLOC(dirbuf
, caddr_t
, uap
->count
, M_TEMP
, M_WAITOK
);
3066 kiov
.iov_base
= dirbuf
;
3067 error
= VOP_READDIR(vp
, &kuio
, fp
->f_cred
, &eofflag
,
3068 (int *)0, (u_long
**)0);
3069 fp
->f_offset
= kuio
.uio_offset
;
3071 readcnt
= uap
->count
- kuio
.uio_resid
;
3072 edp
= (struct dirent
*)&dirbuf
[readcnt
];
3073 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
3074 # if (BYTE_ORDER == LITTLE_ENDIAN)
3076 * The expected low byte of
3077 * dp->d_namlen is our dp->d_type.
3078 * The high MBZ byte of dp->d_namlen
3079 * is our dp->d_namlen.
3081 dp
->d_type
= dp
->d_namlen
;
3085 * The dp->d_type is the high byte
3086 * of the expected dp->d_namlen,
3087 * so must be zero'ed.
3091 if (dp
->d_reclen
> 0) {
3092 dp
= (struct dirent
*)
3093 ((char *)dp
+ dp
->d_reclen
);
3100 error
= uiomove(dirbuf
, readcnt
, &auio
);
3102 FREE(dirbuf
, M_TEMP
);
3104 VOP_UNLOCK(vp
, 0, p
);
3110 extern int (**union_vnodeop_p
)(void *);
3111 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3113 if ((uap
->count
== auio
.uio_resid
) &&
3114 (vp
->v_op
== union_vnodeop_p
)) {
3117 lvp
= union_dircache(vp
, p
);
3118 if (lvp
!= NULLVP
) {
3122 * If the directory is opaque,
3123 * then don't show lower entries
3125 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3126 if (va
.va_flags
& OPAQUE
) {
3132 if (lvp
!= NULLVP
) {
3133 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3138 VOP_UNLOCK(lvp
, 0, p
);
3139 fp
->f_data
= (caddr_t
) lvp
;
3141 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3152 if ((uap
->count
== auio
.uio_resid
) &&
3153 (vp
->v_flag
& VROOT
) &&
3154 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3155 struct vnode
*tvp
= vp
;
3156 vp
= vp
->v_mount
->mnt_vnodecovered
;
3158 fp
->f_data
= (caddr_t
) vp
;
3163 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3165 *retval
= uap
->count
- auio
.uio_resid
;
3168 #endif /* COMPAT_43 */
3171 * Read a block of directory entries in a file system independent format.
3173 struct getdirentries_args
{
3180 getdirentries(p
, uap
, retval
)
3182 register struct getdirentries_args
*uap
;
3185 register struct vnode
*vp
;
3192 AUDIT_ARG(fd
, uap
->fd
);
3193 error
= getvnode(p
, uap
->fd
, &fp
);
3197 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3199 if ((fp
->f_flag
& FREAD
) == 0)
3201 vp
= (struct vnode
*)fp
->f_data
;
3203 if (vp
->v_type
!= VDIR
)
3205 aiov
.iov_base
= uap
->buf
;
3206 aiov
.iov_len
= uap
->count
;
3207 auio
.uio_iov
= &aiov
;
3208 auio
.uio_iovcnt
= 1;
3209 auio
.uio_rw
= UIO_READ
;
3210 auio
.uio_segflg
= UIO_USERSPACE
;
3212 auio
.uio_resid
= uap
->count
;
3213 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3214 loff
= auio
.uio_offset
= fp
->f_offset
;
3215 error
= VOP_READDIR(vp
, &auio
, fp
->f_cred
, &eofflag
,
3216 (int *)0, (u_long
**)0);
3217 fp
->f_offset
= auio
.uio_offset
;
3218 VOP_UNLOCK(vp
, 0, p
);
3224 extern int (**union_vnodeop_p
)(void *);
3225 extern struct vnode
*union_dircache
__P((struct vnode
*, struct proc
*));
3227 if ((uap
->count
== auio
.uio_resid
) &&
3228 (vp
->v_op
== union_vnodeop_p
)) {
3231 lvp
= union_dircache(vp
, p
);
3232 if (lvp
!= NULLVP
) {
3236 * If the directory is opaque,
3237 * then don't show lower entries
3239 error
= VOP_GETATTR(vp
, &va
, fp
->f_cred
, p
);
3240 if (va
.va_flags
& OPAQUE
) {
3246 if (lvp
!= NULLVP
) {
3247 error
= VOP_OPEN(lvp
, FREAD
, fp
->f_cred
, p
);
3252 VOP_UNLOCK(lvp
, 0, p
);
3253 fp
->f_data
= (caddr_t
) lvp
;
3255 error
= VOP_CLOSE(vp
, FREAD
, fp
->f_cred
, p
);
3266 if ((uap
->count
== auio
.uio_resid
) &&
3267 (vp
->v_flag
& VROOT
) &&
3268 (vp
->v_mount
->mnt_flag
& MNT_UNION
)) {
3269 struct vnode
*tvp
= vp
;
3270 vp
= vp
->v_mount
->mnt_vnodecovered
;
3272 fp
->f_data
= (caddr_t
) vp
;
3277 error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
,
3279 *retval
= uap
->count
- auio
.uio_resid
;
3284 * Set the mode mask for creation of filesystem nodes.
3290 umask(p
, uap
, retval
)
3292 struct umask_args
*uap
;
3295 register struct filedesc
*fdp
;
3297 AUDIT_ARG(mask
, uap
->newmask
);
3299 *retval
= fdp
->fd_cmask
;
3300 fdp
->fd_cmask
= uap
->newmask
& ALLPERMS
;
3305 * Void all references to file by ripping underlying filesystem
3308 struct revoke_args
{
3313 revoke(p
, uap
, retval
)
3315 register struct revoke_args
*uap
;
3318 register struct vnode
*vp
;
3321 struct nameidata nd
;
3323 NDINIT(&nd
, LOOKUP
, FOLLOW
| AUDITVNPATH1
, UIO_USERSPACE
, uap
->path
, p
);
3328 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
3330 if (p
->p_ucred
->cr_uid
!= vattr
.va_uid
&&
3331 (error
= suser(p
->p_ucred
, &p
->p_acflag
)))
3333 if (vp
->v_usecount
> 1 || (vp
->v_flag
& VALIASED
))
3334 VOP_REVOKE(vp
, REVOKEALL
);
3341 * Convert a user file descriptor to a kernel file entry.
3344 getvnode(p
, fd
, fpp
)
3352 if (error
= fdgetf(p
, fd
, &fp
))
3354 if (fp
->f_type
!= DTYPE_VNODE
)
3361 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3362 * The following system calls are designed to support features
3363 * which are specific to the HFS & HFS Plus volume formats
3366 #ifdef __APPLE_API_OBSOLETE
3368 /************************************************/
3369 /* *** Following calls will be deleted soon *** */
3370 /************************************************/
3373 * Make a complex file. A complex file is one with multiple forks (data streams)
3375 struct mkcomplex_args
{
3376 const char *path
; /* pathname of the file to be created */
3377 mode_t mode
; /* access mode for the newly created file */
3378 u_long type
; /* format of the complex file */
3382 mkcomplex(p
,uap
,retval
)
3384 register struct mkcomplex_args
*uap
;
3390 struct nameidata nd
;
3392 /* mkcomplex wants the directory vnode locked so do that here */
3394 NDINIT(&nd
, CREATE
, FOLLOW
| LOCKPARENT
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3395 if (error
= namei(&nd
))
3398 /* Set the attributes as specified by the user */
3401 vattr
.va_mode
= (uap
->mode
& ACCESSPERMS
);
3402 error
= VOP_MKCOMPLEX(nd
.ni_dvp
, &vp
, &nd
.ni_cnd
, &vattr
, uap
->type
);
3404 /* The mkcomplex call promises to release the parent vnode pointer
3405 * even an an error case so don't do it here unless the operation
3406 * is not supported. In that case, there isn't anyone to unlock the parent
3407 * The vnode pointer to the file will also be released.
3412 if (error
== EOPNOTSUPP
)
3419 } /* end of mkcomplex system call */
3422 * Extended stat call which returns volumeid and vnodeid as well as other info
3425 const char *path
; /* pathname of the target file */
3426 struct vstat
*vsb
; /* vstat structure for returned info */
3432 register struct statv_args
*uap
;
3436 return (EOPNOTSUPP
); /* We'll just return an error for now */
3438 } /* end of statv system call */
3441 * Extended lstat call which returns volumeid and vnodeid as well as other info
3443 struct lstatv_args
{
3444 const char *path
; /* pathname of the target file */
3445 struct vstat
*vsb
; /* vstat structure for returned info */
3449 lstatv(p
,uap
,retval
)
3451 register struct lstatv_args
*uap
;
3455 return (EOPNOTSUPP
); /* We'll just return an error for now */
3456 } /* end of lstatv system call */
3459 * Extended fstat call which returns volumeid and vnodeid as well as other info
3461 struct fstatv_args
{
3462 int fd
; /* file descriptor of the target file */
3463 struct vstat
*vsb
; /* vstat structure for returned info */
3467 fstatv(p
,uap
,retval
)
3469 register struct fstatv_args
*uap
;
3473 return (EOPNOTSUPP
); /* We'll just return an error for now */
3474 } /* end of fstatv system call */
3477 /************************************************/
3478 /* *** Preceding calls will be deleted soon *** */
3479 /************************************************/
3481 #endif /* __APPLE_API_OBSOLETE */
3485 * Obtain attribute information about a file system object
3488 struct getattrlist_args
{
3489 const char *path
; /* pathname of the target object */
3490 struct attrlist
* alist
; /* Attributes desired by the user */
3491 void * attributeBuffer
; /* buffer to hold returned attributes */
3492 size_t bufferSize
; /* size of the return buffer */
3493 unsigned long options
; /* options (follow/don't follow) */
3497 getattrlist (p
,uap
,retval
)
3499 register struct getattrlist_args
*uap
;
3504 struct nameidata nd
;
3507 struct attrlist attributelist
;
3510 /* Get the attributes desire and do our parameter checking */
3512 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
,
3513 sizeof (attributelist
)))
3518 if (attributelist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
3520 || attributelist
.commonattr
& ~ATTR_CMN_VALIDMASK
||
3521 attributelist
.volattr
& ~ATTR_VOL_VALIDMASK
||
3522 attributelist
.dirattr
& ~ATTR_DIR_VALIDMASK
||
3523 attributelist
.fileattr
& ~ATTR_FILE_VALIDMASK
||
3524 attributelist
.forkattr
& ~ATTR_FORK_VALIDMASK
3531 /* Get the vnode for the file we are getting info on. */
3532 nameiflags
= LOCKLEAF
| SHAREDLEAF
;
3533 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3534 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3535 (char *)uap
->path
, p
);
3541 /* Set up the UIO structure for use by the vfs routine */
3543 aiov
.iov_base
= uap
->attributeBuffer
;
3544 aiov
.iov_len
= uap
->bufferSize
;
3545 auio
.uio_iov
= &aiov
;
3546 auio
.uio_iovcnt
= 1;
3547 auio
.uio_offset
= 0;
3548 auio
.uio_rw
= UIO_READ
;
3549 auio
.uio_segflg
= UIO_USERSPACE
;
3551 auio
.uio_resid
= uap
->bufferSize
;
3554 error
= VOP_GETATTRLIST(nd
.ni_vp
, &attributelist
, &auio
, p
->p_ucred
, p
);
3556 /* Unlock and release the vnode which will have been locked by namei */
3560 /* return the effort if we got one, otherwise return success */
3569 } /* end of getattrlist system call */
3574 * Set attribute information about a file system object
3577 struct setattrlist_args
{
3578 const char *path
; /* pathname of the target object */
3579 struct attrlist
* alist
; /* Attributes being set by the user */
3580 void * attributeBuffer
; /* buffer with attribute values to be set */
3581 size_t bufferSize
; /* size of the return buffer */
3582 unsigned long options
; /* options (follow/don't follow) */
3586 setattrlist (p
,uap
,retval
)
3588 register struct setattrlist_args
*uap
;
3593 struct nameidata nd
;
3596 struct attrlist alist
;
3599 /* Get the attributes desired and do our parameter checking */
3601 if ((error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &alist
,
3606 if (alist
.bitmapcount
!= ATTR_BIT_MAP_COUNT
)
3609 /* Get the vnode for the file whose attributes are being set. */
3610 nameiflags
= LOCKLEAF
;
3611 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3612 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3613 (char *)uap
->path
, p
);
3618 /* Set up the UIO structure for use by the vfs routine */
3619 aiov
.iov_base
= uap
->attributeBuffer
;
3620 aiov
.iov_len
= uap
->bufferSize
;
3621 auio
.uio_iov
= &aiov
;
3622 auio
.uio_iovcnt
= 1;
3623 auio
.uio_offset
= 0;
3624 auio
.uio_rw
= UIO_WRITE
;
3625 auio
.uio_segflg
= UIO_USERSPACE
;
3627 auio
.uio_resid
= uap
->bufferSize
;
3629 error
= VOP_SETATTRLIST(nd
.ni_vp
, &alist
, &auio
, p
->p_ucred
, p
);
3635 } /* end of setattrlist system call */
3639 * Obtain attribute information on objects in a directory while enumerating
3640 * the directory. This call does not yet support union mounted directories.
3642 * 1.union mounted directories.
3645 struct getdirentriesattr_args
{
3646 int fd
; /* file descriptor */
3647 struct attrlist
*alist
; /* bit map of requested attributes */
3648 void *buffer
; /* buffer to hold returned attribute info */
3649 size_t buffersize
; /* size of the return buffer */
3650 u_long
*count
; /* the count of entries requested/returned */
3651 u_long
*basep
; /* the offset of where we are leaving off in buffer */
3652 u_long
*newstate
; /* a flag to inform of changes in directory */
3653 u_long options
; /* maybe unused for now */
3657 getdirentriesattr (p
,uap
,retval
)
3659 register struct getdirentriesattr_args
*uap
;
3663 register struct vnode
*vp
;
3671 struct attrlist attributelist
;
3673 AUDIT_ARG(fd
, uap
->fd
);
3675 /* Get the attributes into kernel space */
3676 if (error
= copyin((caddr_t
)uap
->alist
, (caddr_t
) &attributelist
, sizeof (attributelist
)))
3678 if (error
= copyin((caddr_t
)uap
->count
, (caddr_t
) &actualcount
, sizeof (u_long
)))
3681 if (error
= getvnode(p
, uap
->fd
, &fp
))
3684 AUDIT_ARG(vnpath
, (struct vnode
*)fp
->f_data
, ARG_VNODE1
);
3686 if ((fp
->f_flag
& FREAD
) == 0)
3688 vp
= (struct vnode
*)fp
->f_data
;
3690 if (vp
->v_type
!= VDIR
)
3693 /* set up the uio structure which will contain the users return buffer */
3694 aiov
.iov_base
= uap
->buffer
;
3695 aiov
.iov_len
= uap
->buffersize
;
3696 auio
.uio_iov
= &aiov
;
3697 auio
.uio_iovcnt
= 1;
3698 auio
.uio_rw
= UIO_READ
;
3699 auio
.uio_segflg
= UIO_USERSPACE
;
3701 auio
.uio_resid
= uap
->buffersize
;
3703 loff
= auio
.uio_offset
= fp
->f_offset
;
3704 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3705 error
= VOP_READDIRATTR (vp
, &attributelist
, &auio
,
3706 actualcount
, uap
->options
, &newstate
, &eofflag
,
3707 &actualcount
, ((u_long
**)0), p
->p_ucred
);
3709 VOP_UNLOCK(vp
, 0, p
);
3710 if (error
) return (error
);
3711 fp
->f_offset
= auio
.uio_offset
; /* should be multiple of dirent, not variable */
3713 if (error
= copyout((caddr_t
) &actualcount
, (caddr_t
) uap
->count
, sizeof(u_long
)))
3715 if (error
= copyout((caddr_t
) &newstate
, (caddr_t
) uap
->newstate
, sizeof(u_long
)))
3717 if (error
= copyout((caddr_t
)&loff
, (caddr_t
)uap
->basep
, sizeof(long)))
3720 *retval
= eofflag
; /* similar to getdirentries */
3721 return (0); /* return error earlier, an retval of 0 or 1 now */
3723 } /* end of getdirentryattr system call */
3726 * Exchange data between two files
3729 struct exchangedata_args
{
3730 const char *path1
; /* pathname of the first swapee */
3731 const char *path2
; /* pathname of the second swapee */
3732 unsigned long options
; /* options */
3736 exchangedata (p
,uap
,retval
)
3738 register struct exchangedata_args
*uap
;
3743 struct nameidata fnd
, snd
;
3744 struct vnode
*fvp
, *svp
;
3749 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3751 /* Global lock, to prevent race condition, only one exchange at a time */
3752 lockmgr(&exchangelock
, LK_EXCLUSIVE
, (struct slock
*)0, p
);
3754 NDINIT(&fnd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3755 (char *) uap
->path1
, p
);
3757 error
= namei(&fnd
);
3763 NDINIT(&snd
, LOOKUP
, nameiflags
| AUDITVNPATH2
, UIO_USERSPACE
,
3764 (char *)uap
->path2
, p
);
3766 error
= namei(&snd
);
3774 /* if the files are the same, return an inval error */
3782 vn_lock(fvp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3783 vn_lock(svp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
3785 error
= VOP_ACCESS(fvp
, VWRITE
, p
->p_ucred
, p
);
3786 if (error
) goto out
;
3788 error
= VOP_ACCESS(svp
, VWRITE
, p
->p_ucred
, p
);
3789 if (error
) goto out
;
3791 /* Ok, make the call */
3792 error
= VOP_EXCHANGE (fvp
, svp
, p
->p_ucred
, p
);
3794 if (error
== 0 && VPARENT(fvp
) != VPARENT(svp
)) {
3798 VPARENT(fvp
) = VPARENT(svp
);
3807 lockmgr(&exchangelock
, LK_RELEASE
, (struct slock
*)0, p
);
3815 } /* end of exchangedata system call */
3817 #ifdef __APPLE_API_OBSOLETE
3819 /************************************************/
3820 /* *** Following calls will be deleted soon *** */
3821 /************************************************/
3824 * Check users access to a file
3827 struct checkuseraccess_args
{
3828 const char *path
; /* pathname of the target file */
3829 uid_t userid
; /* user for whom we are checking access */
3830 gid_t
*groups
; /* Group that we are checking for */
3831 int ngroups
; /* Number of groups being checked */
3832 int accessrequired
; /* needed access to the file */
3833 unsigned long options
; /* options */
3838 checkuseraccess (p
,uap
,retval
)
3840 register struct checkuseraccess_args
*uap
;
3844 register struct vnode
*vp
;
3846 struct nameidata nd
;
3848 int flags
; /*what will actually get passed to access*/
3851 /* Make sure that the number of groups is correct before we do anything */
3853 if ((uap
->ngroups
<= 0) || (uap
->ngroups
> NGROUPS
))
3856 /* Verify that the caller is root */
3858 if (error
= suser(p
->p_ucred
, &p
->p_acflag
))
3861 /* Fill in the credential structure */
3864 cred
.cr_uid
= uap
->userid
;
3865 cred
.cr_ngroups
= uap
->ngroups
;
3866 if (error
= copyin((caddr_t
) uap
->groups
, (caddr_t
) &(cred
.cr_groups
), (sizeof(gid_t
))*uap
->ngroups
))
3869 /* Get our hands on the file */
3871 nameiflags
= LOCKLEAF
;
3872 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3873 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
, (char *)uap
->path
, p
);
3875 if (error
= namei(&nd
))
3879 /* Flags == 0 means only check for existence. */
3883 if (uap
->accessrequired
) {
3884 if (uap
->accessrequired
& R_OK
)
3886 if (uap
->accessrequired
& W_OK
)
3888 if (uap
->accessrequired
& X_OK
)
3891 error
= VOP_ACCESS(vp
, flags
, &cred
, p
);
3900 } /* end of checkuseraccess system call */
3902 /************************************************/
3903 /* *** Preceding calls will be deleted soon *** */
3904 /************************************************/
3906 #endif /* __APPLE_API_OBSOLETE */
3910 struct searchfs_args
{
3912 struct fssearchblock
*searchblock
;
3916 struct searchstate
*state
;
3921 searchfs (p
,uap
,retval
)
3923 register struct searchfs_args
*uap
;
3927 register struct vnode
*vp
;
3930 struct nameidata nd
;
3931 struct fssearchblock searchblock
;
3932 struct searchstate
*state
;
3933 struct attrlist
*returnattrs
;
3934 void *searchparams1
,*searchparams2
;
3942 /* Start by copying in fsearchblock paramater list */
3944 if (error
= copyin((caddr_t
) uap
->searchblock
, (caddr_t
) &searchblock
,sizeof(struct fssearchblock
)))
3947 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3948 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3949 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3952 mallocsize
= searchblock
.sizeofsearchparams1
+searchblock
.sizeofsearchparams2
+
3953 sizeof(struct attrlist
) + sizeof(struct searchstate
);
3955 MALLOC(searchparams1
, void *, mallocsize
, M_TEMP
, M_WAITOK
);
3957 /* Now set up the various pointers to the correct place in our newly allocated memory */
3959 searchparams2
= (void *) (((caddr_t
) searchparams1
) + searchblock
.sizeofsearchparams1
);
3960 returnattrs
= (struct attrlist
*) (((caddr_t
) searchparams2
) + searchblock
.sizeofsearchparams2
);
3961 state
= (struct searchstate
*) (((caddr_t
) returnattrs
) + sizeof (struct attrlist
));
3963 /* Now copy in the stuff given our local variables. */
3965 if (error
= copyin((caddr_t
) searchblock
.searchparams1
, searchparams1
,searchblock
.sizeofsearchparams1
))
3968 if (error
= copyin((caddr_t
) searchblock
.searchparams2
, searchparams2
,searchblock
.sizeofsearchparams2
))
3971 if (error
= copyin((caddr_t
) searchblock
.returnattrs
, (caddr_t
) returnattrs
, sizeof(struct attrlist
)))
3974 if (error
= copyin((caddr_t
) uap
->state
, (caddr_t
) state
, sizeof(struct searchstate
)))
3977 /* set up the uio structure which will contain the users return buffer */
3979 aiov
.iov_base
= searchblock
.returnbuffer
;
3980 aiov
.iov_len
= searchblock
.returnbuffersize
;
3981 auio
.uio_iov
= &aiov
;
3982 auio
.uio_iovcnt
= 1;
3983 auio
.uio_rw
= UIO_READ
;
3984 auio
.uio_segflg
= UIO_USERSPACE
;
3986 auio
.uio_resid
= searchblock
.returnbuffersize
;
3988 nameiflags
= LOCKLEAF
;
3989 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
3990 NDINIT(&nd
, LOOKUP
, nameiflags
| AUDITVNPATH1
, UIO_USERSPACE
,
3991 (char *)uap
->path
, p
);
4001 * If searchblock.maxmatches == 0, then skip the search. This has happened
4002 * before and sometimes the underlyning code doesnt deal with it well.
4004 if (searchblock
.maxmatches
== 0) {
4010 Allright, we have everything we need, so lets make that call.
4012 We keep special track of the return value from the file system:
4013 EAGAIN is an acceptable error condition that shouldn't keep us
4014 from copying out any results...
4017 fserror
= VOP_SEARCHFS(vp
,
4020 &searchblock
.searchattrs
,
4021 searchblock
.maxmatches
,
4022 &searchblock
.timelimit
,
4034 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4035 search state. Everything was already put into he return buffer by the vop call. */
4037 if (error
= copyout((caddr_t
) state
, (caddr_t
) uap
->state
, sizeof(struct searchstate
)))
4040 if (error
= copyout((caddr_t
) &nummatches
, (caddr_t
) uap
->nummatches
, sizeof(u_long
)))
4047 FREE(searchparams1
,M_TEMP
);
4052 } /* end of searchfs system call */
4056 * Make a filesystem-specific control call:
4059 const char *path
; /* pathname of the target object */
4060 u_long cmd
; /* cmd (also encodes size/direction of arguments a la ioctl) */
4061 caddr_t data
; /* pointer to argument buffer */
4062 u_long options
; /* options for fsctl processing */
4066 fsctl (p
,uap
,retval
)
4068 struct fsctl_args
*uap
;
4073 struct nameidata nd
;
4075 u_long cmd
= uap
->cmd
;
4076 register u_int size
;
4077 #define STK_PARAMS 128
4078 char stkbuf
[STK_PARAMS
];
4081 size
= IOCPARM_LEN(cmd
);
4082 if (size
> IOCPARM_MAX
) return (EINVAL
);
4085 if (size
> sizeof (stkbuf
)) {
4086 if ((memp
= (caddr_t
)kalloc(size
)) == 0) return ENOMEM
;
4094 error
= copyin(uap
->data
, data
, (u_int
)size
);
4095 if (error
) goto FSCtl_Exit
;
4097 *(caddr_t
*)data
= uap
->data
;
4099 } else if ((cmd
& IOC_OUT
) && size
) {
4101 * Zero the buffer so the user always
4102 * gets back something deterministic.
4105 } else if (cmd
& IOC_VOID
)
4106 *(caddr_t
*)data
= uap
->data
;
4108 /* Get the vnode for the file we are getting info on: */
4109 nameiflags
= LOCKLEAF
;
4110 if ((uap
->options
& FSOPT_NOFOLLOW
) == 0) nameiflags
|= FOLLOW
;
4111 NDINIT(&nd
, LOOKUP
, nameiflags
, UIO_USERSPACE
, (char *)uap
->path
, p
);
4112 if (error
= namei(&nd
)) goto FSCtl_Exit
;
4114 /* Invoke the filesystem-specific code */
4115 error
= VOP_IOCTL(nd
.ni_vp
, IOCBASECMD(cmd
), data
, uap
->options
, p
->p_ucred
, p
);
4120 * Copy any data to user, size was
4121 * already set and checked above.
4123 if (error
== 0 && (cmd
& IOC_OUT
) && size
) error
= copyout(data
, uap
->data
, (u_int
)size
);
4126 if (memp
) kfree(memp
, size
);
4130 /* end of fsctl system call */
4133 * An in-kernel sync for power management to call.
4135 __private_extern__
int
4138 boolean_t funnel_state
;
4141 struct sync_args data
;
4145 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
4147 error
= sync(current_proc(), &data
, &retval
);
4149 thread_funnel_set(kernel_flock
, funnel_state
);
4152 } /* end of sync_internal call */
4156 // XXXdbg fmod watching calls
4157 #define NUM_CHANGE_NODES 256
4158 static int changed_init
=0;
4159 static volatile int fmod_watch_enabled
= 0;
4160 static pid_t fmod_watch_owner
;
4161 static simple_lock_data_t changed_nodes_lock
; // guard access
4162 static volatile struct vnode
*changed_nodes
[NUM_CHANGE_NODES
];
4163 static volatile pid_t changed_nodes_pid
[NUM_CHANGE_NODES
];
4164 static volatile int changed_rd_index
=0, changed_wr_index
=0;
4165 static volatile int notifier_sleeping
=0;
4169 notify_filemod_watchers(struct vnode
*vp
, struct proc
*p
)
4173 // only want notification on regular files.
4174 if (fmod_watch_enabled
== 0 || (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
)) {
4178 // grab a reference so it doesn't go away
4179 if (vget(vp
, 0, p
) != 0) {
4184 simple_lock(&changed_nodes_lock
);
4186 // If the table is full, block until it clears up
4187 if (((changed_wr_index
+1) % NUM_CHANGE_NODES
) == changed_rd_index
) {
4188 simple_unlock(&changed_nodes_lock
);
4190 notifier_sleeping
++;
4191 // wait up to 10 seconds for the queue to drain
4192 ret
= tsleep((caddr_t
)&changed_wr_index
, PINOD
, "changed_nodes_full", 10*hz
);
4193 if (ret
!= 0 || fmod_watch_enabled
== 0) {
4194 notifier_sleeping
--;
4195 printf("notify_filemod: err %d from tsleep/enabled %d. bailing out (vp 0x%x).\n",
4196 ret
, fmod_watch_enabled
, vp
);
4201 notifier_sleeping
--;
4205 // insert our new guy
4206 if (changed_nodes
[changed_wr_index
] != NULL
) {
4207 panic("notify_fmod_watchers: index %d is 0x%x, not null!\n",
4208 changed_wr_index
, changed_nodes
[changed_wr_index
]);
4210 changed_nodes
[changed_wr_index
] = vp
;
4211 changed_nodes_pid
[changed_wr_index
] = current_proc()->p_pid
;
4212 changed_wr_index
= (changed_wr_index
+ 1) % NUM_CHANGE_NODES
;
4214 simple_unlock(&changed_nodes_lock
);
4216 wakeup((caddr_t
)&changed_rd_index
);
4220 struct fmod_watch_args
{
4228 fmod_watch(struct proc
*p
, struct fmod_watch_args
*uap
, register_t
*retval
)
4230 int fd
, didhold
= 0;
4231 struct filedesc
*fdp
;
4235 int type
, indx
, error
, need_wakeup
=0;
4237 struct nameidata nd
;
4238 extern struct fileops vnops
;
4241 if (fmod_watch_enabled
== 0) {
4248 if (changed_init
== 0) {
4250 simple_lock_init(&changed_nodes_lock
);
4253 if (changed_rd_index
== changed_wr_index
) {
4254 // there's nothing to do, go to sleep
4255 error
= tsleep((caddr_t
)&changed_rd_index
, PUSER
|PCATCH
, "changed_nodes_empty", 0);
4257 // XXXdbg - what if after we unblock the changed_nodes
4258 // table is full? We should wakeup() the writer.
4264 simple_lock(&changed_nodes_lock
);
4266 vp
= (struct vnode
*)changed_nodes
[changed_rd_index
];
4267 pid
= changed_nodes_pid
[changed_rd_index
];
4269 changed_nodes
[changed_rd_index
] = NULL
;
4270 changed_rd_index
= (changed_rd_index
+ 1) % NUM_CHANGE_NODES
;
4273 printf("watch_file_changes: Someone put a null vnode in my table! (%d %d)\n",
4274 changed_rd_index
, changed_wr_index
);
4279 simple_unlock(&changed_nodes_lock
);
4281 // if the writers are blocked, wake them up as we just freed up
4282 // some space for them.
4283 if (notifier_sleeping
> 0) {
4284 wakeup((caddr_t
)&changed_wr_index
);
4287 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
) {
4292 if ((error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
)) != 0) {
4293 printf("fmod_watch: vn_lock returned %d\n", error
);
4297 // first copy out the name
4302 MALLOC(buff
, char *, len
, M_TEMP
, M_WAITOK
);
4303 error
= vn_getpath(vp
, buff
, &len
);
4306 error
= copyout(buff
, (void *)uap
->pathbuf
, len
);
4316 // now copy out the pid of the person that changed the file
4318 if ((error
= copyout((caddr_t
)&pid
, (void *)uap
->pid
, sizeof(pid_t
))) != 0) {
4319 printf("fmod_watch: failed to copy out the pid (%d)\n", pid
);
4324 // now create a file descriptor for this vnode
4327 if (error
= falloc(p
, &fp
, &indx
)) {
4328 printf("fmod_watch: failed to allocate an fd...\n");
4332 if ((error
= copyout((caddr_t
)&indx
, (void *)uap
->new_fd
, sizeof(int))) != 0) {
4333 printf("fmod_watch: failed to copy out the new fd (%d)\n", indx
);
4337 fp
->f_flag
= flags
& FMASK
;
4338 fp
->f_type
= DTYPE_VNODE
;
4340 fp
->f_data
= (caddr_t
)vp
;
4342 if (UBCINFOEXISTS(vp
) && ((didhold
= ubc_hold(vp
)) == 0)) {
4346 error
= VOP_OPEN(vp
, flags
, p
->p_ucred
, p
);
4351 VOP_UNLOCK(vp
, 0, p
);
4353 *fdflags(p
, indx
) &= ~UF_RESERVED
;
4355 // note: we explicitly don't vrele() here because it
4356 // happens when the fd is closed.
4368 VOP_UNLOCK(vp
, 0, p
);
4370 vrele(vp
); // undoes the vref() in notify_filemod_watchers()
4378 enable_fmod_watching(register_t
*retval
)
4386 // XXXdbg for now we only allow one watcher at a time.
4387 if (fmod_watch_enabled
) {
4391 fmod_watch_enabled
++;
4392 fmod_watch_owner
= current_proc()->p_pid
;
4399 disable_fmod_watching(register_t
*retval
)
4405 if (fmod_watch_enabled
< 1) {
4406 printf("fmod_watching: too many disables! (%d)\n", fmod_watch_enabled
);
4410 fmod_watch_enabled
--;
4412 // if we're the last guy, clear out any remaining vnodes
4413 // in the table so they don't remain referenced.
4415 if (fmod_watch_enabled
== 0) {
4417 for(i
=changed_rd_index
; i
!= changed_wr_index
; ) {
4418 if (changed_nodes
[i
] == NULL
) {
4419 panic("disable_fmod_watch: index %d is NULL!\n", i
);
4421 vrele((struct vnode
*)changed_nodes
[i
]);
4422 changed_nodes
[i
] = NULL
;
4423 i
= (i
+ 1) % NUM_CHANGE_NODES
;
4425 changed_wr_index
= changed_rd_index
= 0;
4427 fmod_watch_owner
= 0;
4430 // wake up anyone that may be waiting for the
4431 // queue to clear out.
4433 while(notifier_sleeping
) {
4434 wakeup((caddr_t
)&changed_wr_index
);
4436 // yield the cpu so the notifiers can run
4437 tsleep((caddr_t
)&fmod_watch_enabled
, PINOD
, "disable_fmod_watch", 1);
4445 struct fmod_watch_enable_args
{
4450 fmod_watch_enable(struct proc
*p
, struct fmod_watch_enable_args
*uap
, register_t
*retval
)
4454 if (uap
->on_or_off
!= 0) {
4455 ret
= enable_fmod_watching(retval
);
4457 ret
= disable_fmod_watching(retval
);
4464 clean_up_fmod_watch(struct proc
*p
)
4466 if (fmod_watch_enabled
&& fmod_watch_owner
== p
->p_pid
) {
4469 disable_fmod_watching(&retval
);