Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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