2 * Copyright (c) 2000-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@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
26 * (c) UNIX System Laboratories, Inc.
27 * All or some portions of this file are derived from material licensed
28 * to the University of California by American Telephone and Telegraph
29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
30 * the permission of UNIX System Laboratories, Inc.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
63 #include <rev_endian_fs.h>
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/namei.h>
67 #include <sys/resourcevar.h>
68 #include <sys/kernel.h>
69 #include <sys/file_internal.h>
73 #include <sys/kauth.h>
75 #include <sys/mount_internal.h>
76 #include <sys/vnode_internal.h>
77 #include <sys/malloc.h>
78 #include <sys/dirent.h>
79 #include <sys/fcntl.h>
81 #include <sys/quota.h>
82 #include <sys/uio_internal.h>
84 #include <kern/thread.h>
87 #include <miscfs/specfs/specdev.h>
89 #include <ufs/ufs/quota.h>
90 #include <ufs/ufs/inode.h>
91 #include <ufs/ufs/dir.h>
92 #include <ufs/ufs/ufsmount.h>
93 #include <ufs/ufs/ufs_extern.h>
96 #include <ufs/ufs/ufs_byte_order.h>
97 #endif /* REV_ENDIAN_FS */
100 static int ufs_chmod(struct vnode
*, int, kauth_cred_t
, struct proc
*);
101 static int ufs_chown(struct vnode
*, uid_t
, gid_t
, kauth_cred_t
,
103 static int filt_ufsread(struct knote
*kn
, long hint
);
104 static int filt_ufswrite(struct knote
*kn
, long hint
);
105 static int filt_ufsvnode(struct knote
*kn
, long hint
);
106 static void filt_ufsdetach(struct knote
*kn
);
109 extern void fifo_printinfo(struct vnode
*vp
);
111 extern int ufs_direnter2(struct vnode
*dvp
, struct direct
*dirp
,
114 static int ufs_readdirext(vnode_t vp
, uio_t uio
, int *eofflag
, int *numdirent
,
115 vfs_context_t context
);
118 * Create a regular file
122 struct vnop_create_args
/* {
124 struct vnode **a_vpp;
125 struct componentname *a_cnp;
126 struct vnode_vattr *a_vap;
127 vfs_context_t a_context;
132 if ( (error
= ufs_makeinode(ap
->a_vap
, ap
->a_dvp
, ap
->a_vpp
, ap
->a_cnp
)) )
134 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
143 struct vnop_mknod_args
/* {
145 struct vnode **a_vpp;
146 struct componentname *a_cnp;
147 struct vnode_attr *a_vap;
148 vfs_context_t a_context;
151 struct vnode_attr
*vap
= ap
->a_vap
;
152 struct vnode
**vpp
= ap
->a_vpp
;
153 struct vnode
*dvp
= ap
->a_dvp
;
156 struct componentname
*cnp
= ap
->a_cnp
;
159 /* use relookup to force correct directory hints */
160 cnp
->cn_flags
&= ~MODMASK
;
161 cnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
162 cnp
->cn_nameiop
= CREATE
;
164 (void) relookup(dvp
, &tvp
, cnp
);
166 /* get rid of reference relookup returned */
171 ufs_makeinode(ap
->a_vap
, ap
->a_dvp
, vpp
, ap
->a_cnp
)) )
173 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
175 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
176 if (vap
->va_rdev
!= VNOVAL
) {
178 * Want to be able to use this to make badblock
179 * inodes, so don't truncate the dev number.
181 ip
->i_rdev
= vap
->va_rdev
;
193 struct vnop_open_args
/* {
196 vfs_context_t a_context;
201 * Files marked append-only must be opened for appending.
203 if ((VTOI(ap
->a_vp
)->i_flags
& APPEND
) &&
204 (ap
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)
212 * Update the times on the inode.
216 struct vnop_close_args
/* {
219 vfs_context_t a_context;
222 register struct vnode
*vp
= ap
->a_vp
;
223 register struct inode
*ip
= VTOI(vp
);
226 if (vnode_isinuse(vp
, 1)) {
228 ITIMES(ip
, &tv
, &tv
);
231 cluster_push(vp
, IO_CLOSE
);
238 struct vnop_getattr_args
/* {
240 struct vnode_attr *a_vap;
241 vfs_context_t a_context;
244 register struct vnode
*vp
= ap
->a_vp
;
245 register struct inode
*ip
= VTOI(vp
);
246 register struct vnode_attr
*vap
= ap
->a_vap
;
252 ITIMES(ip
, &tv
, &tv
);
254 * Copy from inode table
256 VATTR_RETURN(vap
, va_fsid
, ip
->i_dev
);
257 VATTR_RETURN(vap
, va_fileid
, ip
->i_number
);
258 VATTR_RETURN(vap
, va_mode
, ip
->i_mode
& ~IFMT
);
259 VATTR_RETURN(vap
, va_nlink
, ip
->i_nlink
);
260 VATTR_RETURN(vap
, va_uid
, ip
->i_uid
);
261 VATTR_RETURN(vap
, va_gid
, ip
->i_gid
);
262 VATTR_RETURN(vap
, va_rdev
, (dev_t
)ip
->i_rdev
);
263 VATTR_RETURN(vap
, va_data_size
, ip
->i_din
.di_size
);
264 vap
->va_access_time
.tv_sec
= ip
->i_atime
;
265 vap
->va_access_time
.tv_nsec
= ip
->i_atimensec
;
266 VATTR_SET_SUPPORTED(vap
, va_access_time
);
267 vap
->va_modify_time
.tv_sec
= ip
->i_mtime
;
268 vap
->va_modify_time
.tv_nsec
= ip
->i_mtimensec
;
269 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
270 vap
->va_change_time
.tv_sec
= ip
->i_ctime
;
271 vap
->va_change_time
.tv_nsec
= ip
->i_ctimensec
;
272 VATTR_SET_SUPPORTED(vap
, va_change_time
);
273 VATTR_RETURN(vap
, va_flags
, ip
->i_flags
);
274 VATTR_RETURN(vap
, va_gen
, ip
->i_gen
);
275 if (vp
->v_type
== VBLK
)
276 VATTR_RETURN(vap
, va_iosize
, BLKDEV_IOSIZE
);
277 else if (vp
->v_type
== VCHR
)
278 VATTR_RETURN(vap
, va_iosize
, MAXPHYSIO
);
280 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
);
281 devBlockSize
= vfs_devblocksize(vnode_mount(vp
));
282 VATTR_RETURN(vap
, va_data_alloc
, dbtob((u_quad_t
)ip
->i_blocks
, devBlockSize
));
283 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
284 VATTR_RETURN(vap
, va_filerev
, ip
->i_modrev
);
289 * Set attribute vnode op. called from several syscalls
293 struct vnop_setattr_args
/* {
295 struct vnode_attr *a_vap;
297 vfs_context_t a_context;
300 struct vnode_attr
*vap
= ap
->a_vap
;
301 struct vnode
*vp
= ap
->a_vp
;
302 struct inode
*ip
= VTOI(vp
);
303 kauth_cred_t cred
= vfs_context_ucred(ap
->a_context
);
304 struct proc
*p
= vfs_context_proc(ap
->a_context
);
305 struct timeval atimeval
, mtimeval
;
311 * Go through the fields and update iff set.
313 if (VATTR_IS_ACTIVE(vap
, va_flags
)) {
314 ip
->i_flags
= vap
->va_flags
;
315 ip
->i_flag
|= IN_CHANGE
;
317 VATTR_SET_SUPPORTED(vap
, va_flags
);
319 nuid
= VATTR_IS_ACTIVE(vap
, va_uid
) ? vap
->va_uid
: (uid_t
)VNOVAL
;
320 ngid
= VATTR_IS_ACTIVE(vap
, va_gid
) ? vap
->va_gid
: (gid_t
)VNOVAL
;
321 if (nuid
!= (uid_t
)VNOVAL
|| ngid
!= (gid_t
)VNOVAL
) {
322 if ( (error
= ufs_chown(vp
, nuid
, ngid
, cred
, p
)) )
325 VATTR_SET_SUPPORTED(vap
, va_uid
);
326 VATTR_SET_SUPPORTED(vap
, va_gid
);
328 if (VATTR_IS_ACTIVE(vap
, va_data_size
)) {
329 if ( (error
= ffs_truncate_internal(vp
, vap
->va_data_size
, vap
->va_vaflags
& 0xffff, cred
)) )
332 VATTR_SET_SUPPORTED(vap
, va_data_size
);
335 if (VATTR_IS_ACTIVE(vap
, va_access_time
) || VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
336 if (VATTR_IS_ACTIVE(vap
, va_access_time
))
337 ip
->i_flag
|= IN_ACCESS
;
338 if (VATTR_IS_ACTIVE(vap
, va_modify_time
))
339 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
340 atimeval
.tv_sec
= vap
->va_access_time
.tv_sec
;
341 atimeval
.tv_usec
= vap
->va_access_time
.tv_nsec
/ 1000;
342 mtimeval
.tv_sec
= vap
->va_modify_time
.tv_sec
;
343 mtimeval
.tv_usec
= vap
->va_modify_time
.tv_nsec
/ 1000;
344 if ( (error
= ffs_update(vp
, &atimeval
, &mtimeval
, 1)) )
347 VATTR_SET_SUPPORTED(vap
, va_access_time
);
348 VATTR_SET_SUPPORTED(vap
, va_modify_time
);
350 if (VATTR_IS_ACTIVE(vap
, va_mode
)) {
351 if ((error
= ufs_chmod(vp
, (int)vap
->va_mode
, cred
, p
)))
354 VATTR_SET_SUPPORTED(vap
, va_mode
);
356 VN_KNOTE(vp
, NOTE_ATTRIB
);
362 * Change the mode on a file.
363 * Inode must be locked before calling.
366 ufs_chmod(struct vnode
*vp
, int mode
, kauth_cred_t cred
, struct proc
*p
)
368 register struct inode
*ip
= VTOI(vp
);
370 ip
->i_mode
&= ~ALLPERMS
;
371 ip
->i_mode
|= (mode
& ALLPERMS
);
372 ip
->i_flag
|= IN_CHANGE
;
377 * Perform chown operation on inode ip;
378 * inode must be locked prior to call.
381 ufs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
,
384 register struct inode
*ip
= VTOI(vp
);
391 int64_t change
; /* in bytes */
395 if (uid
== (uid_t
)VNOVAL
)
397 if (gid
== (gid_t
)VNOVAL
)
402 if ( (error
= getinoquota(ip
)) )
405 dqrele(ip
->i_dquot
[USRQUOTA
]);
406 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
409 dqrele(ip
->i_dquot
[GRPQUOTA
]);
410 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
412 devBlockSize
= vfs_devblocksize(vnode_mount(vp
));
414 change
= dbtob((int64_t)ip
->i_blocks
, devBlockSize
);
415 (void) chkdq(ip
, -change
, cred
, CHOWN
);
416 (void) chkiq(ip
, -1, cred
, CHOWN
);
417 for (i
= 0; i
< MAXQUOTAS
; i
++) {
418 dqrele(ip
->i_dquot
[i
]);
419 ip
->i_dquot
[i
] = NODQUOT
;
425 if ((error
= getinoquota(ip
)) == 0) {
427 dqrele(ip
->i_dquot
[USRQUOTA
]);
428 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
431 dqrele(ip
->i_dquot
[GRPQUOTA
]);
432 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
434 if ((error
= chkdq(ip
, change
, cred
, CHOWN
)) == 0) {
435 if ((error
= chkiq(ip
, 1, cred
, CHOWN
)) == 0)
438 (void) chkdq(ip
, -change
, cred
, CHOWN
|FORCE
);
440 for (i
= 0; i
< MAXQUOTAS
; i
++) {
441 dqrele(ip
->i_dquot
[i
]);
442 ip
->i_dquot
[i
] = NODQUOT
;
447 if (getinoquota(ip
) == 0) {
449 dqrele(ip
->i_dquot
[USRQUOTA
]);
450 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
453 dqrele(ip
->i_dquot
[GRPQUOTA
]);
454 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
456 (void) chkdq(ip
, change
, cred
, FORCE
|CHOWN
);
457 (void) chkiq(ip
, 1, cred
, FORCE
|CHOWN
);
458 (void) getinoquota(ip
);
463 panic("chown: lost quota");
465 if (ouid
!= uid
|| ogid
!= gid
)
466 ip
->i_flag
|= IN_CHANGE
;
472 struct vnop_ioctl_args
/* {
477 vfs_context_t a_context;
481 switch (ap
->a_command
) {
484 { register struct inode
*ip
;
485 register struct vnode
*vp
;
486 register struct fs
*fs
;
487 register struct radvisory
*ra
;
488 int devBlockSize
= 0;
493 ra
= (struct radvisory
*)(ap
->a_data
);
497 if ((u_int64_t
)ra
->ra_offset
>= ip
->i_size
) {
500 devBlockSize
= vfs_devblocksize(vnode_mount(vp
));
502 error
= advisory_read(vp
, ip
->i_size
, ra
->ra_offset
, ra
->ra_count
);
512 ufs_select(__unused
struct vnop_select_args
*ap
)
515 * We should really check to see if I/O is possible.
523 * NB Currently unsupported.
526 ufs_mmap(__unused
struct vnop_mmap_args
*ap
)
533 struct vnop_remove_args
/* {
536 struct componentname *a_cnp;
538 vfs_context_t a_context;
541 return(ufs_remove_internal(ap
->a_dvp
, ap
->a_vp
, ap
->a_cnp
, ap
->a_flags
));
546 ufs_remove_internal(vnode_t dvp
, vnode_t vp
, struct componentname
*cnp
, int flags
)
552 if (flags
& VNODE_REMOVE_NODELETEBUSY
) {
553 /* Caller requested Carbon delete semantics */
554 if (vnode_isinuse(vp
, 0)) {
559 cnp
->cn_flags
&= ~MODMASK
;
560 cnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
561 cnp
->cn_nameiop
= DELETE
;
563 (void) relookup(dvp
, &tvp
, cnp
);
568 panic("ufs_remove_internal: relookup returned a different vp");
570 * get rid of reference relookup returned
577 if ((error
= ufs_dirremove(dvp
, cnp
)) == 0) {
579 ip
->i_flag
|= IN_CHANGE
;
580 VN_KNOTE(vp
, NOTE_DELETE
);
581 VN_KNOTE(dvp
, NOTE_WRITE
);
592 struct vnop_link_args
/* {
594 struct vnode *a_tdvp;
595 struct componentname *a_cnp;
596 vfs_context_t a_context;
599 struct vnode
*vp
= ap
->a_vp
;
600 struct vnode
*tdvp
= ap
->a_tdvp
;
601 struct componentname
*cnp
= ap
->a_cnp
;
602 vfs_context_t ctx
= cnp
->cn_context
;
603 struct proc
*p
= vfs_context_proc(ctx
);
610 if ((nlink_t
)ip
->i_nlink
>= LINK_MAX
) {
615 ip
->i_flag
|= IN_CHANGE
;
617 error
= ffs_update(vp
, &tv
, &tv
, 1);
619 error
= ufs_direnter(ip
, tdvp
, cnp
);
622 ip
->i_flag
|= IN_CHANGE
;
624 VN_KNOTE(vp
, NOTE_LINK
);
625 VN_KNOTE(tdvp
, NOTE_WRITE
);
631 * whiteout vnode call
636 struct vnop_whiteout_args
/* {
638 struct componentname *a_cnp;
640 vfs_context_t a_context;
643 struct vnode
*dvp
= ap
->a_dvp
;
644 struct componentname
*cnp
= ap
->a_cnp
;
645 struct direct newdir
;
648 switch (ap
->a_flags
) {
650 /* 4.4 format directories support whiteout operations */
651 if (dvp
->v_mount
->mnt_maxsymlinklen
> 0)
656 /* create a new directory whiteout */
658 if (dvp
->v_mount
->mnt_maxsymlinklen
<= 0)
659 panic("ufs_whiteout: old format filesystem");
663 newdir
.d_namlen
= cnp
->cn_namelen
;
664 bcopy(cnp
->cn_nameptr
, newdir
.d_name
, (unsigned)cnp
->cn_namelen
+ 1);
665 newdir
.d_type
= DT_WHT
;
666 error
= ufs_direnter2(dvp
, &newdir
, cnp
->cn_context
);
670 /* remove an existing directory whiteout */
672 if (dvp
->v_mount
->mnt_maxsymlinklen
<= 0)
673 panic("ufs_whiteout: old format filesystem");
676 cnp
->cn_flags
&= ~DOWHITEOUT
;
677 error
= ufs_dirremove(dvp
, cnp
);
685 * Rename system call.
686 * rename("foo", "bar");
689 * link("foo", "bar");
691 * but ``atomically''. Can't do full commit without saving state in the
692 * inode on disk which isn't feasible at this time. Best we can do is
693 * always guarantee the target exists.
695 * Basic algorithm is:
697 * 1) Bump link count on source while we're linking it to the
698 * target. This also ensure the inode won't be deleted out
699 * from underneath us while we work (it may be truncated by
700 * a concurrent `trunc' or `open' for creation).
701 * 2) Link source to destination. If destination already exists,
703 * 3) Unlink source reference to inode if still around. If a
704 * directory was moved and the parent of the destination
705 * is different from the source, patch the ".." entry in the
710 struct vnop_rename_args
/* {
711 struct vnode *a_fdvp;
713 struct componentname *a_fcnp;
714 struct vnode *a_tdvp;
716 struct componentname *a_tcnp;
717 vfs_context_t a_context;
720 struct vnode
*tvp
= ap
->a_tvp
;
721 register struct vnode
*tdvp
= ap
->a_tdvp
;
722 struct vnode
*fvp
= ap
->a_fvp
;
723 struct vnode
*fdvp
= ap
->a_fdvp
;
724 struct componentname
*tcnp
= ap
->a_tcnp
;
725 struct componentname
*fcnp
= ap
->a_fcnp
;
726 vfs_context_t ctx
= fcnp
->cn_context
;
727 struct proc
*p
= vfs_context_proc(ctx
);
728 struct inode
*ip
, *xp
, *dp
;
729 struct dirtemplate dirbuf
;
731 ino_t doingdirectory
= 0, oldparent
= 0, newparent
= 0;
732 int error
= 0, ioflag
;
734 struct vnode
*rl_vp
= NULL
;
738 * Check if just deleting a link name or if we've lost a race.
739 * If another process completes the same rename after we've looked
740 * up the source and have blocked looking up the target, then the
741 * source and target inodes may be identical now although the
742 * names were never linked.
745 if (fvp
->v_type
== VDIR
) {
747 * Linked directories are impossible, so we must
748 * have lost the race. Pretend that the rename
749 * completed before the lookup.
751 #ifdef UFS_RENAME_DEBUG
752 printf("ufs_rename: fvp == tvp for directories\n");
759 * don't need to check in here for permissions, must already have been granted
760 * ufs_remove_internal now does the relookup
762 error
= ufs_remove_internal(fdvp
, fvp
, fcnp
, 0);
767 * because the vnode_authorization code may have looked up in this directory
768 * between the original lookup and the actual call to VNOP_RENAME, we need
769 * to reset the directory hints... since we haven't dropped the FSNODELOCK
770 * on tdvp since this whole thing started, we expect relookup to return
771 * tvp (which may be NULL)
773 tcnp
->cn_flags
&= ~MODMASK
;
774 tcnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
776 if ( (error
= relookup(tdvp
, &rl_vp
, tcnp
)) )
777 panic("ufs_rename: relookup on target returned error");
780 * Don't panic. The only way this state will be reached is if
781 * another rename has taken effect. In that case, it's safe
782 * to restart this rename and let things sort themselves out.
796 if ((ip
->i_mode
& IFMT
) == IFDIR
) {
797 if (ip
->i_flag
& IN_RENAME
) {
801 ip
->i_flag
|= IN_RENAME
;
802 oldparent
= dp
->i_number
;
805 VN_KNOTE(fdvp
, NOTE_WRITE
); /* XXX right place? */
808 * When the target exists, both the directory
809 * and target vnodes are returned locked.
817 * 1) Bump link count while we're moving stuff
818 * around. If we crash somewhere before
819 * completing our work, the link count
820 * may be wrong, but correctable.
823 ip
->i_flag
|= IN_CHANGE
;
825 if ( (error
= ffs_update(fvp
, &tv
, &tv
, 1)) ) {
830 * If ".." must be changed (ie the directory gets a new
831 * parent) then the source directory must not be in the
832 * directory heirarchy above the target, as this would
833 * orphan everything below the source directory. Also
834 * the user must have write permission in the source so
835 * as to be able to change "..". We must repeat the call
836 * to namei, as the parent directory is unlocked by the
837 * call to checkpath().
840 if (oldparent
!= dp
->i_number
)
841 newparent
= dp
->i_number
;
843 if (doingdirectory
&& newparent
) {
844 if (error
) /* write access check above */
847 if ( (error
= ufs_checkpath(ip
, dp
, vfs_context_ucred(tcnp
->cn_context
))) )
850 if ( (error
= relookup(tdvp
, &tvp
, tcnp
)) )
861 * 2) If target doesn't exist, link the target
862 * to the source and unlink the source.
863 * Otherwise, rewrite the target directory
864 * entry to reference the source inode and
865 * expunge the original entry's existence.
868 if (dp
->i_dev
!= ip
->i_dev
)
869 panic("rename: EXDEV");
871 * Account for ".." in new directory.
872 * When source and destination have the same
873 * parent we don't fool with the link count.
875 if (doingdirectory
&& newparent
) {
876 if ((nlink_t
)dp
->i_nlink
>= LINK_MAX
) {
881 dp
->i_flag
|= IN_CHANGE
;
882 if ( (error
= ffs_update(tdvp
, &tv
, &tv
, 1)) )
885 if ( (error
= ufs_direnter(ip
, tdvp
, tcnp
)) ) {
886 if (doingdirectory
&& newparent
) {
888 dp
->i_flag
|= IN_CHANGE
;
889 (void)ffs_update(tdvp
, &tv
, &tv
, 1);
893 VN_KNOTE(tdvp
, NOTE_WRITE
);
895 if (xp
->i_dev
!= dp
->i_dev
|| xp
->i_dev
!= ip
->i_dev
)
896 panic("rename: EXDEV");
898 * Short circuit rename(foo, foo).
900 if (xp
->i_number
== ip
->i_number
)
901 panic("rename: same file");
903 * Target must be empty if a directory and have no links
904 * to it. Also, ensure source and target are compatible
905 * (both directories, or both not directories).
907 if ((xp
->i_mode
&IFMT
) == IFDIR
) {
908 if (!ufs_dirempty(xp
, dp
->i_number
, vfs_context_ucred(tcnp
->cn_context
)) ||
913 if (!doingdirectory
) {
918 } else if (doingdirectory
) {
922 if ( (error
= ufs_dirrewrite(dp
, ip
, tcnp
)) )
925 * If the target directory is in the same
926 * directory as the source directory,
927 * decrement the link count on the parent
928 * of the target directory.
930 if (doingdirectory
&& !newparent
) {
932 dp
->i_flag
|= IN_CHANGE
;
934 VN_KNOTE(tdvp
, NOTE_WRITE
);
936 * Adjust the link count of the target to
937 * reflect the dirrewrite above. If this is
938 * a directory it is empty and there are
939 * no links to it, so we can squash the inode and
940 * any space associated with it. We disallowed
941 * renaming over top of a directory with links to
942 * it above, as the remaining link would point to
943 * a directory without "." or ".." entries.
946 if (doingdirectory
) {
947 if (--xp
->i_nlink
!= 0)
948 panic("rename: linked directory");
949 ioflag
= ((tvp
)->v_mount
->mnt_flag
& MNT_ASYNC
) ?
951 error
= ffs_truncate_internal(tvp
, (off_t
)0, ioflag
, vfs_context_ucred(tcnp
->cn_context
));
953 xp
->i_flag
|= IN_CHANGE
;
954 VN_KNOTE(tvp
, NOTE_DELETE
);
962 * 3) Unlink the source.
964 fcnp
->cn_flags
&= ~MODMASK
;
965 fcnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
967 (void) relookup(fdvp
, &fvp
, fcnp
);
975 * From name has disappeared.
978 panic("rename: lost dir entry");
983 * Ensure that the directory entry still exists and has not
984 * changed while the new name has been entered. If the source is
985 * a file then the entry may have been unlinked or renamed. In
986 * either case there is no further work to be done. If the source
987 * is a directory then it cannot have been rmdir'ed; its link
988 * count of three would cause a rmdir to fail with ENOTEMPTY.
989 * The IN_RENAME flag ensures that it cannot be moved by another
994 panic("rename: lost dir entry");
997 * If the source is a directory with a
998 * new parent, the link count of the old
999 * parent directory must be decremented
1000 * and ".." set to point to the new parent.
1002 if (doingdirectory
&& newparent
) {
1004 dp
->i_flag
|= IN_CHANGE
;
1005 error
= vn_rdwr(UIO_READ
, fvp
, (caddr_t
)&dirbuf
,
1006 sizeof (struct dirtemplate
), (off_t
)0,
1007 UIO_SYSSPACE32
, IO_NODELOCKED
,
1008 vfs_context_ucred(tcnp
->cn_context
), (int *)0, (struct proc
*)0);
1010 # if (BYTE_ORDER == LITTLE_ENDIAN)
1011 if (fvp
->v_mount
->mnt_maxsymlinklen
<= 0)
1012 namlen
= dirbuf
.dotdot_type
;
1014 namlen
= dirbuf
.dotdot_namlen
;
1016 namlen
= dirbuf
.dotdot_namlen
;
1019 dirbuf
.dotdot_name
[0] != '.' ||
1020 dirbuf
.dotdot_name
[1] != '.') {
1021 ufs_dirbad(xp
, (doff_t
)12,
1022 "rename: mangled dir");
1024 dirbuf
.dotdot_ino
= newparent
;
1025 (void) vn_rdwr(UIO_WRITE
, fvp
,
1027 sizeof (struct dirtemplate
),
1028 (off_t
)0, UIO_SYSSPACE32
,
1029 IO_NODELOCKED
|IO_SYNC
,
1030 vfs_context_ucred(tcnp
->cn_context
), (int *)0,
1036 error
= ufs_dirremove(fdvp
, fcnp
);
1039 xp
->i_flag
|= IN_CHANGE
;
1041 xp
->i_flag
&= ~IN_RENAME
;
1043 VN_KNOTE(fvp
, NOTE_RENAME
);
1055 ip
->i_flag
&= ~IN_RENAME
;
1058 ip
->i_flag
|= IN_CHANGE
;
1059 ip
->i_flag
&= ~IN_RENAME
;
1066 * A virgin directory (no blushing please).
1068 static struct dirtemplate mastertemplate
= {
1069 0, 12, DT_DIR
, 1, ".",
1070 0, DIRBLKSIZ
- 12, DT_DIR
, 2, ".."
1072 static struct odirtemplate omastertemplate
= {
1074 0, DIRBLKSIZ
- 12, 2, ".."
1082 struct vnop_mkdir_args
/* {
1083 struct vnode *a_dvp;
1084 struct vnode **a_vpp;
1085 struct componentname *a_cnp;
1086 struct vnode_attr *a_vap;
1087 vfs_context_t a_context;
1090 register struct vnode
*dvp
= ap
->a_dvp
;
1091 register struct vnode_attr
*vap
= ap
->a_vap
;
1092 register struct componentname
*cnp
= ap
->a_cnp
;
1093 register struct inode
*ip
, *dp
;
1095 struct dirtemplate dirtemplate
, *dtp
;
1099 /* use relookup to force correct directory hints */
1100 cnp
->cn_flags
&= ~MODMASK
;
1101 cnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
1102 cnp
->cn_nameiop
= CREATE
;
1104 (void) relookup(dvp
, &tvp
, cnp
);
1106 /* get rid of reference relookup returned */
1111 if ((nlink_t
)dp
->i_nlink
>= LINK_MAX
) {
1115 dmode
= vap
->va_mode
& 0777;
1119 * Must simulate part of ufs_makeinode here to acquire the inode,
1120 * but not have it entered in the parent directory. The entry is
1121 * made later after writing "." and ".." entries.
1123 if ( (error
= ffs_valloc(dvp
, (mode_t
)dmode
, vfs_context_ucred(cnp
->cn_context
), &tvp
)) )
1126 ip
->i_uid
= ap
->a_vap
->va_uid
;
1127 ip
->i_gid
= ap
->a_vap
->va_gid
;
1128 VATTR_SET_SUPPORTED(ap
->a_vap
, va_mode
);
1129 VATTR_SET_SUPPORTED(ap
->a_vap
, va_uid
);
1130 VATTR_SET_SUPPORTED(ap
->a_vap
, va_gid
);
1132 if ((error
= getinoquota(ip
)) ||
1133 (error
= chkiq(ip
, 1, vfs_context_ucred(cnp
->cn_context
), 0))) {
1134 ffs_vfree(tvp
, ip
->i_number
, dmode
);
1139 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
1142 if (cnp
->cn_flags
& ISWHITEOUT
)
1143 ip
->i_flags
|= UF_OPAQUE
;
1145 error
= ffs_update(tvp
, &tv
, &tv
, 1);
1148 * Bump link count in parent directory
1149 * to reflect work done below. Should
1150 * be done before reference is created
1151 * so reparation is possible if we crash.
1154 dp
->i_flag
|= IN_CHANGE
;
1155 if ( (error
= ffs_update(dvp
, &tv
, &tv
, 1)) )
1158 /* Initialize directory with "." and ".." from static template. */
1159 if (dvp
->v_mount
->mnt_maxsymlinklen
> 0)
1160 dtp
= &mastertemplate
;
1162 dtp
= (struct dirtemplate
*)&omastertemplate
;
1164 dirtemplate
.dot_ino
= ip
->i_number
;
1165 dirtemplate
.dotdot_ino
= dp
->i_number
;
1166 error
= vn_rdwr(UIO_WRITE
, tvp
, (caddr_t
)&dirtemplate
,
1167 sizeof (dirtemplate
), (off_t
)0, UIO_SYSSPACE32
,
1168 IO_NODELOCKED
|IO_SYNC
, vfs_context_ucred(cnp
->cn_context
), (int *)0, (struct proc
*)0);
1171 dp
->i_flag
|= IN_CHANGE
;
1174 if (DIRBLKSIZ
> VFSTOUFS(dvp
->v_mount
)->um_mountp
->mnt_vfsstat
.f_bsize
)
1175 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1177 ip
->i_size
= DIRBLKSIZ
;
1178 ip
->i_flag
|= IN_CHANGE
;
1181 /* Directory set up, now install it's entry in the parent directory. */
1182 if ( (error
= ufs_direnter(ip
, dvp
, cnp
)) ) {
1184 dp
->i_flag
|= IN_CHANGE
;
1188 * No need to do an explicit vnop_truncate here, vnode_put will do it
1189 * for us because we set the link count to 0.
1193 ip
->i_flag
|= IN_CHANGE
;
1195 * since we're not returning tvp due to the error,
1196 * we're responsible for releasing it here
1200 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1208 * Rmdir system call.
1212 struct vnop_rmdir_args
/* {
1213 struct vnode *a_dvp;
1215 struct componentname *a_cnp;
1216 vfs_context_t a_context;
1219 struct vnode
*vp
= ap
->a_vp
;
1220 struct vnode
*dvp
= ap
->a_dvp
;
1222 struct componentname
*cnp
= ap
->a_cnp
;
1223 struct inode
*ip
, *dp
;
1230 * No rmdir "." please.
1236 cnp
->cn_flags
&= ~MODMASK
;
1237 cnp
->cn_flags
|= (WANTPARENT
| NOCACHE
);
1239 (void) relookup(dvp
, &tvp
, cnp
);
1244 panic("ufs_rmdir: relookup returned a different vp");
1246 * get rid of reference relookup returned
1252 * Verify the directory is empty (and valid).
1253 * (Rmdir ".." won't be valid since
1254 * ".." will contain a reference to
1255 * the current directory and thus be
1259 if (ip
->i_nlink
!= 2 ||
1260 !ufs_dirempty(ip
, dp
->i_number
, vfs_context_ucred(cnp
->cn_context
))) {
1265 * Delete reference to directory before purging
1266 * inode. If we crash in between, the directory
1267 * will be reattached to lost+found,
1269 if ( (error
= ufs_dirremove(dvp
, cnp
)) )
1271 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1273 dp
->i_flag
|= IN_CHANGE
;
1276 * Truncate inode. The only stuff left
1277 * in the directory is "." and "..". The
1278 * "." reference is inconsequential since
1279 * we're quashing it. The ".." reference
1280 * has already been adjusted above. We've
1281 * removed the "." reference and the reference
1282 * in the parent directory, but there may be
1283 * other hard links so decrement by 2 and
1284 * worry about them later.
1287 ioflag
= ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) ? 0 : IO_SYNC
;
1288 error
= ffs_truncate_internal(vp
, (off_t
)0, ioflag
, vfs_context_ucred(cnp
->cn_context
));
1289 cache_purge(ITOV(ip
));
1291 VN_KNOTE(vp
, NOTE_DELETE
);
1296 * symlink -- make a symbolic link
1300 struct vnop_symlink_args
/* {
1301 struct vnode *a_dvp;
1302 struct vnode **a_vpp;
1303 struct componentname *a_cnp;
1304 struct vnode_attr *a_vap;
1306 vfs_context_t a_context;
1309 register struct vnode
*vp
, **vpp
= ap
->a_vpp
;
1310 register struct inode
*ip
;
1313 if ( (error
= ufs_makeinode(ap
->a_vap
, ap
->a_dvp
, vpp
, ap
->a_cnp
)) )
1315 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
1317 len
= strlen(ap
->a_target
);
1318 if (len
< vp
->v_mount
->mnt_maxsymlinklen
) {
1320 bcopy(ap
->a_target
, (char *)ip
->i_shortlink
, len
);
1322 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1324 error
= vn_rdwr(UIO_WRITE
, vp
, ap
->a_target
, len
, (off_t
)0,
1325 UIO_SYSSPACE32
, IO_NODELOCKED
, vfs_context_ucred(ap
->a_cnp
->cn_context
), (int *)0,
1331 * Vnode op for reading directories.
1333 * The routine below assumes that the on-disk format of a directory
1334 * is the same as that defined by <sys/dirent.h>. If the on-disk
1335 * format changes, then it will be necessary to do a conversion
1336 * from the on-disk format that read returns to the format defined
1337 * by <sys/dirent.h>.
1341 struct vnop_readdir_args
/* {
1347 vfs_context_t a_context;
1350 struct uio
*uio
= ap
->a_uio
;
1354 if (ap
->a_flags
& VNODE_READDIR_EXTENDED
) {
1355 return ufs_readdirext(ap
->a_vp
, uio
, ap
->a_eofflag
,
1356 ap
->a_numdirent
, ap
->a_context
);
1359 // LP64todo - fix this
1360 count
= uio_resid(uio
);
1361 /* Make sure we don't return partial entries. */
1362 count
-= (uio
->uio_offset
+ count
) & (DIRBLKSIZ
-1);
1365 // LP64todo - fix this
1366 lost
= uio_resid(uio
) - count
;
1367 uio_setresid(uio
, count
);
1368 uio_iov_len_set(uio
, count
);
1369 # if (BYTE_ORDER == LITTLE_ENDIAN)
1370 if (ap
->a_vp
->v_mount
->mnt_maxsymlinklen
> 0) {
1371 error
= ffs_read_internal(ap
->a_vp
, uio
, 0);
1373 struct dirent
*dp
, *edp
;
1375 struct iovec_32 aiov
;
1381 auio
.uio_iovs
.iov32p
= &aiov
;
1382 auio
.uio_iovcnt
= 1;
1383 #if 1 /* LP64todo - can't use new segment flags until the drivers are ready */
1384 auio
.uio_segflg
= UIO_SYSSPACE
;
1386 auio
.uio_segflg
= UIO_SYSSPACE32
;
1388 aiov
.iov_len
= count
;
1389 MALLOC(dirbuf
, caddr_t
, count
, M_TEMP
, M_WAITOK
);
1390 aiov
.iov_base
= (uintptr_t)dirbuf
;
1391 error
= ffs_read_internal(ap
->a_vp
, &auio
, 0);
1393 // LP64todo - fix this
1394 readcnt
= count
- uio_resid(&auio
);
1395 edp
= (struct dirent
*)&dirbuf
[readcnt
];
1396 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
1398 dp
->d_namlen
= dp
->d_type
;
1400 if (dp
->d_reclen
> 0) {
1401 dp
= (struct dirent
*)
1402 ((char *)dp
+ dp
->d_reclen
);
1409 error
= uiomove(dirbuf
, readcnt
, uio
);
1411 FREE(dirbuf
, M_TEMP
);
1414 error
= ffs_read_internal(ap
->a_vp
, uio
, 0);
1417 uio_setresid(uio
, (uio_resid(uio
) + lost
));
1419 *ap
->a_eofflag
= (off_t
)VTOI(ap
->a_vp
)->i_size
<= uio
->uio_offset
;
1425 * ufs_readdirext reads directory entries into the buffer pointed
1426 * to by uio, in a filesystem independent format. Up to uio_resid
1427 * bytes of data can be transferred. The data in the buffer is a
1428 * series of packed direntry structures where each one contains the
1429 * following entries:
1431 * d_reclen: length of record
1432 * d_ino: file number of entry
1433 * d_seekoff: seek offset (used by NFS server, aka cookie)
1435 * d_namlen: length of string in d_name
1436 * d_name: null terminated file name
1438 * The current position (uio_offset) refers to the next block of
1439 * entries. The offset will only be set to a value previously
1440 * returned by ufs_readdirext or zero. This offset does not have
1441 * to match the number of bytes returned (in uio_resid).
1443 #define EXT_DIRENT_LEN(namlen) \
1444 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 3) & ~3)
1447 ufs_readdirext(vnode_t vp
, uio_t uio
, int *eofflag
, int *numdirent
,
1448 __unused vfs_context_t context
)
1452 off_t off
= uio
->uio_offset
;
1453 struct dirent
*dp
, *edp
;
1455 struct iovec_32 aiov
;
1457 struct direntry
*xdp
;
1460 // LP64todo - fix this
1461 count
= uio_resid(uio
);
1462 /* Make sure we don't return partial entries. */
1463 count
-= (uio
->uio_offset
+ count
) & (DIRBLKSIZ
-1);
1466 // LP64todo - fix this
1467 lost
= uio_resid(uio
) - count
;
1468 uio_setresid(uio
, count
);
1469 uio_iov_len_set(uio
, count
);
1472 auio
.uio_iovs
.iov32p
= &aiov
;
1473 auio
.uio_iovcnt
= 1;
1474 /* LP64todo - can't use new segment flags until the drivers are ready */
1475 auio
.uio_segflg
= UIO_SYSSPACE
;
1476 aiov
.iov_len
= count
;
1477 MALLOC(dirbuf
, caddr_t
, count
, M_TEMP
, M_WAITOK
);
1478 aiov
.iov_base
= (uintptr_t)dirbuf
;
1480 MALLOC(xdp
, struct direntry
*, sizeof(struct direntry
), M_TEMP
, M_WAITOK
);
1482 error
= ffs_read_internal(vp
, &auio
, 0);
1486 // LP64todo - fix this
1487 edp
= (struct dirent
*)&dirbuf
[count
- uio_resid(&auio
)];
1488 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
1490 #if (BYTE_ORDER == LITTLE_ENDIAN)
1494 * We only need to swap the d_namlen and
1495 * d_type fields for older versions of UFS,
1496 * which we check by looking at the mnt_maxsymlinklen
1499 if (vp
->v_mount
->mnt_maxsymlinklen
<= 0) {
1501 dp
->d_namlen
= dp
->d_type
;
1506 xdp
->d_reclen
= EXT_DIRENT_LEN(dp
->d_namlen
);
1507 if (xdp
->d_reclen
> uio_resid(uio
)) {
1508 break; /* user buffer is full */
1510 xdp
->d_ino
= dp
->d_ino
;
1511 xdp
->d_namlen
= dp
->d_namlen
;
1512 xdp
->d_type
= dp
->d_type
;
1514 bcopy(dp
->d_name
, xdp
->d_name
, dp
->d_namlen
+ 1);
1515 off
+= dp
->d_reclen
;
1516 xdp
->d_seekoff
= off
;
1517 error
= uiomove((caddr_t
)xdp
, xdp
->d_reclen
, uio
);
1519 off
-= dp
->d_reclen
;
1520 break; /* unexpected this error is */
1524 if (dp
->d_reclen
> 0) {
1525 dp
= (struct dirent
*)
1526 ((char *)dp
+ dp
->d_reclen
);
1533 FREE(dirbuf
, M_TEMP
);
1536 /* Use the on-disk dirent offset */
1537 uio_setoffset(uio
, off
);
1538 *numdirent
= nentries
;
1539 uio_setresid(uio
, (uio_resid(uio
) + lost
));
1541 *eofflag
= (off_t
)VTOI(vp
)->i_size
<= uio
->uio_offset
;
1547 * Return target name of a symbolic link
1551 struct vnop_readlink_args
/* {
1554 vfs_context_t a_context;
1557 register struct vnode
*vp
= ap
->a_vp
;
1558 register struct inode
*ip
= VTOI(vp
);
1562 if (isize
< vp
->v_mount
->mnt_maxsymlinklen
) {
1563 uiomove((char *)ip
->i_shortlink
, isize
, ap
->a_uio
);
1566 return (ffs_read_internal(vp
, ap
->a_uio
, 0));
1570 * prepare and issue the I/O
1574 struct vnop_strategy_args
/* {
1578 buf_t bp
= ap
->a_bp
;
1579 vnode_t vp
= buf_vnode(bp
);
1580 struct inode
*ip
= VTOI(vp
);
1582 return (buf_strategy(ip
->i_devvp
, ap
));
1586 * Read wrapper for special devices.
1590 struct vnop_read_args
/* {
1594 vfs_context_t a_context;
1601 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
1602 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_read
), ap
));
1606 * Write wrapper for special devices.
1610 struct vnop_write_args
/* {
1614 kauth_cred_t a_cred;
1619 * Set update and change flags.
1621 VTOI(ap
->a_vp
)->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1622 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_write
), ap
));
1626 * Close wrapper for special devices.
1628 * Update the times on the inode then do device close.
1632 struct vnop_close_args
/* {
1635 vfs_context_t a_context;
1638 struct vnode
*vp
= ap
->a_vp
;
1639 struct inode
*ip
= VTOI(vp
);
1642 if (ap
->a_vp
->v_usecount
> 1) {
1644 ITIMES(ip
, &tv
, &tv
);
1646 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_close
), ap
));
1651 * Read wrapper for fifo's
1655 struct vnop_read_args
/* {
1659 vfs_context_t a_context;
1662 extern int (**fifo_vnodeop_p
)(void *);
1667 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
1668 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vnop_read
), ap
));
1672 * Write wrapper for fifo's.
1676 struct vnop_write_args
/* {
1680 kauth_cred_t a_cred;
1683 extern int (**fifo_vnodeop_p
)(void *);
1686 * Set update and change flags.
1688 VTOI(ap
->a_vp
)->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1689 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vnop_write
), ap
));
1693 * Close wrapper for fifo's.
1695 * Update the times on the inode then do device close.
1699 struct vnop_close_args
/* {
1702 vfs_context_t a_context;
1705 extern int (**fifo_vnodeop_p
)(void *);
1706 struct vnode
*vp
= ap
->a_vp
;
1707 struct inode
*ip
= VTOI(vp
);
1710 if (ap
->a_vp
->v_usecount
> 1) {
1712 ITIMES(ip
, &tv
, &tv
);
1714 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vnop_close
), ap
));
1718 * kqfilt_add wrapper for fifos.
1720 * Fall through to ufs kqfilt_add routines if needed
1723 ufsfifo_kqfilt_add(ap
)
1724 struct vnop_kqfilt_add_args
*ap
;
1726 extern int (**fifo_vnodeop_p
)(void *);
1729 error
= VOCALL(fifo_vnodeop_p
, VOFFSET(vnop_kqfilt_add
), ap
);
1731 error
= ufs_kqfilt_add(ap
);
1737 * kqfilt_remove wrapper for fifos.
1739 * Fall through to ufs kqfilt_remove routines if needed
1742 ufsfifo_kqfilt_remove(ap
)
1743 struct vnop_kqfilt_remove_args
*ap
;
1745 extern int (**fifo_vnodeop_p
)(void *);
1748 error
= VOCALL(fifo_vnodeop_p
, VOFFSET(vnop_kqfilt_remove
), ap
);
1750 error
= ufs_kqfilt_remove(ap
);
1758 static struct filterops ufsread_filtops
=
1759 { 1, NULL
, filt_ufsdetach
, filt_ufsread
};
1760 static struct filterops ufswrite_filtops
=
1761 { 1, NULL
, filt_ufsdetach
, filt_ufswrite
};
1762 static struct filterops ufsvnode_filtops
=
1763 { 1, NULL
, filt_ufsdetach
, filt_ufsvnode
};
1767 #% kqfilt_add vp L L L
1770 IN struct vnode *vp;
1771 IN struct knote *kn;
1772 IN vfs_context_t context;
1776 struct vnop_kqfilt_add_args
/* {
1779 vfs_context_t a_context;
1782 struct vnode
*vp
= ap
->a_vp
;
1783 struct knote
*kn
= ap
->a_kn
;
1785 switch (kn
->kn_filter
) {
1787 kn
->kn_fop
= &ufsread_filtops
;
1790 kn
->kn_fop
= &ufswrite_filtops
;
1793 kn
->kn_fop
= &ufsvnode_filtops
;
1799 kn
->kn_hook
= (caddr_t
)vp
;
1800 kn
->kn_hookid
= vnode_vid(vp
);
1802 KNOTE_ATTACH(&VTOI(vp
)->i_knotes
, kn
);
1808 filt_ufsdetach(struct knote
*kn
)
1812 struct proc
*p
= current_proc();
1814 vp
= (struct vnode
*)kn
->kn_hook
;
1816 if (vnode_getwithvid(vp
, kn
->kn_hookid
))
1819 result
= KNOTE_DETACH(&VTOI(vp
)->i_knotes
, kn
);
1824 filt_ufsread(struct knote
*kn
, long hint
)
1826 struct vnode
*vp
= (struct vnode
*)kn
->kn_hook
;
1832 if ((vnode_getwithvid(vp
, kn
->kn_hookid
) != 0)) {
1837 if (hint
== NOTE_REVOKE
) {
1839 * filesystem is gone, so set the EOF flag and schedule
1840 * the knote for deletion.
1842 kn
->kn_flags
|= (EV_EOF
| EV_ONESHOT
);
1846 /* poll(2) semantics dictate always returning true */
1847 if (kn
->kn_flags
& EV_POLL
) {
1852 kn
->kn_data
= ip
->i_size
- kn
->kn_fp
->f_fglob
->fg_offset
;
1853 result
= (kn
->kn_data
!= 0);
1863 filt_ufswrite(struct knote
*kn
, long hint
)
1869 if ((vnode_getwithvid(kn
->kn_hook
, kn
->kn_hookid
) != 0)) {
1872 vnode_put(kn
->kn_hook
);
1874 if (hint
== NOTE_REVOKE
) {
1876 * filesystem is gone, so set the EOF flag and schedule
1877 * the knote for deletion.
1880 kn
->kn_flags
|= (EV_EOF
| EV_ONESHOT
);
1888 filt_ufsvnode(struct knote
*kn
, long hint
)
1892 if ((vnode_getwithvid(kn
->kn_hook
, kn
->kn_hookid
) != 0)) {
1895 vnode_put(kn
->kn_hook
);
1897 if (kn
->kn_sfflags
& hint
)
1898 kn
->kn_fflags
|= hint
;
1899 if ((hint
== NOTE_REVOKE
)) {
1900 kn
->kn_flags
|= (EV_EOF
| EV_ONESHOT
);
1904 return (kn
->kn_fflags
!= 0);
1908 * Return POSIX pathconf information applicable to ufs filesystems.
1912 struct vnop_pathconf_args
/* {
1916 vfs_context_t a_context;
1920 switch (ap
->a_name
) {
1922 *ap
->a_retval
= LINK_MAX
;
1925 *ap
->a_retval
= NAME_MAX
;
1928 *ap
->a_retval
= PATH_MAX
;
1931 *ap
->a_retval
= PIPE_BUF
;
1933 case _PC_CHOWN_RESTRICTED
:
1946 * Allocate a new inode.
1949 ufs_makeinode(vap
, dvp
, vpp
, cnp
)
1950 struct vnode_attr
*vap
;
1953 struct componentname
*cnp
;
1955 register struct inode
*ip
, *pdir
;
1962 mode
= MAKEIMODE(vap
->va_type
, vap
->va_mode
);
1965 if ((mode
& IFMT
) == 0)
1968 if ( (error
= ffs_valloc(dvp
, (mode_t
)mode
, vfs_context_ucred(cnp
->cn_context
), &tvp
)) )
1972 ip
->i_gid
= vap
->va_gid
;
1973 ip
->i_uid
= vap
->va_uid
;
1974 VATTR_SET_SUPPORTED(vap
, va_mode
);
1975 VATTR_SET_SUPPORTED(vap
, va_uid
);
1976 VATTR_SET_SUPPORTED(vap
, va_gid
);
1978 if ((error
= getinoquota(ip
)) ||
1979 (error
= chkiq(ip
, 1, vfs_context_ucred(cnp
->cn_context
), 0))) {
1980 ffs_vfree(tvp
, ip
->i_number
, mode
);
1985 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
1989 if (cnp
->cn_flags
& ISWHITEOUT
)
1990 ip
->i_flags
|= UF_OPAQUE
;
1993 * Make sure inode goes to disk before directory entry.
1996 if ( (error
= ffs_update(tvp
, &tv
, &tv
, 1)) )
1998 if ( (error
= ufs_direnter(ip
, dvp
, cnp
)) )
2006 * Write error occurred trying to update the inode
2007 * or the directory so must deallocate the inode.
2010 ip
->i_flag
|= IN_CHANGE
;