Bug Summary

File:ufs/ufs/ufs_vnops.c
Warning:line 1302, column 2
Value stored to 'error' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ufs_vnops.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/ufs/ufs/ufs_vnops.c
1/* $OpenBSD: ufs_vnops.c,v 1.155 2021/12/12 09:14:59 visa Exp $ */
2/* $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $ */
3
4/*
5 * Copyright (c) 1982, 1986, 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 * (c) UNIX System Laboratories, Inc.
8 * All or some portions of this file are derived from material licensed
9 * to the University of California by American Telephone and Telegraph
10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 * the permission of UNIX System Laboratories, Inc.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/namei.h>
43#include <sys/resourcevar.h>
44#include <sys/kernel.h>
45#include <sys/fcntl.h>
46#include <sys/file.h>
47#include <sys/stat.h>
48#include <sys/buf.h>
49#include <sys/proc.h>
50#include <sys/mount.h>
51#include <sys/vnode.h>
52#include <sys/malloc.h>
53#include <sys/pool.h>
54#include <sys/dirent.h>
55#include <sys/lockf.h>
56#include <sys/event.h>
57#include <sys/poll.h>
58#include <sys/specdev.h>
59#include <sys/unistd.h>
60
61#include <miscfs/fifofs/fifo.h>
62
63#include <ufs/ufs/quota.h>
64#include <ufs/ufs/inode.h>
65#include <ufs/ufs/dir.h>
66#include <ufs/ufs/ufsmount.h>
67#include <ufs/ufs/ufs_extern.h>
68#ifdef UFS_DIRHASH1
69#include <ufs/ufs/dirhash.h>
70#endif
71#include <ufs/ext2fs/ext2fs_extern.h>
72
73#include <uvm/uvm_extern.h>
74
75int ufs_chmod(struct vnode *, int, struct ucred *);
76int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *);
77int filt_ufsread(struct knote *, long);
78int filt_ufswrite(struct knote *, long);
79int filt_ufsvnode(struct knote *, long);
80void filt_ufsdetach(struct knote *);
81
82/*
83 * A virgin directory (no blushing please).
84 */
85static struct dirtemplate mastertemplate = {
86 0, 12, DT_DIR4, 1, ".",
87 0, DIRBLKSIZ(1 << 9) - 12, DT_DIR4, 2, ".."
88};
89static struct odirtemplate omastertemplate = {
90 0, 12, 1, ".",
91 0, DIRBLKSIZ(1 << 9) - 12, 2, ".."
92};
93
94/*
95 * Update the times in the inode
96 */
97void
98ufs_itimes(struct vnode *vp)
99{
100 struct inode *ip;
101 struct timespec ts;
102
103 ip = VTOI(vp)((struct inode *)(vp)->v_data);
104 if ((ip->i_flag & (IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004)) == 0)
105 return;
106
107 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
108 goto out;
109
110#ifdef EXT2FS1
111 if (IS_EXT2_VNODE(ip->i_vnode)(ip->i_vnode->v_tag == VT_EXT2FS)) {
112 EXT2FS_ITIMES(ip)do { if ((ip)->i_flag & (0x0001 | 0x0002 | 0x0004)) { (
ip)->i_flag |= 0x0008; if ((ip)->i_flag & 0x0001) (
ip)->dinode_u.e2fs_din->e2di_atime = gettime(); if ((ip
)->i_flag & 0x0004) (ip)->dinode_u.e2fs_din->e2di_mtime
= gettime(); if ((ip)->i_flag & 0x0002) { (ip)->dinode_u
.e2fs_din->e2di_ctime = gettime(); (ip)->i_modrev++; } (
ip)->i_flag &= ~(0x0001 | 0x0002 | 0x0004); } } while (
0)
;
113 goto out;
114 }
115#endif
116
117 if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000))
118 ip->i_flag |= IN_LAZYMOD0x0080;
119 else
120 ip->i_flag |= IN_MODIFIED0x0008;
121
122 getnanotime(&ts);
123 if (ip->i_flag & IN_ACCESS0x0001) {
124 DIP_ASSIGN(ip, atime, ts.tv_sec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_atime = (ts.tv_sec); else (ip)->dinode_u.
ffs2_din->di_atime = (ts.tv_sec); } while (0)
;
125 DIP_ASSIGN(ip, atimensec, ts.tv_nsec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_atimensec = (ts.tv_nsec); else (ip)->dinode_u
.ffs2_din->di_atimensec = (ts.tv_nsec); } while (0)
;
126 }
127 if (ip->i_flag & IN_UPDATE0x0004) {
128 DIP_ASSIGN(ip, mtime, ts.tv_sec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mtime = (ts.tv_sec); else (ip)->dinode_u.
ffs2_din->di_mtime = (ts.tv_sec); } while (0)
;
129 DIP_ASSIGN(ip, mtimensec, ts.tv_nsec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mtimensec = (ts.tv_nsec); else (ip)->dinode_u
.ffs2_din->di_mtimensec = (ts.tv_nsec); } while (0)
;
130 }
131 if (ip->i_flag & IN_CHANGE0x0002) {
132 DIP_ASSIGN(ip, ctime, ts.tv_sec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_ctime = (ts.tv_sec); else (ip)->dinode_u.
ffs2_din->di_ctime = (ts.tv_sec); } while (0)
;
133 DIP_ASSIGN(ip, ctimensec, ts.tv_nsec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_ctimensec = (ts.tv_nsec); else (ip)->dinode_u
.ffs2_din->di_ctimensec = (ts.tv_nsec); } while (0)
;
134 ip->i_modrev++;
135 }
136
137 out:
138 ip->i_flag &= ~(IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004);
139}
140
141
142/*
143 * Create a regular file
144 */
145int
146ufs_create(void *v)
147{
148 struct vop_create_args *ap = v;
149 int error;
150
151 error =
152 ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode)(int)((vttoif_tab[(int)(ap->a_vap->va_type)]) | (ap->
a_vap->va_mode))
,
153 ap->a_dvp, ap->a_vpp, ap->a_cnp);
154 if (error == 0)
155 VN_KNOTE(ap->a_dvp, NOTE_WRITE)do { struct klist *__list = (&ap->a_dvp->v_selectinfo
.si_note); if (__list != ((void *)0)) knote(__list, (0x0002))
; } while (0)
;
156 return (error);
157}
158
159/*
160 * Mknod vnode call
161 */
162int
163ufs_mknod(void *v)
164{
165 struct vop_mknod_args *ap = v;
166 struct vattr *vap = ap->a_vap;
167 struct vnode **vpp = ap->a_vpp;
168 struct inode *ip;
169 int error;
170
171 if ((error =
172 ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode)(int)((vttoif_tab[(int)(vap->va_type)]) | (vap->va_mode
))
,
173 ap->a_dvp, vpp, ap->a_cnp)) != 0)
174 return (error);
175 VN_KNOTE(ap->a_dvp, NOTE_WRITE)do { struct klist *__list = (&ap->a_dvp->v_selectinfo
.si_note); if (__list != ((void *)0)) knote(__list, (0x0002))
; } while (0)
;
176 ip = VTOI(*vpp)((struct inode *)(*vpp)->v_data);
177 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
178 if (vap->va_rdev != VNOVAL(-1)) {
179 /*
180 * Want to be able to use this to make badblock
181 * inodes, so don't truncate the dev number.
182 */
183 DIP_ASSIGN(ip, rdev, vap->va_rdev)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_db[0] = (vap->va_rdev); else (ip)->dinode_u
.ffs2_din->di_db[0] = (vap->va_rdev); } while (0)
;
184 }
185 /*
186 * Remove inode so that it will be reloaded by VFS_VGET and
187 * checked to see if it is an alias of an existing entry in
188 * the inode cache.
189 */
190 vput(*vpp);
191 (*vpp)->v_type = VNON;
192 vgone(*vpp);
193 *vpp = NULL((void *)0);
194 return (0);
195}
196
197/*
198 * Open called.
199 *
200 * Nothing to do.
201 */
202int
203ufs_open(void *v)
204{
205 struct vop_open_args *ap = v;
206 struct inode *ip = VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data);
207
208 /*
209 * Files marked append-only must be opened for appending.
210 */
211 if ((DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& APPEND(0x00000004 | 0x00040000)) &&
212 (ap->a_mode & (FWRITE0x0002 | O_APPEND0x0008)) == FWRITE0x0002)
213 return (EPERM1);
214
215 if (ap->a_mode & O_TRUNC0x0400)
216 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
217
218 return (0);
219}
220
221/*
222 * Close called.
223 *
224 * Update the times on the inode.
225 */
226int
227ufs_close(void *v)
228{
229 struct vop_close_args *ap = v;
230 struct vnode *vp = ap->a_vp;
231
232 if (vp->v_usecount > 1)
233 ufs_itimes(vp);
234 return (0);
235}
236
237int
238ufs_access(void *v)
239{
240 struct vop_access_args *ap = v;
241 struct vnode *vp = ap->a_vp;
242 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
243 mode_t mode = ap->a_mode;
244
245 /*
246 * Disallow write attempts on read-only file systems;
247 * unless the file is a socket, fifo, or a block or
248 * character device resident on the file system.
249 */
250 if (mode & VWRITE00200) {
251 switch (vp->v_type) {
252 int error;
253 case VDIR:
254 case VLNK:
255 case VREG:
256 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
257 return (EROFS30);
258
259 if ((error = getinoquota(ip)) != 0)
260 return (error);
261 break;
262 case VBAD:
263 case VBLK:
264 case VCHR:
265 case VSOCK:
266 case VFIFO:
267 case VNON:
268 break;
269
270 }
271 }
272
273 /* If immutable bit set, nobody gets to write it. */
274 if ((mode & VWRITE00200) && (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& IMMUTABLE(0x00000002 | 0x00020000)))
275 return (EPERM1);
276
277 if (vnoperm(vp)) {
278 /* For VEXEC, at least one of the execute bits must be set. */
279 if ((mode & VEXEC00100) && vp->v_type != VDIR &&
280 (DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
& (S_IXUSR0000100|S_IXGRP0000010|S_IXOTH0000001)) == 0)
281 return EACCES13;
282 return 0;
283 }
284
285 return (vaccess(vp->v_type, DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
, DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
, DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
,
286 mode, ap->a_cred));
287}
288
289int
290ufs_getattr(void *v)
291{
292 struct vop_getattr_args *ap = v;
293 struct vnode *vp = ap->a_vp;
294 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
295 struct vattr *vap = ap->a_vap;
296
297 ufs_itimes(vp);
298
299 /*
300 * Copy from inode table
301 */
302 vap->va_fsid = ip->i_dev;
303 vap->va_fileid = ip->i_number;
304 vap->va_mode = DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
& ~IFMT0170000;
305 vap->va_nlink = ip->i_effnlink;
306 vap->va_uid = DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
;
307 vap->va_gid = DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
;
308 vap->va_rdev = (dev_t) DIP(ip, rdev)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_db[0] : (ip)->dinode_u.ffs2_din->di_db[0])
;
309 vap->va_size = DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
;
310 vap->va_atime.tv_sec = DIP(ip, atime)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_atime : (ip)->dinode_u.ffs2_din->di_atime)
;
311 vap->va_atime.tv_nsec = DIP(ip, atimensec)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_atimensec : (ip)->dinode_u.ffs2_din->di_atimensec
)
;
312 vap->va_mtime.tv_sec = DIP(ip, mtime)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mtime : (ip)->dinode_u.ffs2_din->di_mtime)
;
313 vap->va_mtime.tv_nsec = DIP(ip, mtimensec)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mtimensec : (ip)->dinode_u.ffs2_din->di_mtimensec
)
;
314 vap->va_ctime.tv_sec = DIP(ip, ctime)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_ctime : (ip)->dinode_u.ffs2_din->di_ctime)
;
315 vap->va_ctime.tv_nsec = DIP(ip, ctimensec)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_ctimensec : (ip)->dinode_u.ffs2_din->di_ctimensec
)
;
316 vap->va_flags = DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
;
317 vap->va_gen = DIP(ip, gen)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gen : (ip)->dinode_u.ffs2_din->di_gen)
;
318 /* this doesn't belong here */
319 if (vp->v_type == VBLK)
320 vap->va_blocksize = BLKDEV_IOSIZE(1 << 12);
321 else if (vp->v_type == VCHR)
322 vap->va_blocksize = MAXBSIZE(64 * 1024);
323 else
324 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
325 vap->va_bytes = dbtob((u_quad_t) DIP(ip, blocks))(((u_quad_t) (((ip)->i_ump->um_fstype == 1) ? (ip)->
dinode_u.ffs1_din->di_blocks : (ip)->dinode_u.ffs2_din->
di_blocks)) << 9)
;
326 vap->va_type = vp->v_type;
327 vap->va_filerev = ip->i_modrev;
328 return (0);
329}
330
331/*
332 * Set attribute vnode op. called from several syscalls
333 */
334int
335ufs_setattr(void *v)
336{
337 struct vop_setattr_args *ap = v;
338 struct vattr *vap = ap->a_vap;
339 struct vnode *vp = ap->a_vp;
340 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
341 struct ucred *cred = ap->a_cred;
342 int error;
343 long hint = NOTE_ATTRIB0x0008;
344 u_quad_t oldsize;
345
346 /*
347 * Check for unsettable attributes.
348 */
349 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL(-1)) ||
350 (vap->va_fsid != VNOVAL(-1)) || (vap->va_fileid != VNOVAL(-1)) ||
351 (vap->va_blocksize != VNOVAL(-1)) || (vap->va_rdev != VNOVAL(-1)) ||
352 ((int)vap->va_bytes != VNOVAL(-1)) || (vap->va_gen != VNOVAL(-1))) {
353 return (EINVAL22);
354 }
355 if (vap->va_flags != VNOVAL(-1)) {
356 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
357 return (EROFS30);
358 if (cred->cr_uid != DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
&&
359 !vnoperm(vp) &&
360 (error = suser_ucred(cred)))
361 return (error);
362 if (cred->cr_uid == 0 || vnoperm(vp)) {
363 if ((DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (SF_IMMUTABLE0x00020000 | SF_APPEND0x00040000)) &&
364 securelevel > 0)
365 return (EPERM1);
366 DIP_ASSIGN(ip, flags, vap->va_flags)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_flags = (vap->va_flags); else (ip)->dinode_u
.ffs2_din->di_flags = (vap->va_flags); } while (0)
;
367 } else {
368 if (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (SF_IMMUTABLE0x00020000 | SF_APPEND0x00040000) ||
369 (vap->va_flags & UF_SETTABLE0x0000ffff) != vap->va_flags)
370 return (EPERM1);
371 DIP_AND(ip, flags, SF_SETTABLE)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_flags &= (0xffff0000); else (ip)->dinode_u
.ffs2_din->di_flags &= (0xffff0000); } while (0)
;
372 DIP_OR(ip, flags, vap->va_flags & UF_SETTABLE)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_flags |= (vap->va_flags & 0x0000ffff)
; else (ip)->dinode_u.ffs2_din->di_flags |= (vap->va_flags
& 0x0000ffff); } while (0)
;
373 }
374 ip->i_flag |= IN_CHANGE0x0002;
375 if (vap->va_flags & (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000)))
376 return (0);
377 }
378 if (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000)))
379 return (EPERM1);
380 /*
381 * Go through the fields and update if not VNOVAL.
382 */
383 if (vap->va_uid != (uid_t)VNOVAL(-1) || vap->va_gid != (gid_t)VNOVAL(-1)) {
384 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
385 return (EROFS30);
386 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred);
387 if (error)
388 return (error);
389 }
390 if (vap->va_size != VNOVAL(-1)) {
391 oldsize = DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
;
392 /*
393 * Disallow write attempts on read-only file systems;
394 * unless the file is a socket, fifo, or a block or
395 * character device resident on the file system.
396 */
397 switch (vp->v_type) {
398 case VDIR:
399 return (EISDIR21);
400 case VLNK:
401 case VREG:
402 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
403 return (EROFS30);
404 break;
405 default:
406 break;
407 }
408 if ((error = UFS_TRUNCATE(ip, vap->va_size, 0, cred)((ip)->i_vtbl->iv_truncate)((ip), (vap->va_size), (0
), (cred))
) != 0)
409 return (error);
410 if (vap->va_size < oldsize)
411 hint |= NOTE_TRUNCATE0x0080;
412 }
413 if ((vap->va_vaflags & VA_UTIMES_CHANGE0x04) ||
414 vap->va_atime.tv_nsec != VNOVAL(-1) ||
415 vap->va_mtime.tv_nsec != VNOVAL(-1)) {
416 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
417 return (EROFS30);
418 if (cred->cr_uid != DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
&&
419 !vnoperm(vp) &&
420 (error = suser_ucred(cred)) &&
421 ((vap->va_vaflags & VA_UTIMES_NULL0x01) == 0 ||
422 (error = VOP_ACCESS(vp, VWRITE00200, cred, ap->a_p))))
423 return (error);
424 if (vap->va_mtime.tv_nsec != VNOVAL(-1))
425 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
426 else if (vap->va_vaflags & VA_UTIMES_CHANGE0x04)
427 ip->i_flag |= IN_CHANGE0x0002;
428 if (vap->va_atime.tv_nsec != VNOVAL(-1)) {
429 if (!(vp->v_mount->mnt_flag & MNT_NOATIME0x00008000) ||
430 (ip->i_flag & (IN_CHANGE0x0002 | IN_UPDATE0x0004)))
431 ip->i_flag |= IN_ACCESS0x0001;
432 }
433 ufs_itimes(vp);
434 if (vap->va_mtime.tv_nsec != VNOVAL(-1)) {
435 DIP_ASSIGN(ip, mtime, vap->va_mtime.tv_sec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mtime = (vap->va_mtime.tv_sec); else (ip)
->dinode_u.ffs2_din->di_mtime = (vap->va_mtime.tv_sec
); } while (0)
;
436 DIP_ASSIGN(ip, mtimensec, vap->va_mtime.tv_nsec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mtimensec = (vap->va_mtime.tv_nsec); else
(ip)->dinode_u.ffs2_din->di_mtimensec = (vap->va_mtime
.tv_nsec); } while (0)
;
437 }
438 if (vap->va_atime.tv_nsec != VNOVAL(-1)) {
439 DIP_ASSIGN(ip, atime, vap->va_atime.tv_sec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_atime = (vap->va_atime.tv_sec); else (ip)
->dinode_u.ffs2_din->di_atime = (vap->va_atime.tv_sec
); } while (0)
;
440 DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_atimensec = (vap->va_atime.tv_nsec); else
(ip)->dinode_u.ffs2_din->di_atimensec = (vap->va_atime
.tv_nsec); } while (0)
;
441 }
442 error = UFS_UPDATE(ip, 0)((ip)->i_vtbl->iv_update)((ip), (0));
443 if (error)
444 return (error);
445 }
446 error = 0;
447 if (vap->va_mode != (mode_t)VNOVAL(-1)) {
448 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
449 return (EROFS30);
450 error = ufs_chmod(vp, (int)vap->va_mode, cred);
451 }
452 VN_KNOTE(vp, hint)do { struct klist *__list = (&vp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (hint)); } while (
0)
;
453 return (error);
454}
455
456/*
457 * Change the mode on a file.
458 * Inode must be locked before calling.
459 */
460int
461ufs_chmod(struct vnode *vp, int mode, struct ucred *cred)
462{
463 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
464 int error;
465
466 if (cred->cr_uid != DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
&&
467 !vnoperm(vp) &&
468 (error = suser_ucred(cred)))
469 return (error);
470 if (cred->cr_uid && !vnoperm(vp)) {
471 if (vp->v_type != VDIR && (mode & S_ISTXT0001000))
472 return (EFTYPE79);
473 if (!groupmember(DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
, cred) && (mode & ISGID0002000))
474 return (EPERM1);
475 }
476 DIP_AND(ip, mode, ~ALLPERMS)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode &= (~(0004000|0002000|0001000|0000700
|0000070|0000007)); else (ip)->dinode_u.ffs2_din->di_mode
&= (~(0004000|0002000|0001000|0000700|0000070|0000007));
} while (0)
;
477 DIP_OR(ip, mode, mode & ALLPERMS)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode |= (mode & (0004000|0002000|0001000
|0000700|0000070|0000007)); else (ip)->dinode_u.ffs2_din->
di_mode |= (mode & (0004000|0002000|0001000|0000700|0000070
|0000007)); } while (0)
;
478 ip->i_flag |= IN_CHANGE0x0002;
479 if ((vp->v_flag & VTEXT0x0002) && (DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
& S_ISTXT0001000) == 0)
480 (void) uvm_vnp_uncache(vp);
481 return (0);
482}
483
484/*
485 * Perform chown operation on inode ip;
486 * inode must be locked prior to call.
487 */
488int
489ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred)
490{
491 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
492 uid_t ouid;
493 gid_t ogid;
494 int error = 0;
495 daddr_t change;
496 enum ufs_quota_flags quota_flags = 0;
497
498 if (uid == (uid_t)VNOVAL(-1))
499 uid = DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
;
500 if (gid == (gid_t)VNOVAL(-1))
501 gid = DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
;
502 /*
503 * If we don't own the file, are trying to change the owner
504 * of the file, or are not a member of the target group,
505 * the caller must be superuser or the call fails.
506 */
507 if ((cred->cr_uid != DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
|| uid != DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
||
508 (gid != DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
&& !groupmember(gid, cred))) &&
509 !vnoperm(vp) &&
510 (error = suser_ucred(cred)))
511 return (error);
512 ogid = DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
;
513 ouid = DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
;
514 change = DIP(ip, blocks)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_blocks : (ip)->dinode_u.ffs2_din->di_blocks)
;
515
516 if (ouid == uid)
517 quota_flags |= UFS_QUOTA_NOUID;
518
519 if (ogid == gid)
520 quota_flags |= UFS_QUOTA_NOGID;
521
522 if ((error = getinoquota(ip)) != 0)
523 return (error);
524 (void) ufs_quota_free_blocks2(ip, change, cred, quota_flags);
525 (void) ufs_quota_free_inode2(ip, cred, quota_flags);
526 (void) ufs_quota_delete(ip);
527
528 DIP_ASSIGN(ip, gid, gid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_gid = (gid); else (ip)->dinode_u.ffs2_din
->di_gid = (gid); } while (0)
;
529 DIP_ASSIGN(ip, uid, uid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_uid = (uid); else (ip)->dinode_u.ffs2_din
->di_uid = (uid); } while (0)
;
530
531 if ((error = getinoquota(ip)) != 0)
532 goto error;
533
534 if ((error = ufs_quota_alloc_blocks2(ip, change, cred,
535 quota_flags)) != 0)
536 goto error;
537
538 if ((error = ufs_quota_alloc_inode2(ip, cred ,
539 quota_flags)) != 0) {
540 (void)ufs_quota_free_blocks2(ip, change, cred,
541 quota_flags);
542 goto error;
543 }
544
545 if (getinoquota(ip))
546 panic("chown: lost quota");
547
548 if (ouid != uid || ogid != gid)
549 ip->i_flag |= IN_CHANGE0x0002;
550 if (!vnoperm(vp)) {
551 if (ouid != uid && cred->cr_uid != 0)
552 DIP_AND(ip, mode, ~ISUID)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode &= (~0004000); else (ip)->dinode_u
.ffs2_din->di_mode &= (~0004000); } while (0)
;
553 if (ogid != gid && cred->cr_uid != 0)
554 DIP_AND(ip, mode, ~ISGID)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode &= (~0002000); else (ip)->dinode_u
.ffs2_din->di_mode &= (~0002000); } while (0)
;
555 }
556 return (0);
557
558error:
559 (void) ufs_quota_delete(ip);
560
561 DIP_ASSIGN(ip, gid, ogid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_gid = (ogid); else (ip)->dinode_u.ffs2_din
->di_gid = (ogid); } while (0)
;
562 DIP_ASSIGN(ip, uid, ouid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_uid = (ouid); else (ip)->dinode_u.ffs2_din
->di_uid = (ouid); } while (0)
;
563
564 if (getinoquota(ip) == 0) {
565 (void) ufs_quota_alloc_blocks2(ip, change, cred,
566 quota_flags | UFS_QUOTA_FORCE);
567 (void) ufs_quota_alloc_inode2(ip, cred,
568 quota_flags | UFS_QUOTA_FORCE);
569 (void) getinoquota(ip);
570 }
571 return (error);
572
573}
574
575/* ARGSUSED */
576int
577ufs_ioctl(void *v)
578{
579#if 0
580 struct vop_ioctl_args *ap = v;
581#endif
582 return (ENOTTY25);
583}
584
585int
586ufs_poll(void *v)
587{
588 struct vop_poll_args *ap = v;
589
590 /*
591 * We should really check to see if I/O is possible.
592 */
593 return (ap->a_events & (POLLIN0x0001 | POLLOUT0x0004 | POLLRDNORM0x0040 | POLLWRNORM0x0004));
594}
595
596int
597ufs_remove(void *v)
598{
599 struct vop_remove_args *ap = v;
600 struct inode *ip;
601 struct vnode *vp = ap->a_vp;
602 struct vnode *dvp = ap->a_dvp;
603 int error;
604
605 ip = VTOI(vp)((struct inode *)(vp)->v_data);
606 if (vp->v_type == VDIR || (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000))) ||
607 (DIP(VTOI(dvp), flags)(((((struct inode *)(dvp)->v_data))->i_ump->um_fstype
== 1) ? (((struct inode *)(dvp)->v_data))->dinode_u.ffs1_din
->di_flags : (((struct inode *)(dvp)->v_data))->dinode_u
.ffs2_din->di_flags)
& APPEND(0x00000004 | 0x00040000))) {
608 error = EPERM1;
609 goto out;
610 }
611 error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
612 VN_KNOTE(vp, NOTE_DELETE)do { struct klist *__list = (&vp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0001)); } while
(0)
;
613 VN_KNOTE(dvp, NOTE_WRITE)do { struct klist *__list = (&dvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002)); } while
(0)
;
614 out:
615 if (dvp == vp)
616 vrele(vp);
617 else
618 vput(vp);
619 vput(dvp);
620 return (error);
621}
622
623/*
624 * link vnode call
625 */
626int
627ufs_link(void *v)
628{
629 struct vop_link_args *ap = v;
630 struct vnode *dvp = ap->a_dvp;
631 struct vnode *vp = ap->a_vp;
632 struct componentname *cnp = ap->a_cnp;
633 struct inode *ip;
634 struct direct newdir;
635 int error;
636
637#ifdef DIAGNOSTIC1
638 if ((cnp->cn_flags & HASBUF0x000400) == 0)
639 panic("ufs_link: no name");
640#endif
641 if (vp->v_type == VDIR) {
642 VOP_ABORTOP(dvp, cnp);
643 error = EPERM1;
644 goto out2;
645 }
646 if (dvp->v_mount != vp->v_mount) {
647 VOP_ABORTOP(dvp, cnp);
648 error = EXDEV18;
649 goto out2;
650 }
651 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE0x0001UL))) {
652 VOP_ABORTOP(dvp, cnp);
653 goto out2;
654 }
655 ip = VTOI(vp)((struct inode *)(vp)->v_data);
656 if ((nlink_t) DIP(ip, nlink)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_nlink : (ip)->dinode_u.ffs2_din->di_nlink)
>= LINK_MAX32767) {
657 VOP_ABORTOP(dvp, cnp);
658 error = EMLINK31;
659 goto out1;
660 }
661 if (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000))) {
662 VOP_ABORTOP(dvp, cnp);
663 error = EPERM1;
664 goto out1;
665 }
666 ip->i_effnlink++;
667 DIP_ADD(ip, nlink, 1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink += (1); else (ip)->dinode_u.ffs2_din
->di_nlink += (1); } while (0)
;
668 ip->i_flag |= IN_CHANGE0x0002;
669 if (DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000))
670 softdep_change_linkcnt(ip, 0);
671 if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(vp))((ip)->i_vtbl->iv_update)((ip), (!((vp)->v_mount->
mnt_flag & 0x04000000)))
) == 0) {
672 ufs_makedirentry(ip, cnp, &newdir);
673 error = ufs_direnter(dvp, vp, &newdir, cnp, NULL((void *)0));
674 }
675 if (error) {
676 ip->i_effnlink--;
677 DIP_ADD(ip, nlink, -1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink += (-1); else (ip)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
678 ip->i_flag |= IN_CHANGE0x0002;
679 if (DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000))
680 softdep_change_linkcnt(ip, 0);
681 }
682 pool_put(&namei_pool, cnp->cn_pnbuf);
683 VN_KNOTE(vp, NOTE_LINK)do { struct klist *__list = (&vp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0010)); } while
(0)
;
684 VN_KNOTE(dvp, NOTE_WRITE)do { struct klist *__list = (&dvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002)); } while
(0)
;
685out1:
686 if (dvp != vp)
687 VOP_UNLOCK(vp);
688out2:
689 vput(dvp);
690 return (error);
691}
692
693/*
694 * Rename system call.
695 * rename("foo", "bar");
696 * is essentially
697 * unlink("bar");
698 * link("foo", "bar");
699 * unlink("foo");
700 * but ``atomically''. Can't do full commit without saving state in the
701 * inode on disk which isn't feasible at this time. Best we can do is
702 * always guarantee the target exists.
703 *
704 * Basic algorithm is:
705 *
706 * 1) Bump link count on source while we're linking it to the
707 * target. This also ensure the inode won't be deleted out
708 * from underneath us while we work (it may be truncated by
709 * a concurrent `trunc' or `open' for creation).
710 * 2) Link source to destination. If destination already exists,
711 * delete it first.
712 * 3) Unlink source reference to inode if still around. If a
713 * directory was moved and the parent of the destination
714 * is different from the source, patch the ".." entry in the
715 * directory.
716 */
717int
718ufs_rename(void *v)
719{
720 struct vop_rename_args *ap = v;
721 struct vnode *tvp = ap->a_tvp;
722 struct vnode *tdvp = ap->a_tdvp;
723 struct vnode *fvp = ap->a_fvp;
724 struct vnode *fdvp = ap->a_fdvp;
725 struct componentname *tcnp = ap->a_tcnp;
726 struct componentname *fcnp = ap->a_fcnp;
727 struct inode *ip, *xp, *dp;
728 struct direct newdir;
729 int doingdirectory = 0, oldparent = 0, newparent = 0;
730 int error = 0;
731
732#ifdef DIAGNOSTIC1
733 if ((tcnp->cn_flags & HASBUF0x000400) == 0 ||
734 (fcnp->cn_flags & HASBUF0x000400) == 0)
735 panic("ufs_rename: no name");
736#endif
737 /*
738 * Check for cross-device rename.
739 */
740 if ((fvp->v_mount != tdvp->v_mount) ||
741 (tvp && (fvp->v_mount != tvp->v_mount))) {
742 error = EXDEV18;
743abortit:
744 VOP_ABORTOP(tdvp, tcnp);
745 if (tdvp == tvp)
746 vrele(tdvp);
747 else
748 vput(tdvp);
749 if (tvp)
750 vput(tvp);
751 VOP_ABORTOP(fdvp, fcnp);
752 vrele(fdvp);
753 vrele(fvp);
754 return (error);
755 }
756
757 if (tvp && ((DIP(VTOI(tvp), flags)(((((struct inode *)(tvp)->v_data))->i_ump->um_fstype
== 1) ? (((struct inode *)(tvp)->v_data))->dinode_u.ffs1_din
->di_flags : (((struct inode *)(tvp)->v_data))->dinode_u
.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000))) ||
758 (DIP(VTOI(tdvp), flags)(((((struct inode *)(tdvp)->v_data))->i_ump->um_fstype
== 1) ? (((struct inode *)(tdvp)->v_data))->dinode_u.ffs1_din
->di_flags : (((struct inode *)(tdvp)->v_data))->dinode_u
.ffs2_din->di_flags)
& APPEND(0x00000004 | 0x00040000)))) {
759 error = EPERM1;
760 goto abortit;
761 }
762
763 /*
764 * Check if just deleting a link name or if we've lost a race.
765 * If another process completes the same rename after we've looked
766 * up the source and have blocked looking up the target, then the
767 * source and target inodes may be identical now although the
768 * names were never linked.
769 */
770 if (fvp == tvp) {
771 if (fvp->v_type == VDIR) {
772 /*
773 * Linked directories are impossible, so we must
774 * have lost the race. Pretend that the rename
775 * completed before the lookup.
776 */
777 error = ENOENT2;
778 goto abortit;
779 }
780
781 /* Release destination completely. */
782 VOP_ABORTOP(tdvp, tcnp);
783 vput(tdvp);
784 vput(tvp);
785
786 /*
787 * Delete source. There is another race now that everything
788 * is unlocked, but this doesn't cause any new complications.
789 * relookup() may find a file that is unrelated to the
790 * original one, or it may fail. Too bad.
791 */
792 vrele(fvp);
793 fcnp->cn_flags &= ~MODMASK0x00fc;
794 fcnp->cn_flags |= LOCKPARENT0x0008 | LOCKLEAF0x0004;
795 if ((fcnp->cn_flags & SAVESTART0x001000) == 0)
796 panic("ufs_rename: lost from startdir");
797 fcnp->cn_nameiop = DELETE2;
798 if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0)
799 return (error); /* relookup did vrele() */
800 vrele(fdvp);
801 return (VOP_REMOVE(fdvp, fvp, fcnp));
802 }
803
804 if ((error = vn_lock(fvp, LK_EXCLUSIVE0x0001UL)) != 0)
805 goto abortit;
806
807 /* fvp, tdvp, tvp now locked */
808 dp = VTOI(fdvp)((struct inode *)(fdvp)->v_data);
809 ip = VTOI(fvp)((struct inode *)(fvp)->v_data);
810 if ((nlink_t) DIP(ip, nlink)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_nlink : (ip)->dinode_u.ffs2_din->di_nlink)
>= LINK_MAX32767) {
811 VOP_UNLOCK(fvp);
812 error = EMLINK31;
813 goto abortit;
814 }
815 if ((DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000))) ||
816 (DIP(dp, flags)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_flags : (dp)->dinode_u.ffs2_din->di_flags)
& APPEND(0x00000004 | 0x00040000))) {
817 VOP_UNLOCK(fvp);
818 error = EPERM1;
819 goto abortit;
820 }
821 if ((DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
& IFMT0170000) == IFDIR0040000) {
822 error = VOP_ACCESS(fvp, VWRITE00200, tcnp->cn_cred, tcnp->cn_proc);
823 if (!error && tvp)
824 error = VOP_ACCESS(tvp, VWRITE00200, tcnp->cn_cred, tcnp->cn_proc);
825 if (error) {
826 VOP_UNLOCK(fvp);
827 error = EACCES13;
828 goto abortit;
829 }
830 /*
831 * Avoid ".", "..", and aliases of "." for obvious reasons.
832 */
833 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
834 dp == ip ||
835 (fcnp->cn_flags & ISDOTDOT0x002000) ||
836 (tcnp->cn_flags & ISDOTDOT0x002000) ||
837 (ip->i_flag & IN_RENAME0x0010)) {
838 VOP_UNLOCK(fvp);
839 error = EINVAL22;
840 goto abortit;
841 }
842 ip->i_flag |= IN_RENAME0x0010;
843 oldparent = dp->i_number;
844 doingdirectory = 1;
845 }
846 VN_KNOTE(fdvp, NOTE_WRITE)do { struct klist *__list = (&fdvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002)); } while
(0)
; /* XXX right place? */
847
848 /*
849 * When the target exists, both the directory
850 * and target vnodes are returned locked.
851 */
852 dp = VTOI(tdvp)((struct inode *)(tdvp)->v_data);
853 xp = NULL((void *)0);
854 if (tvp)
855 xp = VTOI(tvp)((struct inode *)(tvp)->v_data);
856
857 /*
858 * 1) Bump link count while we're moving stuff
859 * around. If we crash somewhere before
860 * completing our work, the link count
861 * may be wrong, but correctable.
862 */
863 ip->i_effnlink++;
864 DIP_ADD(ip, nlink, 1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink += (1); else (ip)->dinode_u.ffs2_din
->di_nlink += (1); } while (0)
;
865 ip->i_flag |= IN_CHANGE0x0002;
866 if (DOINGSOFTDEP(fvp)((fvp)->v_mount->mnt_flag & 0x04000000))
867 softdep_change_linkcnt(ip, 0);
868 if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(fvp))((ip)->i_vtbl->iv_update)((ip), (!((fvp)->v_mount->
mnt_flag & 0x04000000)))
) != 0) {
869 VOP_UNLOCK(fvp);
870 goto bad;
871 }
872
873 /*
874 * If ".." must be changed (ie the directory gets a new
875 * parent) then the source directory must not be in the
876 * directory hierarchy above the target, as this would
877 * orphan everything below the source directory. Also
878 * the user must have write permission in the source so
879 * as to be able to change "..". We must repeat the call
880 * to namei, as the parent directory is unlocked by the
881 * call to checkpath().
882 */
883 error = VOP_ACCESS(fvp, VWRITE00200, tcnp->cn_cred, tcnp->cn_proc);
884 VOP_UNLOCK(fvp);
885
886 /* tdvp and tvp locked */
887 if (oldparent != dp->i_number)
888 newparent = dp->i_number;
889 if (doingdirectory && newparent) {
890 if (error) /* write access check above */
891 goto bad;
892 if (xp != NULL((void *)0))
893 vput(tvp);
894 /*
895 * Compensate for the reference ufs_checkpath() loses.
896 */
897 vref(tdvp);
898 /* Only tdvp is locked */
899 if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) {
900 vrele(tdvp);
901 goto out;
902 }
903 if ((tcnp->cn_flags & SAVESTART0x001000) == 0)
904 panic("ufs_rename: lost to startdir");
905 if ((error = vfs_relookup(tdvp, &tvp, tcnp)) != 0)
906 goto out;
907 vrele(tdvp); /* relookup() acquired a reference */
908 dp = VTOI(tdvp)((struct inode *)(tdvp)->v_data);
909 xp = NULL((void *)0);
910 if (tvp)
911 xp = VTOI(tvp)((struct inode *)(tvp)->v_data);
912 }
913 /*
914 * 2) If target doesn't exist, link the target
915 * to the source and unlink the source.
916 * Otherwise, rewrite the target directory
917 * entry to reference the source inode and
918 * expunge the original entry's existence.
919 */
920 if (xp == NULL((void *)0)) {
921 if (dp->i_dev != ip->i_dev)
922 panic("rename: EXDEV");
923 /*
924 * Account for ".." in new directory.
925 * When source and destination have the same
926 * parent we don't fool with the link count.
927 */
928 if (doingdirectory && newparent) {
929 if ((nlink_t) DIP(dp, nlink)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_nlink : (dp)->dinode_u.ffs2_din->di_nlink)
>= LINK_MAX32767) {
930 error = EMLINK31;
931 goto bad;
932 }
933 dp->i_effnlink++;
934 DIP_ADD(dp, nlink, 1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (1); else (dp)->dinode_u.ffs2_din
->di_nlink += (1); } while (0)
;
935 dp->i_flag |= IN_CHANGE0x0002;
936 if (DOINGSOFTDEP(tdvp)((tdvp)->v_mount->mnt_flag & 0x04000000))
937 softdep_change_linkcnt(dp, 0);
938 if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(tdvp))((dp)->i_vtbl->iv_update)((dp), (!((tdvp)->v_mount->
mnt_flag & 0x04000000)))
)
939 != 0) {
940 dp->i_effnlink--;
941 DIP_ADD(dp, nlink, -1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (-1); else (dp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
942 dp->i_flag |= IN_CHANGE0x0002;
943 if (DOINGSOFTDEP(tdvp)((tdvp)->v_mount->mnt_flag & 0x04000000))
944 softdep_change_linkcnt(dp, 0);
945 goto bad;
946 }
947 }
948 ufs_makedirentry(ip, tcnp, &newdir);
949 if ((error = ufs_direnter(tdvp, NULL((void *)0), &newdir, tcnp, NULL((void *)0))) != 0) {
950 if (doingdirectory && newparent) {
951 dp->i_effnlink--;
952 DIP_ADD(dp, nlink, -1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (-1); else (dp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
953 dp->i_flag |= IN_CHANGE0x0002;
954 if (DOINGSOFTDEP(tdvp)((tdvp)->v_mount->mnt_flag & 0x04000000))
955 softdep_change_linkcnt(dp, 0);
956 (void)UFS_UPDATE(dp, 1)((dp)->i_vtbl->iv_update)((dp), (1));
957 }
958 goto bad;
959 }
960 VN_KNOTE(tdvp, NOTE_WRITE)do { struct klist *__list = (&tdvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002)); } while
(0)
;
961 vput(tdvp);
962 } else {
963 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
964 panic("rename: EXDEV");
965 /*
966 * Short circuit rename(foo, foo).
967 */
968 if (xp->i_number == ip->i_number)
969 panic("ufs_rename: same file");
970 /*
971 * If the parent directory is "sticky", then the user must
972 * own the parent directory, or the destination of the rename,
973 * otherwise the destination may not be changed (except by
974 * root). This implements append-only directories.
975 */
976 if ((DIP(dp, mode)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_mode : (dp)->dinode_u.ffs2_din->di_mode)
& S_ISTXT0001000) && tcnp->cn_cred->cr_uid != 0 &&
977 tcnp->cn_cred->cr_uid != DIP(dp, uid)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_uid : (dp)->dinode_u.ffs2_din->di_uid)
&&
978 DIP(xp, uid )(((xp)->i_ump->um_fstype == 1) ? (xp)->dinode_u.ffs1_din
->di_uid : (xp)->dinode_u.ffs2_din->di_uid)
!= tcnp->cn_cred->cr_uid &&
979 !vnoperm(tdvp)) {
980 error = EPERM1;
981 goto bad;
982 }
983 /*
984 * Target must be empty if a directory and have no links
985 * to it. Also, ensure source and target are compatible
986 * (both directories, or both not directories).
987 */
988 if ((DIP(xp, mode)(((xp)->i_ump->um_fstype == 1) ? (xp)->dinode_u.ffs1_din
->di_mode : (xp)->dinode_u.ffs2_din->di_mode)
& IFMT0170000) == IFDIR0040000) {
989 if (xp->i_effnlink > 2 ||
990 !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
991 error = ENOTEMPTY66;
992 goto bad;
993 }
994 if (!doingdirectory) {
995 error = ENOTDIR20;
996 goto bad;
997 }
998 cache_purge(tdvp);
999 } else if (doingdirectory) {
1000 error = EISDIR21;
1001 goto bad;
1002 }
1003
1004 if ((error = ufs_dirrewrite(dp, xp, ip->i_number,
1005 IFTODT(DIP(ip, mode))((((((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)) &
0170000) >> 12)
, (doingdirectory && newparent) ?
1006 newparent : doingdirectory)) != 0)
1007 goto bad;
1008 if (doingdirectory) {
1009 if (!newparent) {
1010 dp->i_effnlink--;
1011 if (DOINGSOFTDEP(tdvp)((tdvp)->v_mount->mnt_flag & 0x04000000))
1012 softdep_change_linkcnt(dp, 0);
1013 }
1014 xp->i_effnlink--;
1015 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000))
1016 softdep_change_linkcnt(xp, 0);
1017 }
1018 if (doingdirectory && !DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000)) {
1019 /*
1020 * Truncate inode. The only stuff left in the directory
1021 * is "." and "..". The "." reference is inconsequential
1022 * since we are quashing it. We have removed the "."
1023 * reference and the reference in the parent directory,
1024 * but there may be other hard links. The soft
1025 * dependency code will arrange to do these operations
1026 * after the parent directory entry has been deleted on
1027 * disk, so when running with that code we avoid doing
1028 * them now.
1029 */
1030 if (!newparent) {
1031 DIP_ADD(dp, nlink, -1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (-1); else (dp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1032 dp->i_flag |= IN_CHANGE0x0002;
1033 }
1034
1035 DIP_ADD(xp, nlink, -1)do { if ((xp)->i_ump->um_fstype == 1) (xp)->dinode_u
.ffs1_din->di_nlink += (-1); else (xp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1036 xp->i_flag |= IN_CHANGE0x0002;
1037 if ((error = UFS_TRUNCATE(VTOI(tvp), (off_t)0, IO_SYNC,((((struct inode *)(tvp)->v_data))->i_vtbl->iv_truncate
)((((struct inode *)(tvp)->v_data)), ((off_t)0), (0x04), (
tcnp->cn_cred))
1038 tcnp->cn_cred)((((struct inode *)(tvp)->v_data))->i_vtbl->iv_truncate
)((((struct inode *)(tvp)->v_data)), ((off_t)0), (0x04), (
tcnp->cn_cred))
) != 0)
1039 goto bad;
1040 }
1041 VN_KNOTE(tdvp, NOTE_WRITE)do { struct klist *__list = (&tdvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002)); } while
(0)
;
1042 vput(tdvp);
1043 VN_KNOTE(tvp, NOTE_DELETE)do { struct klist *__list = (&tvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0001)); } while
(0)
;
1044 vput(tvp);
1045 xp = NULL((void *)0);
1046 }
1047
1048 /*
1049 * 3) Unlink the source.
1050 */
1051 fcnp->cn_flags &= ~MODMASK0x00fc;
1052 fcnp->cn_flags |= LOCKPARENT0x0008 | LOCKLEAF0x0004;
1053 if ((fcnp->cn_flags & SAVESTART0x001000) == 0)
1054 panic("ufs_rename: lost from startdir");
1055 if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0) {
1056 vrele(ap->a_fvp);
1057 return (error);
1058 }
1059 vrele(fdvp);
1060 if (fvp == NULL((void *)0)) {
1061 /*
1062 * From name has disappeared.
1063 */
1064 if (doingdirectory)
1065 panic("ufs_rename: lost dir entry");
1066 vrele(ap->a_fvp);
1067 return (0);
1068 }
1069
1070 xp = VTOI(fvp)((struct inode *)(fvp)->v_data);
1071 dp = VTOI(fdvp)((struct inode *)(fdvp)->v_data);
1072
1073 /*
1074 * Ensure that the directory entry still exists and has not
1075 * changed while the new name has been entered. If the source is
1076 * a file then the entry may have been unlinked or renamed. In
1077 * either case there is no further work to be done. If the source
1078 * is a directory then it cannot have been rmdir'ed; the IN_RENAME
1079 * flag ensures that it cannot be moved by another rename or removed
1080 * by a rmdir.
1081 */
1082 if (xp != ip) {
1083 if (doingdirectory)
1084 panic("ufs_rename: lost dir entry");
1085 } else {
1086 /*
1087 * If the source is a directory with a
1088 * new parent, the link count of the old
1089 * parent directory must be decremented
1090 * and ".." set to point to the new parent.
1091 */
1092 if (doingdirectory && newparent) {
1093 xp->i_offset = mastertemplate.dot_reclen;
1094 ufs_dirrewrite(xp, dp, newparent, DT_DIR4, 0);
1095 cache_purge(fdvp);
1096 }
1097 error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1098 xp->i_flag &= ~IN_RENAME0x0010;
1099 }
1100 VN_KNOTE(fvp, NOTE_RENAME)do { struct klist *__list = (&fvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0020)); } while
(0)
;
1101 if (dp)
1102 vput(fdvp);
1103 if (xp)
1104 vput(fvp);
1105 vrele(ap->a_fvp);
1106 return (error);
1107
1108bad:
1109 if (xp)
1110 vput(ITOV(xp)((xp)->i_vnode));
1111 vput(ITOV(dp)((dp)->i_vnode));
1112out:
1113 vrele(fdvp);
1114 if (doingdirectory)
1115 ip->i_flag &= ~IN_RENAME0x0010;
1116 if (vn_lock(fvp, LK_EXCLUSIVE0x0001UL) == 0) {
1117 ip->i_effnlink--;
1118 DIP_ADD(ip, nlink, -1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink += (-1); else (ip)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1119 ip->i_flag |= IN_CHANGE0x0002;
1120 ip->i_flag &= ~IN_RENAME0x0010;
1121 if (DOINGSOFTDEP(fvp)((fvp)->v_mount->mnt_flag & 0x04000000))
1122 softdep_change_linkcnt(ip, 0);
1123 vput(fvp);
1124 } else
1125 vrele(fvp);
1126 return (error);
1127}
1128
1129/*
1130 * Mkdir system call
1131 */
1132int
1133ufs_mkdir(void *v)
1134{
1135 struct vop_mkdir_args *ap = v;
1136 struct vnode *dvp = ap->a_dvp;
1137 struct vattr *vap = ap->a_vap;
1138 struct componentname *cnp = ap->a_cnp;
1139 struct inode *ip, *dp;
1140 struct vnode *tvp;
1141 struct buf *bp;
1142 struct direct newdir;
1143 struct dirtemplate dirtemplate, *dtp;
1144 int error, dmode, blkoff;
1145
1146#ifdef DIAGNOSTIC1
1147 if ((cnp->cn_flags & HASBUF0x000400) == 0)
1148 panic("ufs_mkdir: no name");
1149#endif
1150 dp = VTOI(dvp)((struct inode *)(dvp)->v_data);
1151 if ((nlink_t) DIP(dp, nlink)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_nlink : (dp)->dinode_u.ffs2_din->di_nlink)
>= LINK_MAX32767) {
1152 error = EMLINK31;
1153 goto out;
1154 }
1155 dmode = vap->va_mode & 0777;
1156 dmode |= IFDIR0040000;
1157 /*
1158 * Must simulate part of ufs_makeinode here to acquire the inode,
1159 * but not have it entered in the parent directory. The entry is
1160 * made later after writing "." and ".." entries.
1161 */
1162 if ((error = UFS_INODE_ALLOC(dp, dmode, cnp->cn_cred, &tvp)((dp)->i_vtbl->iv_inode_alloc)((dp), (dmode), (cnp->
cn_cred), (&tvp))
) != 0)
1163 goto out;
1164
1165 ip = VTOI(tvp)((struct inode *)(tvp)->v_data);
1166
1167 DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_uid = (cnp->cn_cred->cr_uid); else (ip
)->dinode_u.ffs2_din->di_uid = (cnp->cn_cred->cr_uid
); } while (0)
;
1168 DIP_ASSIGN(ip, gid, DIP(dp, gid))do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_gid = ((((dp)->i_ump->um_fstype == 1) ?
(dp)->dinode_u.ffs1_din->di_gid : (dp)->dinode_u.ffs2_din
->di_gid)); else (ip)->dinode_u.ffs2_din->di_gid = (
(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_gid : (dp)->dinode_u.ffs2_din->di_gid)); } while
(0)
;
1169
1170 if ((error = getinoquota(ip)) ||
1171 (error = ufs_quota_alloc_inode(ip, cnp->cn_cred)ufs_quota_alloc_inode2(ip, cnp->cn_cred, 0))) {
1172 pool_put(&namei_pool, cnp->cn_pnbuf);
1173 UFS_INODE_FREE(ip, ip->i_number, dmode)((ip)->i_vtbl->iv_inode_free)((ip), (ip->i_number), (
dmode))
;
1174 vput(tvp);
1175 vput(dvp);
1176 return (error);
1177 }
1178
1179 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
1180 DIP_ASSIGN(ip, mode, dmode)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode = (dmode); else (ip)->dinode_u.ffs2_din
->di_mode = (dmode); } while (0)
;
1181 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1182 ip->i_effnlink = 2;
1183 DIP_ASSIGN(ip, nlink, 2)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink = (2); else (ip)->dinode_u.ffs2_din
->di_nlink = (2); } while (0)
;
1184 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000))
1185 softdep_change_linkcnt(ip, 0);
1186
1187 /*
1188 * Bump link count in parent directory to reflect work done below.
1189 * Should be done before reference is create so cleanup is
1190 * possible if we crash.
1191 */
1192 dp->i_effnlink++;
1193 DIP_ADD(dp, nlink, 1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (1); else (dp)->dinode_u.ffs2_din
->di_nlink += (1); } while (0)
;
1194 dp->i_flag |= IN_CHANGE0x0002;
1195 if (DOINGSOFTDEP(dvp)((dvp)->v_mount->mnt_flag & 0x04000000))
1196 softdep_change_linkcnt(dp, 0);
1197 if ((error = UFS_UPDATE(dp, !DOINGSOFTDEP(dvp))((dp)->i_vtbl->iv_update)((dp), (!((dvp)->v_mount->
mnt_flag & 0x04000000)))
) != 0)
1198 goto bad;
1199
1200 /*
1201 * Initialize directory with "." and ".." from static template.
1202 */
1203 if (dp->i_ump->um_maxsymlinklen > 0)
1204 dtp = &mastertemplate;
1205 else
1206 dtp = (struct dirtemplate *)&omastertemplate;
1207 dirtemplate = *dtp;
1208 dirtemplate.dot_ino = ip->i_number;
1209 dirtemplate.dotdot_ino = dp->i_number;
1210
1211 if ((error = UFS_BUF_ALLOC(ip, (off_t)0, DIRBLKSIZ, cnp->cn_cred,((ip)->i_vtbl->iv_buf_alloc)((ip), ((off_t)0), ((1 <<
9)), (cnp->cn_cred), (0x01), (&bp))
1212 B_CLRBUF, &bp)((ip)->i_vtbl->iv_buf_alloc)((ip), ((off_t)0), ((1 <<
9)), (cnp->cn_cred), (0x01), (&bp))
) != 0)
1213 goto bad;
1214 DIP_ASSIGN(ip, size, DIRBLKSIZ)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_size = ((1 << 9)); else (ip)->dinode_u
.ffs2_din->di_size = ((1 << 9)); } while (0)
;
1215 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
1216 uvm_vnp_setsize(tvp, DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
);
1217 memcpy(bp->b_data, &dirtemplate, sizeof(dirtemplate))__builtin_memcpy((bp->b_data), (&dirtemplate), (sizeof
(dirtemplate)))
;
1218 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000)) {
1219 /*
1220 * Ensure that the entire newly allocated block is a
1221 * valid directory so that future growth within the
1222 * block does not have to ensure that the block is
1223 * written before the inode
1224 */
1225 blkoff = DIRBLKSIZ(1 << 9);
1226 while (blkoff < bp->b_bcount) {
1227 ((struct direct *)
1228 (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ(1 << 9);
1229 blkoff += DIRBLKSIZ(1 << 9);
1230 }
1231 }
1232 if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))((ip)->i_vtbl->iv_update)((ip), (!((tvp)->v_mount->
mnt_flag & 0x04000000)))
) != 0) {
1233 (void)VOP_BWRITE(bp);
1234 goto bad;
1235 }
1236
1237 /*
1238 * Directory set up, now install its entry in the parent directory.
1239 *
1240 * If we are not doing soft dependencies, then we must write out the
1241 * buffer containing the new directory body before entering the new
1242 * name in the parent. If we are doing soft dependencies, then the
1243 * buffer containing the new directory body will be passed to and
1244 * released in the soft dependency code after the code has attached
1245 * an appropriate ordering dependency to the buffer which ensures that
1246 * the buffer is written before the new name is written in the parent.
1247 */
1248 if (!DOINGSOFTDEP(dvp)((dvp)->v_mount->mnt_flag & 0x04000000) && ((error = VOP_BWRITE(bp)) != 0))
1249 goto bad;
1250 ufs_makedirentry(ip, cnp, &newdir);
1251 error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
1252
1253bad:
1254 if (error == 0) {
1255 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK)do { struct klist *__list = (&dvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002 | 0x0010)
); } while (0)
;
1256 *ap->a_vpp = tvp;
1257 } else {
1258 dp->i_effnlink--;
1259 DIP_ADD(dp, nlink, -1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (-1); else (dp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1260 dp->i_flag |= IN_CHANGE0x0002;
1261 if (DOINGSOFTDEP(dvp)((dvp)->v_mount->mnt_flag & 0x04000000))
1262 softdep_change_linkcnt(dp, 0);
1263 /*
1264 * No need to do an explicit VOP_TRUNCATE here, vrele will
1265 * do this for us because we set the link count to 0.
1266 */
1267 ip->i_effnlink = 0;
1268 DIP_ASSIGN(ip, nlink, 0)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink = (0); else (ip)->dinode_u.ffs2_din
->di_nlink = (0); } while (0)
;
1269 ip->i_flag |= IN_CHANGE0x0002;
1270 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000))
1271 softdep_change_linkcnt(ip, 0);
1272 vput(tvp);
1273 }
1274out:
1275 pool_put(&namei_pool, cnp->cn_pnbuf);
1276 vput(dvp);
1277
1278 return (error);
1279}
1280
1281/*
1282 * Rmdir system call.
1283 */
1284int
1285ufs_rmdir(void *v)
1286{
1287 struct vop_rmdir_args *ap = v;
1288 struct vnode *vp = ap->a_vp;
1289 struct vnode *dvp = ap->a_dvp;
1290 struct componentname *cnp = ap->a_cnp;
1291 struct inode *ip, *dp;
1292 int error;
1293
1294 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1295 dp = VTOI(dvp)((struct inode *)(dvp)->v_data);
1296 /*
1297 * Do not remove a directory that is in the process of being renamed.
1298 * Verify the directory is empty (and valid). Rmdir ".." will not be
1299 * valid since ".." will contain a reference to the current directory
1300 * and thus be non-empty.
1301 */
1302 error = 0;
Value stored to 'error' is never read
1303 if (ip->i_flag & IN_RENAME0x0010) {
1304 error = EINVAL22;
1305 goto out;
1306 }
1307 if (ip->i_effnlink != 2 ||
1308 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1309 error = ENOTEMPTY66;
1310 goto out;
1311 }
1312 if ((DIP(dp, flags)(((dp)->i_ump->um_fstype == 1) ? (dp)->dinode_u.ffs1_din
->di_flags : (dp)->dinode_u.ffs2_din->di_flags)
& APPEND(0x00000004 | 0x00040000)) ||
1313 (DIP(ip, flags)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_flags : (ip)->dinode_u.ffs2_din->di_flags)
& (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000)))) {
1314 error = EPERM1;
1315 goto out;
1316 }
1317 /*
1318 * Delete reference to directory before purging
1319 * inode. If we crash in between, the directory
1320 * will be reattached to lost+found,
1321 */
1322 dp->i_effnlink--;
1323 ip->i_effnlink--;
1324 if (DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000)) {
1325 softdep_change_linkcnt(dp, 0);
1326 softdep_change_linkcnt(ip, 0);
1327 }
1328 if ((error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1)) != 0) {
1329 dp->i_effnlink++;
1330 ip->i_effnlink++;
1331 if (DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000)) {
1332 softdep_change_linkcnt(dp, 0);
1333 softdep_change_linkcnt(ip, 0);
1334 }
1335 goto out;
1336 }
1337
1338 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK)do { struct klist *__list = (&dvp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0002 | 0x0010)
); } while (0)
;
1339 cache_purge(dvp);
1340 /*
1341 * Truncate inode. The only stuff left in the directory is "." and
1342 * "..". The "." reference is inconsequential since we are quashing
1343 * it. The soft dependency code will arrange to do these operations
1344 * after the parent directory entry has been deleted on disk, so
1345 * when running with that code we avoid doing them now.
1346 */
1347 if (!DOINGSOFTDEP(vp)((vp)->v_mount->mnt_flag & 0x04000000)) {
1348 int ioflag;
1349
1350 DIP_ADD(dp, nlink, -1)do { if ((dp)->i_ump->um_fstype == 1) (dp)->dinode_u
.ffs1_din->di_nlink += (-1); else (dp)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1351 dp->i_flag |= IN_CHANGE0x0002;
1352 DIP_ADD(ip, nlink, -1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink += (-1); else (ip)->dinode_u.ffs2_din
->di_nlink += (-1); } while (0)
;
1353 ip->i_flag |= IN_CHANGE0x0002;
1354 ioflag = DOINGASYNC(vp)((vp)->v_mount->mnt_flag & 0x00000040) ? 0 : IO_SYNC0x04;
1355 error = UFS_TRUNCATE(ip, (off_t)0, ioflag, cnp->cn_cred)((ip)->i_vtbl->iv_truncate)((ip), ((off_t)0), (ioflag),
(cnp->cn_cred))
;
1356 }
1357 cache_purge(vp);
1358#ifdef UFS_DIRHASH1
1359 /* Kill any active hash; i_effnlink == 0, so it will not come back. */
1360 if (ip->i_dirhashinode_ext.dirhash != NULL((void *)0))
1361 ufsdirhash_free(ip);
1362#endif
1363
1364out:
1365 VN_KNOTE(vp, NOTE_DELETE)do { struct klist *__list = (&vp->v_selectinfo.si_note
); if (__list != ((void *)0)) knote(__list, (0x0001)); } while
(0)
;
1366 vput(dvp);
1367 vput(vp);
1368 return (error);
1369}
1370
1371/*
1372 * symlink -- make a symbolic link
1373 */
1374int
1375ufs_symlink(void *v)
1376{
1377 struct vop_symlink_args *ap = v;
1378 struct vnode *vp, **vpp = ap->a_vpp;
1379 struct inode *ip;
1380 int len, error;
1381
1382 error = ufs_makeinode(IFLNK0120000 | ap->a_vap->va_mode, ap->a_dvp,
1383 vpp, ap->a_cnp);
1384 if (error) {
1385 vput(ap->a_dvp);
1386 return (error);
1387 }
1388 VN_KNOTE(ap->a_dvp, NOTE_WRITE)do { struct klist *__list = (&ap->a_dvp->v_selectinfo
.si_note); if (__list != ((void *)0)) knote(__list, (0x0002))
; } while (0)
;
1389 vput(ap->a_dvp);
1390 vp = *vpp;
1391 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1392 len = strlen(ap->a_target);
1393 if (len < ip->i_ump->um_maxsymlinklen) {
1394 memcpy(SHORTLINK(ip), ap->a_target, len)__builtin_memcpy(((((ip)->i_ump->um_fstype == 1) ? (caddr_t
)(ip)->dinode_u.ffs1_din->di_db : (caddr_t)(ip)->dinode_u
.ffs2_din->di_db)), (ap->a_target), (len))
;
1395 DIP_ASSIGN(ip, size, len)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_size = (len); else (ip)->dinode_u.ffs2_din
->di_size = (len); } while (0)
;
1396 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
1397 } else
1398 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1399 UIO_SYSSPACE, IO_NODELOCKED0x08, ap->a_cnp->cn_cred, NULL((void *)0),
1400 curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
);
1401 vput(vp);
1402 return (error);
1403}
1404
1405/*
1406 * Vnode op for reading directories.
1407 *
1408 * This routine converts the on-disk struct direct entries to the
1409 * struct dirent entries expected by userland and the rest of the kernel.
1410 */
1411int
1412ufs_readdir(void *v)
1413{
1414 struct vop_readdir_args *ap = v;
1415 struct uio auio, *uio = ap->a_uio;
1416 struct iovec aiov;
1417 union {
1418 struct dirent dn;
1419 char __pad[roundup(sizeof(struct dirent), 8)((((sizeof(struct dirent))+((8)-1))/(8))*(8))];
1420 } u;
1421 off_t off = uio->uio_offset;
1422 struct direct *dp;
1423 char *edp;
1424 caddr_t diskbuf;
1425 size_t count, entries;
1426 int bufsize, readcnt, error;
1427#if (BYTE_ORDER1234 == LITTLE_ENDIAN1234)
1428 int ofmt = VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_ump->um_maxsymlinklen == 0;
1429#endif
1430
1431 if (uio->uio_rw != UIO_READ)
1432 return (EINVAL22);
1433
1434 count = uio->uio_resid;
1435 entries = (uio->uio_offset + count) & (DIRBLKSIZ(1 << 9) - 1);
1436
1437 /* Make sure we don't return partial entries. */
1438 if (count <= entries)
1439 return (EINVAL22);
1440
1441 /*
1442 * Convert and copy back the on-disk struct direct format to
1443 * the user-space struct dirent format, one entry at a time
1444 */
1445
1446 /* read from disk, stopping on a block boundary, max 64kB */
1447 readcnt = min(count, 64*1024) - entries;
1448
1449 auio = *uio;
1450 auio.uio_iov = &aiov;
1451 auio.uio_iovcnt = 1;
1452 auio.uio_resid = readcnt;
1453 auio.uio_segflg = UIO_SYSSPACE;
1454 aiov.iov_len = readcnt;
1455 bufsize = readcnt;
1456 diskbuf = malloc(bufsize, M_TEMP127, M_WAITOK0x0001);
1457 aiov.iov_base = diskbuf;
1458 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1459 readcnt -= auio.uio_resid;
1460 dp = (struct direct *)diskbuf;
1461 edp = &diskbuf[readcnt];
1462
1463 memset(&u, 0, sizeof(u))__builtin_memset((&u), (0), (sizeof(u)));
1464
1465 /*
1466 * While
1467 * - we haven't failed to VOP_READ or uiomove()
1468 * - there's space in the read buf for the head of an entry
1469 * - that entry has a valid d_reclen, and
1470 * - there's space for the *entire* entry
1471 * then we're good to process this one.
1472 */
1473 while (error == 0 &&
1474 (char *)dp + offsetof(struct direct, d_name)__builtin_offsetof(struct direct, d_name) < edp &&
1475 dp->d_reclen > offsetof(struct direct, d_name)__builtin_offsetof(struct direct, d_name) &&
1476 (char *)dp + dp->d_reclen <= edp) {
1477 u.dn.d_reclen = roundup(dp->d_namlen+1 +((((dp->d_namlen+1 + __builtin_offsetof(struct dirent, d_name
))+((8)-1))/(8))*(8))
1478 offsetof(struct dirent, d_name), 8)((((dp->d_namlen+1 + __builtin_offsetof(struct dirent, d_name
))+((8)-1))/(8))*(8))
;
1479 if (u.dn.d_reclen > uio->uio_resid)
1480 break;
1481 off += dp->d_reclen;
1482 u.dn.d_off = off;
1483 u.dn.d_fileno = dp->d_ino;
1484#if (BYTE_ORDER1234 == LITTLE_ENDIAN1234)
1485 if (ofmt) {
1486 u.dn.d_type = dp->d_namlen;
1487 u.dn.d_namlen = dp->d_type;
1488 } else
1489#endif
1490 {
1491 u.dn.d_type = dp->d_type;
1492 u.dn.d_namlen = dp->d_namlen;
1493 }
1494 memcpy(u.dn.d_name, dp->d_name, u.dn.d_namlen)__builtin_memcpy((u.dn.d_name), (dp->d_name), (u.dn.d_namlen
))
;
1495 memset(u.dn.d_name + u.dn.d_namlen, 0, u.dn.d_reclen__builtin_memset((u.dn.d_name + u.dn.d_namlen), (0), (u.dn.d_reclen
- u.dn.d_namlen - __builtin_offsetof(struct dirent, d_name))
)
1496 - u.dn.d_namlen - offsetof(struct dirent, d_name))__builtin_memset((u.dn.d_name + u.dn.d_namlen), (0), (u.dn.d_reclen
- u.dn.d_namlen - __builtin_offsetof(struct dirent, d_name))
)
;
1497
1498 error = uiomove(&u.dn, u.dn.d_reclen, uio);
1499 dp = (struct direct *)((char *)dp + dp->d_reclen);
1500 }
1501
1502 /*
1503 * If there was room for an entry in what we read but its
1504 * d_reclen is bogus, fail
1505 */
1506 if ((char *)dp + offsetof(struct direct, d_name)__builtin_offsetof(struct direct, d_name) < edp &&
1507 dp->d_reclen <= offsetof(struct direct, d_name)__builtin_offsetof(struct direct, d_name))
1508 error = EIO5;
1509 free(diskbuf, M_TEMP127, bufsize);
1510
1511 uio->uio_offset = off;
1512 *ap->a_eofflag = DIP(VTOI(ap->a_vp), size)(((((struct inode *)(ap->a_vp)->v_data))->i_ump->
um_fstype == 1) ? (((struct inode *)(ap->a_vp)->v_data)
)->dinode_u.ffs1_din->di_size : (((struct inode *)(ap->
a_vp)->v_data))->dinode_u.ffs2_din->di_size)
<= off;
1513
1514 return (error);
1515}
1516
1517/*
1518 * Return target name of a symbolic link
1519 */
1520int
1521ufs_readlink(void *v)
1522{
1523 struct vop_readlink_args *ap = v;
1524 struct vnode *vp = ap->a_vp;
1525 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
1526 u_int64_t isize;
1527
1528 isize = DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
;
1529 if (isize < ip->i_ump->um_maxsymlinklen ||
1530 (ip->i_ump->um_maxsymlinklen == 0 && DIP(ip, blocks)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_blocks : (ip)->dinode_u.ffs2_din->di_blocks)
== 0)) {
1531 return (uiomove((char *)SHORTLINK(ip)(((ip)->i_ump->um_fstype == 1) ? (caddr_t)(ip)->dinode_u
.ffs1_din->di_db : (caddr_t)(ip)->dinode_u.ffs2_din->
di_db)
, isize, ap->a_uio));
1532 }
1533 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1534}
1535
1536/*
1537 * Lock an inode. If its already locked, set the WANT bit and sleep.
1538 */
1539int
1540ufs_lock(void *v)
1541{
1542 struct vop_lock_args *ap = v;
1543 struct vnode *vp = ap->a_vp;
1544
1545 return rrw_enter(&VTOI(vp)((struct inode *)(vp)->v_data)->i_lock, ap->a_flags & LK_RWFLAGS(0x0001UL|0x0002UL|0x0040UL|0x0080UL|0x0100UL));
1546}
1547
1548/*
1549 * Unlock an inode. If WANT bit is on, wakeup.
1550 */
1551int
1552ufs_unlock(void *v)
1553{
1554 struct vop_unlock_args *ap = v;
1555 struct vnode *vp = ap->a_vp;
1556
1557 rrw_exit(&VTOI(vp)((struct inode *)(vp)->v_data)->i_lock);
1558 return 0;
1559}
1560
1561/*
1562 * Check for a locked inode.
1563 */
1564int
1565ufs_islocked(void *v)
1566{
1567 struct vop_islocked_args *ap = v;
1568
1569 return rrw_status(&VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_lock);
1570}
1571
1572/*
1573 * Calculate the logical to physical mapping if not done already,
1574 * then call the device strategy routine.
1575 */
1576int
1577ufs_strategy(void *v)
1578{
1579 struct vop_strategy_args *ap = v;
1580 struct buf *bp = ap->a_bp;
1581 struct vnode *vp = bp->b_vp;
1582 struct inode *ip;
1583 int error;
1584 int s;
1585
1586 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1587 if (vp->v_type == VBLK || vp->v_type == VCHR)
1588 panic("ufs_strategy: spec");
1589 if (bp->b_blkno == bp->b_lblkno) {
1590 error = VOP_BMAP(vp, bp->b_lblkno, NULL((void *)0), &bp->b_blkno,
1591 NULL((void *)0));
1592 if (error) {
1593 bp->b_error = error;
1594 bp->b_flags |= B_ERROR0x00000400;
1595 s = splbio()splraise(0x6);
1596 biodone(bp);
1597 splx(s)spllower(s);
1598 return (error);
1599 }
1600 if (bp->b_blkno == -1)
1601 clrbuf(bp){ __builtin_bzero(((bp)->b_data), ((bp)->b_bcount)); (bp
)->b_resid = 0; }
;
1602 }
1603 if (bp->b_blkno == -1) {
1604 s = splbio()splraise(0x6);
1605 biodone(bp);
1606 splx(s)spllower(s);
1607 return (0);
1608 }
1609 vp = ip->i_devvpi_ump->um_devvp;
1610 bp->b_dev = vp->v_rdevv_un.vu_specinfo->si_rdev;
1611 VOP_STRATEGY(vp, bp);
1612 return (0);
1613}
1614
1615/*
1616 * Print out the contents of an inode.
1617 */
1618int
1619ufs_print(void *v)
1620{
1621#ifdef DIAGNOSTIC1
1622 struct vop_print_args *ap = v;
1623
1624 struct vnode *vp = ap->a_vp;
1625 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
1626
1627 printf("tag VT_UFS, ino %u, on dev %d, %d", ip->i_number,
1628 major(ip->i_dev)(((unsigned)(ip->i_dev) >> 8) & 0xff), minor(ip->i_dev)((unsigned)((ip->i_dev) & 0xff) | (((ip->i_dev) &
0xffff0000) >> 8))
);
1629 printf(" flags 0x%x, effnlink %d, nlink %d\n",
1630 ip->i_flag, ip->i_effnlink, DIP(ip, nlink)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_nlink : (ip)->dinode_u.ffs2_din->di_nlink)
);
1631 printf("\tmode 0%o, owner %d, group %d, size %lld",
1632 DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
, DIP(ip, uid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_uid : (ip)->dinode_u.ffs2_din->di_uid)
, DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
, DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
);
1633
1634#ifdef FIFO1
1635 if (vp->v_type == VFIFO)
1636 fifo_printinfo(vp);
1637#endif /* FIFO */
1638 printf("\n");
1639
1640#endif /* DIAGNOSTIC */
1641
1642 return (0);
1643}
1644
1645/*
1646 * Read wrapper for special devices.
1647 */
1648int
1649ufsspec_read(void *v)
1650{
1651 struct vop_read_args *ap = v;
1652
1653 /*
1654 * Set access flag.
1655 */
1656 VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_flag |= IN_ACCESS0x0001;
1657 return (spec_read(ap));
1658}
1659
1660/*
1661 * Write wrapper for special devices.
1662 */
1663int
1664ufsspec_write(void *v)
1665{
1666 struct vop_write_args *ap = v;
1667
1668 /*
1669 * Set update and change flags.
1670 */
1671 VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
1672 return (spec_write(ap));
1673}
1674
1675/*
1676 * Close wrapper for special devices.
1677 *
1678 * Update the times on the inode then do device close.
1679 */
1680int
1681ufsspec_close(void *v)
1682{
1683 struct vop_close_args *ap = v;
1684 struct vnode *vp = ap->a_vp;
1685
1686 if (vp->v_usecount > 1)
1687 ufs_itimes(vp);
1688 return (spec_close(ap));
1689}
1690
1691#ifdef FIFO1
1692/*
1693 * Read wrapper for fifo's
1694 */
1695int
1696ufsfifo_read(void *v)
1697{
1698 struct vop_read_args *ap = v;
1699
1700 /*
1701 * Set access flag.
1702 */
1703 VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_flag |= IN_ACCESS0x0001;
1704 return (fifo_read(ap));
1705}
1706
1707/*
1708 * Write wrapper for fifo's.
1709 */
1710int
1711ufsfifo_write(void *v)
1712{
1713 struct vop_write_args *ap = v;
1714
1715 /*
1716 * Set update and change flags.
1717 */
1718 VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
1719 return (fifo_write(ap));
1720}
1721
1722/*
1723 * Close wrapper for fifo's.
1724 *
1725 * Update the times on the inode then do device close.
1726 */
1727int
1728ufsfifo_close(void *v)
1729{
1730 struct vop_close_args *ap = v;
1731 struct vnode *vp = ap->a_vp;
1732
1733 if (vp->v_usecount > 1)
1734 ufs_itimes(vp);
1735 return (fifo_close(ap));
1736}
1737#endif /* FIFO */
1738
1739/*
1740 * Return POSIX pathconf information applicable to ufs filesystems.
1741 */
1742int
1743ufs_pathconf(void *v)
1744{
1745 struct vop_pathconf_args *ap = v;
1746 int error = 0;
1747
1748 switch (ap->a_name) {
1749 case _PC_LINK_MAX1:
1750 *ap->a_retval = LINK_MAX32767;
1751 break;
1752 case _PC_NAME_MAX4:
1753 *ap->a_retval = NAME_MAX255;
1754 break;
1755 case _PC_CHOWN_RESTRICTED7:
1756 *ap->a_retval = 1;
1757 break;
1758 case _PC_NO_TRUNC8:
1759 *ap->a_retval = 1;
1760 break;
1761 case _PC_ALLOC_SIZE_MIN11:
1762 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
1763 break;
1764 case _PC_FILESIZEBITS13:
1765 *ap->a_retval = 64;
1766 break;
1767 case _PC_REC_INCR_XFER_SIZE15:
1768 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
1769 break;
1770 case _PC_REC_MAX_XFER_SIZE16:
1771 *ap->a_retval = -1; /* means ``unlimited'' */
1772 break;
1773 case _PC_REC_MIN_XFER_SIZE17:
1774 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
1775 break;
1776 case _PC_REC_XFER_ALIGN18:
1777 *ap->a_retval = PAGE_SIZE(1 << 12);
1778 break;
1779 case _PC_SYMLINK_MAX19:
1780 *ap->a_retval = MAXPATHLEN1024;
1781 break;
1782 case _PC_2_SYMLINKS10:
1783 *ap->a_retval = 1;
1784 break;
1785 case _PC_TIMESTAMP_RESOLUTION21:
1786 *ap->a_retval = 1;
1787 break;
1788 default:
1789 error = EINVAL22;
1790 break;
1791 }
1792
1793 return (error);
1794}
1795
1796/*
1797 * Advisory record locking support
1798 */
1799int
1800ufs_advlock(void *v)
1801{
1802 struct vop_advlock_args *ap = v;
1803 struct inode *ip = VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data);
1804
1805 return (lf_advlock(&ip->i_lockf, DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
, ap->a_id, ap->a_op,
1806 ap->a_fl, ap->a_flags));
1807}
1808
1809/*
1810 * Allocate a new inode.
1811 */
1812int
1813ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1814 struct componentname *cnp)
1815{
1816 struct inode *ip, *pdir;
1817 struct direct newdir;
1818 struct vnode *tvp;
1819 int error;
1820
1821 pdir = VTOI(dvp)((struct inode *)(dvp)->v_data);
1822#ifdef DIAGNOSTIC1
1823 if ((cnp->cn_flags & HASBUF0x000400) == 0)
1824 panic("ufs_makeinode: no name");
1825#endif
1826 *vpp = NULL((void *)0);
1827 if ((mode & IFMT0170000) == 0)
1828 mode |= IFREG0100000;
1829
1830 if ((error = UFS_INODE_ALLOC(pdir, mode, cnp->cn_cred, &tvp)((pdir)->i_vtbl->iv_inode_alloc)((pdir), (mode), (cnp->
cn_cred), (&tvp))
) != 0) {
1831 pool_put(&namei_pool, cnp->cn_pnbuf);
1832 return (error);
1833 }
1834
1835 ip = VTOI(tvp)((struct inode *)(tvp)->v_data);
1836
1837 DIP_ASSIGN(ip, gid, DIP(pdir, gid))do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_gid = ((((pdir)->i_ump->um_fstype == 1
) ? (pdir)->dinode_u.ffs1_din->di_gid : (pdir)->dinode_u
.ffs2_din->di_gid)); else (ip)->dinode_u.ffs2_din->di_gid
= ((((pdir)->i_ump->um_fstype == 1) ? (pdir)->dinode_u
.ffs1_din->di_gid : (pdir)->dinode_u.ffs2_din->di_gid
)); } while (0)
;
1838 DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_uid = (cnp->cn_cred->cr_uid); else (ip
)->dinode_u.ffs2_din->di_uid = (cnp->cn_cred->cr_uid
); } while (0)
;
1839
1840 if ((error = getinoquota(ip)) ||
1841 (error = ufs_quota_alloc_inode(ip, cnp->cn_cred)ufs_quota_alloc_inode2(ip, cnp->cn_cred, 0))) {
1842 pool_put(&namei_pool, cnp->cn_pnbuf);
1843 UFS_INODE_FREE(ip, ip->i_number, mode)((ip)->i_vtbl->iv_inode_free)((ip), (ip->i_number), (
mode))
;
1844 vput(tvp);
1845 return (error);
1846 }
1847
1848 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
1849 DIP_ASSIGN(ip, mode, mode)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode = (mode); else (ip)->dinode_u.ffs2_din
->di_mode = (mode); } while (0)
;
1850 tvp->v_type = IFTOVT(mode)(iftovt_tab[((mode) & 0170000) >> 12]); /* Rest init'd in getnewvnode(). */
1851 ip->i_effnlink = 1;
1852 DIP_ASSIGN(ip, nlink, 1)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink = (1); else (ip)->dinode_u.ffs2_din
->di_nlink = (1); } while (0)
;
1853 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000))
1854 softdep_change_linkcnt(ip, 0);
1855 if ((DIP(ip, mode)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_mode : (ip)->dinode_u.ffs2_din->di_mode)
& ISGID0002000) &&
1856 !groupmember(DIP(ip, gid)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_gid : (ip)->dinode_u.ffs2_din->di_gid)
, cnp->cn_cred) &&
1857 !vnoperm(dvp) &&
1858 suser_ucred(cnp->cn_cred))
1859 DIP_AND(ip, mode, ~ISGID)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_mode &= (~0002000); else (ip)->dinode_u
.ffs2_din->di_mode &= (~0002000); } while (0)
;
1860
1861 /*
1862 * Make sure inode goes to disk before directory entry.
1863 */
1864 if ((error = UFS_UPDATE(ip, !DOINGSOFTDEP(tvp))((ip)->i_vtbl->iv_update)((ip), (!((tvp)->v_mount->
mnt_flag & 0x04000000)))
) != 0)
1865 goto bad;
1866
1867 ufs_makedirentry(ip, cnp, &newdir);
1868 if ((error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL((void *)0))) != 0)
1869 goto bad;
1870
1871 if ((cnp->cn_flags & SAVESTART0x001000) == 0)
1872 pool_put(&namei_pool, cnp->cn_pnbuf);
1873 *vpp = tvp;
1874 return (0);
1875
1876bad:
1877 /*
1878 * Write error occurred trying to update the inode
1879 * or the directory so must deallocate the inode.
1880 */
1881 pool_put(&namei_pool, cnp->cn_pnbuf);
1882 ip->i_effnlink = 0;
1883 DIP_ASSIGN(ip, nlink, 0)do { if ((ip)->i_ump->um_fstype == 1) (ip)->dinode_u
.ffs1_din->di_nlink = (0); else (ip)->dinode_u.ffs2_din
->di_nlink = (0); } while (0)
;
1884 ip->i_flag |= IN_CHANGE0x0002;
1885 if (DOINGSOFTDEP(tvp)((tvp)->v_mount->mnt_flag & 0x04000000))
1886 softdep_change_linkcnt(ip, 0);
1887 tvp->v_type = VNON;
1888 vput(tvp);
1889
1890 return (error);
1891}
1892
1893const struct filterops ufsread_filtops = {
1894 .f_flags = FILTEROP_ISFD0x00000001,
1895 .f_attach = NULL((void *)0),
1896 .f_detach = filt_ufsdetach,
1897 .f_event = filt_ufsread,
1898};
1899
1900const struct filterops ufswrite_filtops = {
1901 .f_flags = FILTEROP_ISFD0x00000001,
1902 .f_attach = NULL((void *)0),
1903 .f_detach = filt_ufsdetach,
1904 .f_event = filt_ufswrite,
1905};
1906
1907const struct filterops ufsvnode_filtops = {
1908 .f_flags = FILTEROP_ISFD0x00000001,
1909 .f_attach = NULL((void *)0),
1910 .f_detach = filt_ufsdetach,
1911 .f_event = filt_ufsvnode,
1912};
1913
1914int
1915ufs_kqfilter(void *v)
1916{
1917 struct vop_kqfilter_args *ap = v;
1918 struct vnode *vp = ap->a_vp;
1919 struct knote *kn = ap->a_kn;
1920
1921 switch (kn->kn_filterkn_kevent.filter) {
1922 case EVFILT_READ(-1):
1923 kn->kn_fop = &ufsread_filtops;
1924 break;
1925 case EVFILT_WRITE(-2):
1926 kn->kn_fop = &ufswrite_filtops;
1927 break;
1928 case EVFILT_VNODE(-4):
1929 kn->kn_fop = &ufsvnode_filtops;
1930 break;
1931 default:
1932 return (EINVAL22);
1933 }
1934
1935 kn->kn_hook = (caddr_t)vp;
1936
1937 klist_insert_locked(&vp->v_selectinfo.si_note, kn);
1938
1939 return (0);
1940}
1941
1942void
1943filt_ufsdetach(struct knote *kn)
1944{
1945 struct vnode *vp = (struct vnode *)kn->kn_hook;
1946
1947 klist_remove_locked(&vp->v_selectinfo.si_note, kn);
1948}
1949
1950int
1951filt_ufsread(struct knote *kn, long hint)
1952{
1953 struct vnode *vp = (struct vnode *)kn->kn_hook;
1954 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
1955
1956 /*
1957 * filesystem is gone, so set the EOF flag and schedule
1958 * the knote for deletion.
1959 */
1960 if (hint == NOTE_REVOKE0x0040) {
1961 kn->kn_flagskn_kevent.flags |= (EV_EOF0x8000 | EV_ONESHOT0x0010);
1962 return (1);
1963 }
1964
1965#ifdef EXT2FS1
1966 if (IS_EXT2_VNODE(ip->i_vnode)(ip->i_vnode->v_tag == VT_EXT2FS))
1967 kn->kn_datakn_kevent.data = ext2fs_size(ip) - foffset(kn->kn_fpkn_ptr.p_fp);
1968 else
1969#endif
1970 kn->kn_datakn_kevent.data = DIP(ip, size)(((ip)->i_ump->um_fstype == 1) ? (ip)->dinode_u.ffs1_din
->di_size : (ip)->dinode_u.ffs2_din->di_size)
- foffset(kn->kn_fpkn_ptr.p_fp);
1971 if (kn->kn_datakn_kevent.data == 0 && kn->kn_sfflags & NOTE_EOF0x0002) {
1972 kn->kn_fflagskn_kevent.fflags |= NOTE_EOF0x0002;
1973 return (1);
1974 }
1975
1976 if (kn->kn_flagskn_kevent.flags & (__EV_POLL0x1000 | __EV_SELECT0x0800))
1977 return (1);
1978
1979 return (kn->kn_datakn_kevent.data != 0);
1980}
1981
1982int
1983filt_ufswrite(struct knote *kn, long hint)
1984{
1985 /*
1986 * filesystem is gone, so set the EOF flag and schedule
1987 * the knote for deletion.
1988 */
1989 if (hint == NOTE_REVOKE0x0040) {
1990 kn->kn_flagskn_kevent.flags |= (EV_EOF0x8000 | EV_ONESHOT0x0010);
1991 return (1);
1992 }
1993
1994 kn->kn_datakn_kevent.data = 0;
1995 return (1);
1996}
1997
1998int
1999filt_ufsvnode(struct knote *kn, long hint)
2000{
2001 if (kn->kn_sfflags & hint)
2002 kn->kn_fflagskn_kevent.fflags |= hint;
2003 if (hint == NOTE_REVOKE0x0040) {
2004 kn->kn_flagskn_kevent.flags |= EV_EOF0x8000;
2005 return (1);
2006 }
2007 return (kn->kn_fflagskn_kevent.fflags != 0);
2008}