Bug Summary

File:ufs/ext2fs/ext2fs_vnops.c
Warning:line 1018, 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 ext2fs_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/ext2fs/ext2fs_vnops.c
1/* $OpenBSD: ext2fs_vnops.c,v 1.91 2023/03/08 04:43:09 guenther Exp $ */
2/* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */
3
4/*
5 * Copyright (c) 1997 Manuel Bouyer.
6 * Copyright (c) 1982, 1986, 1989, 1993
7 * The Regents of the University of California. All rights reserved.
8 * (c) UNIX System Laboratories, Inc.
9 * All or some portions of this file are derived from material licensed
10 * to the University of California by American Telephone and Telegraph
11 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12 * the permission of UNIX System Laboratories, Inc.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)ufs_vnops.c 8.14 (Berkeley) 10/26/94
39 * Modified for ext2fs by Manuel Bouyer.
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/resourcevar.h>
45#include <sys/kernel.h>
46#include <sys/fcntl.h>
47#include <sys/stat.h>
48#include <sys/proc.h>
49#include <sys/conf.h>
50#include <sys/mount.h>
51#include <sys/namei.h>
52#include <sys/vnode.h>
53#include <sys/lockf.h>
54#include <sys/malloc.h>
55#include <sys/pool.h>
56#include <sys/signalvar.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/ufs_extern.h>
65#include <ufs/ufs/ufsmount.h>
66
67#include <ufs/ext2fs/ext2fs.h>
68#include <ufs/ext2fs/ext2fs_extern.h>
69#include <ufs/ext2fs/ext2fs_dir.h>
70
71#include <uvm/uvm_extern.h>
72
73static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *);
74static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *);
75
76/*
77 * Create a regular file
78 */
79int
80ext2fs_create(void *v)
81{
82 struct vop_create_args *ap = v;
83
84 return (ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type,(int)((vttoif_tab[(int)(ap->a_vap->va_type)]) | (ap->
a_vap->va_mode))
85 ap->a_vap->va_mode)(int)((vttoif_tab[(int)(ap->a_vap->va_type)]) | (ap->
a_vap->va_mode))
, ap->a_dvp, ap->a_vpp, ap->a_cnp));
86}
87
88/*
89 * Mknod vnode call
90 */
91int
92ext2fs_mknod(void *v)
93{
94 struct vop_mknod_args *ap = v;
95 struct vattr *vap = ap->a_vap;
96 struct vnode **vpp = ap->a_vpp;
97 struct inode *ip;
98 int error;
99
100 error = ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode)(int)((vttoif_tab[(int)(vap->va_type)]) | (vap->va_mode
))
,
101 ap->a_dvp, vpp, ap->a_cnp);
102 if (error != 0)
103 return (error);
104 ip = VTOI(*vpp)((struct inode *)(*vpp)->v_data);
105 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
106 if (vap->va_rdev != VNOVAL(-1)) {
107 /*
108 * Want to be able to use this to make badblock
109 * inodes, so don't truncate the dev number.
110 */
111 ip->i_e2dindinode_u.e2fs_din->e2di_rdeve2di_blocks[0] = htole32(vap->va_rdev)((__uint32_t)(vap->va_rdev));
112 }
113 /*
114 * Remove inode so that it will be reloaded by VFS_VGET and
115 * checked to see if it is an alias of an existing entry in
116 * the inode cache.
117 */
118 vput(*vpp);
119 (*vpp)->v_type = VNON;
120 vgone(*vpp);
121 *vpp = NULL((void *)0);
122 return (0);
123}
124
125/*
126 * Open called.
127 *
128 * Just check the APPEND flag.
129 */
130int
131ext2fs_open(void *v)
132{
133 struct vop_open_args *ap = v;
134
135 /*
136 * Files marked append-only must be opened for appending.
137 */
138 if ((VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data)->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020) &&
139 (ap->a_mode & (FWRITE0x0002 | O_APPEND0x0008)) == FWRITE0x0002)
140 return (EPERM1);
141 return (0);
142}
143
144int
145ext2fs_access(void *v)
146{
147 struct vop_access_args *ap = v;
148 struct vnode *vp = ap->a_vp;
149 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
150 mode_t mode = ap->a_mode;
151
152 /* If immutable bit set, nobody gets to write it. */
153 if ((mode & VWRITE00200) && (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_IMMUTABLE0x00000010))
154 return (EPERM1);
155
156 return (vaccess(vp->v_type, ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode, ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid,
157 ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid, mode, ap->a_cred));
158}
159
160int
161ext2fs_getattr(void *v)
162{
163 struct vop_getattr_args *ap = v;
164 struct vnode *vp = ap->a_vp;
165 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
166 struct vattr *vap = ap->a_vap;
167
168 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)
;
169 /*
170 * Copy from inode table
171 */
172 vap->va_fsid = ip->i_dev;
173 vap->va_fileid = ip->i_number;
174 vap->va_mode = ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode & ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007);
175 vap->va_nlink = ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink;
176 vap->va_uid = ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid;
177 vap->va_gid = ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid;
178 vap->va_rdev = (dev_t) letoh32(ip->i_e2din->e2di_rdev)((__uint32_t)(ip->dinode_u.e2fs_din->e2di_blocks[0]));
179 vap->va_size = ext2fs_size(ip);
180 vap->va_atime.tv_sec = ip->i_e2fs_atimedinode_u.e2fs_din->e2di_atime;
181 vap->va_atime.tv_nsec = 0;
182 vap->va_mtime.tv_sec = ip->i_e2fs_mtimedinode_u.e2fs_din->e2di_mtime;
183 vap->va_mtime.tv_nsec = 0;
184 vap->va_ctime.tv_sec = ip->i_e2fs_ctimedinode_u.e2fs_din->e2di_ctime;
185 vap->va_ctime.tv_nsec = 0;
186#ifdef EXT2FS_SYSTEM_FLAGS
187 vap->va_flags = (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020) ? SF_APPEND0x00040000 : 0;
188 vap->va_flags |= (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_IMMUTABLE0x00000010) ? SF_IMMUTABLE0x00020000 : 0;
189#else
190 vap->va_flags = (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020) ? UF_APPEND0x00000004 : 0;
191 vap->va_flags |= (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_IMMUTABLE0x00000010) ? UF_IMMUTABLE0x00000002 : 0;
192#endif
193 vap->va_gen = ip->i_e2fs_gendinode_u.e2fs_din->e2di_gen;
194 /* this doesn't belong here */
195 if (vp->v_type == VBLK)
196 vap->va_blocksize = BLKDEV_IOSIZE(1 << 12);
197 else if (vp->v_type == VCHR)
198 vap->va_blocksize = MAXBSIZE(64 * 1024);
199 else
200 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
201 vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock)(((u_quad_t)ip->dinode_u.e2fs_din->e2di_nblock) <<
9)
;
202 vap->va_type = vp->v_type;
203 vap->va_filerev = ip->i_modrev;
204 return (0);
205}
206
207/*
208 * Set attribute vnode op. called from several syscalls
209 */
210int
211ext2fs_setattr(void *v)
212{
213 struct vop_setattr_args *ap = v;
214 struct vattr *vap = ap->a_vap;
215 struct vnode *vp = ap->a_vp;
216 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
217 struct ucred *cred = ap->a_cred;
218 int error;
219
220 /*
221 * Check for unsettable attributes.
222 */
223 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL(-1)) ||
224 (vap->va_fsid != VNOVAL(-1)) || (vap->va_fileid != VNOVAL(-1)) ||
225 (vap->va_blocksize != VNOVAL(-1)) || (vap->va_rdev != VNOVAL(-1)) ||
226 ((int)vap->va_bytes != VNOVAL(-1)) || (vap->va_gen != VNOVAL(-1))) {
227 return (EINVAL22);
228 }
229 if (vap->va_flags != VNOVAL(-1)) {
230 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
231 return (EROFS30);
232 if (cred->cr_uid != ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid &&
233 (error = suser_ucred(cred)))
234 return (error);
235#ifdef EXT2FS_SYSTEM_FLAGS
236 if (cred->cr_uid == 0) {
237 if ((ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags &
238 (EXT2_APPEND0x00000020 | EXT2_IMMUTABLE0x00000010)) && securelevel > 0)
239 return (EPERM1);
240 ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags &= ~(EXT2_APPEND0x00000020 | EXT2_IMMUTABLE0x00000010);
241 ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags |=
242 (vap->va_flags & SF_APPEND0x00040000) ? EXT2_APPEND0x00000020 : 0 |
243 (vap->va_flags & SF_IMMUTABLE0x00020000) ? EXT2_IMMUTABLE0x00000010: 0;
244 } else {
245 return (EPERM1);
246 }
247#else
248 ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags &= ~(EXT2_APPEND0x00000020 | EXT2_IMMUTABLE0x00000010);
249 ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags |=
250 (vap->va_flags & UF_APPEND0x00000004) ? EXT2_APPEND0x00000020 : 0 |
251 (vap->va_flags & UF_IMMUTABLE0x00000002) ? EXT2_IMMUTABLE0x00000010: 0;
252#endif
253 ip->i_flag |= IN_CHANGE0x0002;
254 if (vap->va_flags & (IMMUTABLE(0x00000002 | 0x00020000) | APPEND(0x00000004 | 0x00040000)))
255 return (0);
256 }
257 if (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_APPEND0x00000020 | EXT2_IMMUTABLE0x00000010))
258 return (EPERM1);
259 /*
260 * Go through the fields and update iff not VNOVAL.
261 */
262 if (vap->va_uid != (uid_t)VNOVAL(-1) || vap->va_gid != (gid_t)VNOVAL(-1)) {
263 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
264 return (EROFS30);
265 error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred);
266 if (error)
267 return (error);
268 }
269 if (vap->va_size != VNOVAL(-1)) {
270 /*
271 * Disallow write attempts on read-only file systems;
272 * unless the file is a socket, fifo, or a block or
273 * character device resident on the file system.
274 */
275 switch (vp->v_type) {
276 case VDIR:
277 return (EISDIR21);
278 case VLNK:
279 case VREG:
280 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
281 return (EROFS30);
282 default:
283 break;
284 }
285 error = ext2fs_truncate(ip, vap->va_size, 0, cred);
286 if (error)
287 return (error);
288 }
289 if ((vap->va_vaflags & VA_UTIMES_CHANGE0x04) ||
290 vap->va_atime.tv_nsec != VNOVAL(-1) ||
291 vap->va_mtime.tv_nsec != VNOVAL(-1)) {
292 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
293 return (EROFS30);
294 if (cred->cr_uid != ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid &&
295 (error = suser_ucred(cred)) &&
296 ((vap->va_vaflags & VA_UTIMES_NULL0x01) == 0 ||
297 (error = VOP_ACCESS(vp, VWRITE00200, cred, ap->a_p))))
298 return (error);
299 if (vap->va_mtime.tv_nsec != VNOVAL(-1))
300 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
301 else if (vap->va_vaflags & VA_UTIMES_CHANGE0x04)
302 ip->i_flag |= IN_CHANGE0x0002;
303 if (vap->va_atime.tv_nsec != VNOVAL(-1)) {
304 if (!(vp->v_mount->mnt_flag & MNT_NOATIME0x00008000) ||
305 (ip->i_flag & (IN_CHANGE0x0002 | IN_UPDATE0x0004)))
306 ip->i_flag |= IN_ACCESS0x0001;
307 }
308 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)
;
309 if (vap->va_mtime.tv_nsec != VNOVAL(-1))
310 ip->i_e2fs_mtimedinode_u.e2fs_din->e2di_mtime = vap->va_mtime.tv_sec;
311 if (vap->va_atime.tv_nsec != VNOVAL(-1))
312 ip->i_e2fs_atimedinode_u.e2fs_din->e2di_atime = vap->va_atime.tv_sec;
313 error = ext2fs_update(ip, 1);
314 if (error)
315 return (error);
316 }
317 error = 0;
318 if (vap->va_mode != (mode_t)VNOVAL(-1)) {
319 if (vp->v_mount->mnt_flag & MNT_RDONLY0x00000001)
320 return (EROFS30);
321 error = ext2fs_chmod(vp, vap->va_mode, cred);
322 }
323 return (error);
324}
325
326/*
327 * Change the mode on a file.
328 * Inode must be locked before calling.
329 */
330static int
331ext2fs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred)
332{
333 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
334 int error;
335
336 if (cred->cr_uid != ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid && (error = suser_ucred(cred)))
337 return (error);
338 if (cred->cr_uid) {
339 if (vp->v_type != VDIR && (mode & S_ISTXT0001000))
340 return (EFTYPE79);
341 if (!groupmember(ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid, cred) && (mode & ISGID0002000))
342 return (EPERM1);
343 }
344 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode &= ~ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007);
345 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode |= (mode & ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007));
346 ip->i_flag |= IN_CHANGE0x0002;
347 if ((vp->v_flag & VTEXT0x0002) && (ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode & S_ISTXT0001000) == 0)
348 (void) uvm_vnp_uncache(vp);
349 return (0);
350}
351
352/*
353 * Perform chown operation on inode ip;
354 * inode must be locked prior to call.
355 */
356static int
357ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred)
358{
359 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
360 uid_t ouid;
361 gid_t ogid;
362 int error = 0;
363
364 if (uid == (uid_t)VNOVAL(-1))
365 uid = ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid;
366 if (gid == (gid_t)VNOVAL(-1))
367 gid = ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid;
368 /*
369 * If we don't own the file, are trying to change the owner
370 * of the file, or are not a member of the target group,
371 * the caller must be superuser or the call fails.
372 */
373 if ((cred->cr_uid != ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid || uid != ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid ||
374 (gid != ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid && !groupmember(gid, cred))) &&
375 (error = suser_ucred(cred)))
376 return (error);
377 ogid = ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid;
378 ouid = ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid;
379
380 ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid = gid;
381 ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid = uid;
382 if (ouid != uid || ogid != gid)
383 ip->i_flag |= IN_CHANGE0x0002;
384 if (ouid != uid && cred->cr_uid != 0)
385 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode &= ~ISUID0004000;
386 if (ogid != gid && cred->cr_uid != 0)
387 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode &= ~ISGID0002000;
388 return (0);
389}
390
391int
392ext2fs_remove(void *v)
393{
394 struct vop_remove_args *ap = v;
395 struct inode *ip;
396 struct vnode *vp = ap->a_vp;
397 struct vnode *dvp = ap->a_dvp;
398 int error;
399
400 ip = VTOI(vp)((struct inode *)(vp)->v_data);
401 if (vp->v_type == VDIR ||
402 (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_IMMUTABLE0x00000010 | EXT2_APPEND0x00000020)) ||
403 (VTOI(dvp)((struct inode *)(dvp)->v_data)->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020)) {
404 error = EPERM1;
405 goto out;
406 }
407 error = ext2fs_dirremove(dvp, ap->a_cnp);
408 if (error == 0) {
409 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
410 ip->i_flag |= IN_CHANGE0x0002;
411 }
412out:
413 if (dvp == vp)
414 vrele(vp);
415 else
416 vput(vp);
417 vput(dvp);
418 return (error);
419}
420
421/*
422 * link vnode call
423 */
424int
425ext2fs_link(void *v)
426{
427 struct vop_link_args *ap = v;
428 struct vnode *dvp = ap->a_dvp;
429 struct vnode *vp = ap->a_vp;
430 struct componentname *cnp = ap->a_cnp;
431 struct inode *ip;
432 int error;
433
434#ifdef DIAGNOSTIC1
435 if ((cnp->cn_flags & HASBUF0x000400) == 0)
436 panic("ext2fs_link: no name");
437#endif
438 if (vp->v_type == VDIR) {
439 VOP_ABORTOP(dvp, cnp);
440 error = EISDIR21;
441 goto out2;
442 }
443 if (dvp->v_mount != vp->v_mount) {
444 VOP_ABORTOP(dvp, cnp);
445 error = EXDEV18;
446 goto out2;
447 }
448 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE0x0001UL))) {
449 VOP_ABORTOP(dvp, cnp);
450 goto out2;
451 }
452 ip = VTOI(vp)((struct inode *)(vp)->v_data);
453 if ((nlink_t)ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink >= LINK_MAX32767) {
454 VOP_ABORTOP(dvp, cnp);
455 error = EMLINK31;
456 goto out1;
457 }
458 if (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_IMMUTABLE0x00000010 | EXT2_APPEND0x00000020)) {
459 VOP_ABORTOP(dvp, cnp);
460 error = EPERM1;
461 goto out1;
462 }
463 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink++;
464 ip->i_flag |= IN_CHANGE0x0002;
465 error = ext2fs_update(ip, 1);
466 if (!error)
467 error = ext2fs_direnter(ip, dvp, cnp);
468 if (error) {
469 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
470 ip->i_flag |= IN_CHANGE0x0002;
471 }
472 pool_put(&namei_pool, cnp->cn_pnbuf);
473out1:
474 if (dvp != vp)
475 VOP_UNLOCK(vp);
476out2:
477 vput(dvp);
478 return (error);
479}
480
481/*
482 * Rename system call.
483 * rename("foo", "bar");
484 * is essentially
485 * unlink("bar");
486 * link("foo", "bar");
487 * unlink("foo");
488 * but ``atomically''. Can't do full commit without saving state in the
489 * inode on disk which isn't feasible at this time. Best we can do is
490 * always guarantee the target exists.
491 *
492 * Basic algorithm is:
493 *
494 * 1) Bump link count on source while we're linking it to the
495 * target. This also ensure the inode won't be deleted out
496 * from underneath us while we work (it may be truncated by
497 * a concurrent `trunc' or `open' for creation).
498 * 2) Link source to destination. If destination already exists,
499 * delete it first.
500 * 3) Unlink source reference to inode if still around. If a
501 * directory was moved and the parent of the destination
502 * is different from the source, patch the ".." entry in the
503 * directory.
504 */
505int
506ext2fs_rename(void *v)
507{
508 struct vop_rename_args *ap = v;
509 struct vnode *tvp = ap->a_tvp;
510 struct vnode *tdvp = ap->a_tdvp;
511 struct vnode *fvp = ap->a_fvp;
512 struct vnode *fdvp = ap->a_fdvp;
513 struct componentname *tcnp = ap->a_tcnp;
514 struct componentname *fcnp = ap->a_fcnp;
515 struct inode *ip, *xp, *dp;
516 struct ext2fs_dirtemplate dirbuf;
517 /* struct timespec ts; */
518 int doingdirectory = 0, oldparent = 0, newparent = 0;
519 int error = 0;
520 u_char namlen;
521
522#ifdef DIAGNOSTIC1
523 if ((tcnp->cn_flags & HASBUF0x000400) == 0 ||
524 (fcnp->cn_flags & HASBUF0x000400) == 0)
525 panic("ext2fs_rename: no name");
526#endif
527 /*
528 * Check for cross-device rename.
529 */
530 if ((fvp->v_mount != tdvp->v_mount) ||
531 (tvp && (fvp->v_mount != tvp->v_mount))) {
532 error = EXDEV18;
533abortit:
534 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
535 if (tdvp == tvp)
536 vrele(tdvp);
537 else
538 vput(tdvp);
539 if (tvp)
540 vput(tvp);
541 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
542 vrele(fdvp);
543 vrele(fvp);
544 return (error);
545 }
546
547 /*
548 * Check if just deleting a link name.
549 */
550 if (tvp && ((VTOI(tvp)((struct inode *)(tvp)->v_data)->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_IMMUTABLE0x00000010 | EXT2_APPEND0x00000020)) ||
551 (VTOI(tdvp)((struct inode *)(tdvp)->v_data)->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020))) {
552 error = EPERM1;
553 goto abortit;
554 }
555 if (fvp == tvp) {
556 if (fvp->v_type == VDIR) {
557 error = EINVAL22;
558 goto abortit;
559 }
560
561 /* Release destination completely. */
562 VOP_ABORTOP(tdvp, tcnp);
563 vput(tdvp);
564 vput(tvp);
565
566 /* Delete source. */
567 vrele(fdvp);
568 vrele(fvp);
569 fcnp->cn_flags &= ~MODMASK0x00fc;
570 fcnp->cn_flags |= LOCKPARENT0x0008 | LOCKLEAF0x0004;
571 if ((fcnp->cn_flags & SAVESTART0x001000) == 0)
572 panic("ext2fs_rename: lost from startdir");
573 fcnp->cn_nameiop = DELETE2;
574 (void) vfs_relookup(fdvp, &fvp, fcnp);
575 return (VOP_REMOVE(fdvp, fvp, fcnp));
576 }
577 if ((error = vn_lock(fvp, LK_EXCLUSIVE0x0001UL)) != 0)
578 goto abortit;
579 dp = VTOI(fdvp)((struct inode *)(fdvp)->v_data);
580 ip = VTOI(fvp)((struct inode *)(fvp)->v_data);
581 if ((nlink_t)ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink >= LINK_MAX32767) {
582 VOP_UNLOCK(fvp);
583 error = EMLINK31;
584 goto abortit;
585 }
586 if ((ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_IMMUTABLE0x00000010 | EXT2_APPEND0x00000020)) ||
587 (dp->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020)) {
588 VOP_UNLOCK(fvp);
589 error = EPERM1;
590 goto abortit;
591 }
592 if ((ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode & IFMT0170000) == IFDIR0040000) {
593 error = VOP_ACCESS(fvp, VWRITE00200, tcnp->cn_cred, tcnp->cn_proc);
594 if (!error && tvp)
595 error = VOP_ACCESS(tvp, VWRITE00200, tcnp->cn_cred,
596 tcnp->cn_proc);
597 if (error) {
598 VOP_UNLOCK(fvp);
599 error = EACCES13;
600 goto abortit;
601 }
602 /*
603 * Avoid ".", "..", and aliases of "." for obvious reasons.
604 */
605 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
606 dp == ip ||
607 (fcnp->cn_flags&ISDOTDOT0x002000) ||
608 (tcnp->cn_flags & ISDOTDOT0x002000) ||
609 (ip->i_flag & IN_RENAME0x0010)) {
610 VOP_UNLOCK(fvp);
611 error = EINVAL22;
612 goto abortit;
613 }
614 ip->i_flag |= IN_RENAME0x0010;
615 oldparent = dp->i_number;
616 doingdirectory++;
617 }
618 vrele(fdvp);
619
620 /*
621 * When the target exists, both the directory
622 * and target vnodes are returned locked.
623 */
624 dp = VTOI(tdvp)((struct inode *)(tdvp)->v_data);
625 xp = NULL((void *)0);
626 if (tvp)
627 xp = VTOI(tvp)((struct inode *)(tvp)->v_data);
628
629 /*
630 * 1) Bump link count while we're moving stuff
631 * around. If we crash somewhere before
632 * completing our work, the link count
633 * may be wrong, but correctable.
634 */
635 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink++;
636 ip->i_flag |= IN_CHANGE0x0002;
637 if ((error = ext2fs_update(ip, 1)) != 0) {
638 VOP_UNLOCK(fvp);
639 goto bad;
640 }
641
642 /*
643 * If ".." must be changed (ie the directory gets a new
644 * parent) then the source directory must not be in the
645 * directory hierarchy above the target, as this would
646 * orphan everything below the source directory. Also
647 * the user must have write permission in the source so
648 * as to be able to change "..". We must repeat the call
649 * to namei, as the parent directory is unlocked by the
650 * call to checkpath().
651 */
652 error = VOP_ACCESS(fvp, VWRITE00200, tcnp->cn_cred, tcnp->cn_proc);
653 VOP_UNLOCK(fvp);
654 if (oldparent != dp->i_number)
655 newparent = dp->i_number;
656 if (doingdirectory && newparent) {
657 if (error) /* write access check above */
658 goto bad;
659 if (xp != NULL((void *)0))
660 vput(tvp);
661 error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
662 if (error != 0)
663 goto out;
664 if ((tcnp->cn_flags & SAVESTART0x001000) == 0)
665 panic("ext2fs_rename: lost to startdir");
666 if ((error = vfs_relookup(tdvp, &tvp, tcnp)) != 0)
667 goto out;
668 dp = VTOI(tdvp)((struct inode *)(tdvp)->v_data);
669 xp = NULL((void *)0);
670 if (tvp)
671 xp = VTOI(tvp)((struct inode *)(tvp)->v_data);
672 }
673 /*
674 * 2) If target doesn't exist, link the target
675 * to the source and unlink the source.
676 * Otherwise, rewrite the target directory
677 * entry to reference the source inode and
678 * expunge the original entry's existence.
679 */
680 if (xp == NULL((void *)0)) {
681 if (dp->i_dev != ip->i_dev)
682 panic("rename: EXDEV");
683 /*
684 * Account for ".." in new directory.
685 * When source and destination have the same
686 * parent we don't fool with the link count.
687 */
688 if (doingdirectory && newparent) {
689 if ((nlink_t)dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink >= LINK_MAX32767) {
690 error = EMLINK31;
691 goto bad;
692 }
693 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink++;
694 dp->i_flag |= IN_CHANGE0x0002;
695 if ((error = ext2fs_update(dp, 1)) != 0)
696 goto bad;
697 }
698 error = ext2fs_direnter(ip, tdvp, tcnp);
699 if (error != 0) {
700 if (doingdirectory && newparent) {
701 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
702 dp->i_flag |= IN_CHANGE0x0002;
703 (void)ext2fs_update(dp, 1);
704 }
705 goto bad;
706 }
707 vput(tdvp);
708 } else {
709 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
710 panic("rename: EXDEV");
711 /*
712 * Short circuit rename(foo, foo).
713 */
714 if (xp->i_number == ip->i_number)
715 panic("rename: same file");
716 /*
717 * If the parent directory is "sticky", then the user must
718 * own the parent directory, or the destination of the rename,
719 * otherwise the destination may not be changed (except by
720 * root). This implements append-only directories.
721 */
722 if ((dp->i_e2fs_modedinode_u.e2fs_din->e2di_mode & S_ISTXT0001000) && tcnp->cn_cred->cr_uid != 0 &&
723 tcnp->cn_cred->cr_uid != dp->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid &&
724 xp->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid != tcnp->cn_cred->cr_uid) {
725 error = EPERM1;
726 goto bad;
727 }
728 /*
729 * Target must be empty if a directory and have no links
730 * to it. Also, ensure source and target are compatible
731 * (both directories, or both not directories).
732 */
733 if ((xp->i_e2fs_modedinode_u.e2fs_din->e2di_mode & IFMT0170000) == IFDIR0040000) {
734 if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
735 xp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink > 2) {
736 error = ENOTEMPTY66;
737 goto bad;
738 }
739 if (!doingdirectory) {
740 error = ENOTDIR20;
741 goto bad;
742 }
743 cache_purge(tdvp);
744 } else if (doingdirectory) {
745 error = EISDIR21;
746 goto bad;
747 }
748 error = ext2fs_dirrewrite(dp, ip, tcnp);
749 if (error != 0)
750 goto bad;
751 /*
752 * If the target directory is in the same
753 * directory as the source directory,
754 * decrement the link count on the parent
755 * of the target directory.
756 */
757 if (doingdirectory && !newparent) {
758 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
759 dp->i_flag |= IN_CHANGE0x0002;
760 }
761 vput(tdvp);
762 /*
763 * Adjust the link count of the target to
764 * reflect the dirrewrite above. If this is
765 * a directory it is empty and there are
766 * no links to it, so we can squash the inode and
767 * any space associated with it. We disallowed
768 * renaming over top of a directory with links to
769 * it above, as the remaining link would point to
770 * a directory without "." or ".." entries.
771 */
772 xp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
773 if (doingdirectory) {
774 if (--xp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink != 0)
775 panic("rename: linked directory");
776 error = ext2fs_truncate(xp, (off_t)0, IO_SYNC0x04,
777 tcnp->cn_cred);
778 }
779 xp->i_flag |= IN_CHANGE0x0002;
780 vput(tvp);
781 xp = NULL((void *)0);
782 }
783
784 /*
785 * 3) Unlink the source.
786 */
787 fcnp->cn_flags &= ~MODMASK0x00fc;
788 fcnp->cn_flags |= LOCKPARENT0x0008 | LOCKLEAF0x0004;
789 if ((fcnp->cn_flags & SAVESTART0x001000) == 0)
790 panic("ext2fs_rename: lost from startdir");
791 (void) vfs_relookup(fdvp, &fvp, fcnp);
792 if (fvp != NULL((void *)0)) {
793 xp = VTOI(fvp)((struct inode *)(fvp)->v_data);
794 dp = VTOI(fdvp)((struct inode *)(fdvp)->v_data);
795 } else {
796 /*
797 * From name has disappeared.
798 */
799 if (doingdirectory)
800 panic("ext2fs_rename: lost dir entry");
801 vrele(ap->a_fvp);
802 return (0);
803 }
804 /*
805 * Ensure that the directory entry still exists and has not
806 * changed while the new name has been entered. If the source is
807 * a file then the entry may have been unlinked or renamed. In
808 * either case there is no further work to be done. If the source
809 * is a directory then it cannot have been rmdir'ed; its link
810 * count of three would cause a rmdir to fail with ENOTEMPTY.
811 * The IRENAME flag ensures that it cannot be moved by another
812 * rename.
813 */
814 if (xp != ip) {
815 if (doingdirectory)
816 panic("ext2fs_rename: lost dir entry");
817 } else {
818 /*
819 * If the source is a directory with a
820 * new parent, the link count of the old
821 * parent directory must be decremented
822 * and ".." set to point to the new parent.
823 */
824 if (doingdirectory && newparent) {
825 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
826 dp->i_flag |= IN_CHANGE0x0002;
827 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
828 sizeof (struct ext2fs_dirtemplate), (off_t)0,
829 UIO_SYSSPACE, IO_NODELOCKED0x08,
830 tcnp->cn_cred, NULL((void *)0), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
);
831 if (error == 0) {
832 namlen = dirbuf.dotdot_namlen;
833 if (namlen != 2 ||
834 dirbuf.dotdot_name[0] != '.' ||
835 dirbuf.dotdot_name[1] != '.') {
836 ufs_dirbad(xp, (doff_tint32_t)12,
837 "ext2fs_rename: mangled dir");
838 } else {
839 dirbuf.dotdot_ino = htole32(newparent)((__uint32_t)(newparent));
840 (void) vn_rdwr(UIO_WRITE, fvp,
841 (caddr_t)&dirbuf,
842 sizeof (struct dirtemplate),
843 (off_t)0, UIO_SYSSPACE,
844 IO_NODELOCKED0x08|IO_SYNC0x04,
845 tcnp->cn_cred, NULL((void *)0), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
);
846 cache_purge(fdvp);
847 }
848 }
849 }
850 error = ext2fs_dirremove(fdvp, fcnp);
851 if (!error) {
852 xp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
853 xp->i_flag |= IN_CHANGE0x0002;
854 }
855 xp->i_flag &= ~IN_RENAME0x0010;
856 }
857 if (dp)
858 vput(fdvp);
859 if (xp)
860 vput(fvp);
861 vrele(ap->a_fvp);
862 return (error);
863
864bad:
865 if (xp)
866 vput(ITOV(xp)((xp)->i_vnode));
867 vput(ITOV(dp)((dp)->i_vnode));
868out:
869 if (doingdirectory)
870 ip->i_flag &= ~IN_RENAME0x0010;
871 if (vn_lock(fvp, LK_EXCLUSIVE0x0001UL) == 0) {
872 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
873 ip->i_flag |= IN_CHANGE0x0002;
874 vput(fvp);
875 } else
876 vrele(fvp);
877 return (error);
878}
879
880/*
881 * Mkdir system call
882 */
883int
884ext2fs_mkdir(void *v)
885{
886 struct vop_mkdir_args *ap = v;
887 struct vnode *dvp = ap->a_dvp;
888 struct vattr *vap = ap->a_vap;
889 struct componentname *cnp = ap->a_cnp;
890 struct inode *ip, *dp;
891 struct vnode *tvp;
892 struct ext2fs_dirtemplate dirtemplate;
893 mode_t dmode;
894 int error;
895
896#ifdef DIAGNOSTIC1
897 if ((cnp->cn_flags & HASBUF0x000400) == 0)
898 panic("ext2fs_mkdir: no name");
899#endif
900 dp = VTOI(dvp)((struct inode *)(dvp)->v_data);
901 if ((nlink_t)dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink >= LINK_MAX32767) {
902 error = EMLINK31;
903 goto out;
904 }
905 dmode = vap->va_mode & ACCESSPERMS(0000700|0000070|0000007);
906 dmode |= IFDIR0040000;
907 /*
908 * Must simulate part of ext2fs_makeinode here to acquire the inode,
909 * but not have it entered in the parent directory. The entry is
910 * made later after writing "." and ".." entries.
911 */
912 if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
913 goto out;
914 ip = VTOI(tvp)((struct inode *)(tvp)->v_data);
915 ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid = cnp->cn_cred->cr_uid;
916 ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid = dp->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid;
917 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
918 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode = dmode;
919 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
920 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink = 2;
921 error = ext2fs_update(ip, 1);
922
923 /*
924 * Bump link count in parent directory
925 * to reflect work done below. Should
926 * be done before reference is created
927 * so reparation is possible if we crash.
928 */
929 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink++;
930 dp->i_flag |= IN_CHANGE0x0002;
931 if ((error = ext2fs_update(dp, 1)) != 0)
932 goto bad;
933
934 /* Initialize directory with "." and ".." from static template. */
935 memset(&dirtemplate, 0, sizeof(dirtemplate))__builtin_memset((&dirtemplate), (0), (sizeof(dirtemplate
)))
;
936 dirtemplate.dot_ino = htole32(ip->i_number)((__uint32_t)(ip->i_number));
937 dirtemplate.dot_reclen = htole16(12)((__uint16_t)(12));
938 dirtemplate.dot_namlen = 1;
939 if (ip->i_e2fsinode_u.e2fs->e2fs.e2fs_rev > E2FS_REV00 &&
940 (ip->i_e2fsinode_u.e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) {
941 dirtemplate.dot_type = EXT2_FT_DIR2;
942 }
943 dirtemplate.dot_name[0] = '.';
944 dirtemplate.dotdot_ino = htole32(dp->i_number)((__uint32_t)(dp->i_number));
945 dirtemplate.dotdot_reclen = htole16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12)((__uint16_t)(((struct inode *)(dvp)->v_data)->inode_u.
e2fs->e2fs_bsize - 12))
;
946 dirtemplate.dotdot_namlen = 2;
947 if (ip->i_e2fsinode_u.e2fs->e2fs.e2fs_rev > E2FS_REV00 &&
948 (ip->i_e2fsinode_u.e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE0x0002)) {
949 dirtemplate.dotdot_type = EXT2_FT_DIR2;
950 }
951 dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
952 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
953 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
954 IO_NODELOCKED0x08|IO_SYNC0x04, cnp->cn_cred, NULL((void *)0), curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
);
955 if (error) {
956 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
957 dp->i_flag |= IN_CHANGE0x0002;
958 goto bad;
959 }
960 if (VTOI(dvp)((struct inode *)(dvp)->v_data)->i_e2fsinode_u.e2fs->e2fs_bsize >
961 VFSTOUFS(dvp->v_mount)((struct ufsmount *)((dvp->v_mount)->mnt_data))->um_mountp->mnt_stat.f_bsize)
962 panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
963 else {
964 error = ext2fs_setsize(ip, VTOI(dvp)((struct inode *)(dvp)->v_data)->i_e2fsinode_u.e2fs->e2fs_bsize);
965 if (error) {
966 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
967 dp->i_flag |= IN_CHANGE0x0002;
968 goto bad;
969 }
970 ip->i_flag |= IN_CHANGE0x0002;
971 }
972
973 /* Directory set up, now install its entry in the parent directory. */
974 error = ext2fs_direnter(ip, dvp, cnp);
975 if (error != 0) {
976 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
977 dp->i_flag |= IN_CHANGE0x0002;
978 }
979bad:
980 /*
981 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
982 * for us because we set the link count to 0.
983 */
984 if (error) {
985 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink = 0;
986 ip->i_flag |= IN_CHANGE0x0002;
987 vput(tvp);
988 } else
989 *ap->a_vpp = tvp;
990out:
991 pool_put(&namei_pool, cnp->cn_pnbuf);
992 vput(dvp);
993 return (error);
994}
995
996/*
997 * Rmdir system call.
998 */
999int
1000ext2fs_rmdir(void *v)
1001{
1002 struct vop_rmdir_args *ap = v;
1003 struct vnode *vp = ap->a_vp;
1004 struct vnode *dvp = ap->a_dvp;
1005 struct componentname *cnp = ap->a_cnp;
1006 struct inode *ip, *dp;
1007 int error;
1008
1009 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1010 dp = VTOI(dvp)((struct inode *)(dvp)->v_data);
1011 /*
1012 * Verify the directory is empty (and valid).
1013 * (Rmdir ".." won't be valid since
1014 * ".." will contain a reference to
1015 * the current directory and thus be
1016 * non-empty.)
1017 */
1018 error = 0;
Value stored to 'error' is never read
1019 if (ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink != 2 ||
1020 !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1021 error = ENOTEMPTY66;
1022 goto out;
1023 }
1024 if ((dp->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020) ||
1025 (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & (EXT2_IMMUTABLE0x00000010 | EXT2_APPEND0x00000020))) {
1026 error = EPERM1;
1027 goto out;
1028 }
1029 /*
1030 * Delete reference to directory before purging
1031 * inode. If we crash in between, the directory
1032 * will be reattached to lost+found,
1033 */
1034 error = ext2fs_dirremove(dvp, cnp);
1035 if (error != 0)
1036 goto out;
1037 dp->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink--;
1038 dp->i_flag |= IN_CHANGE0x0002;
1039 cache_purge(dvp);
1040 vput(dvp);
1041 dvp = NULL((void *)0);
1042 /*
1043 * Truncate inode. The only stuff left
1044 * in the directory is "." and "..". The
1045 * "." reference is inconsequential since
1046 * we're quashing it. The ".." reference
1047 * has already been adjusted above. We've
1048 * removed the "." reference and the reference
1049 * in the parent directory, but there may be
1050 * other hard links so decrement by 2 and
1051 * worry about them later.
1052 */
1053 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink -= 2;
1054 error = ext2fs_truncate(ip, (off_t)0, IO_SYNC0x04, cnp->cn_cred);
1055 cache_purge(ITOV(ip)((ip)->i_vnode));
1056out:
1057 if (dvp)
1058 vput(dvp);
1059 vput(vp);
1060 return (error);
1061}
1062
1063/*
1064 * symlink -- make a symbolic link
1065 */
1066int
1067ext2fs_symlink(void *v)
1068{
1069 struct vop_symlink_args *ap = v;
1070 struct vnode *vp, **vpp = ap->a_vpp;
1071 struct inode *ip;
1072 int len, error;
1073
1074 error = ext2fs_makeinode(IFLNK0120000 | ap->a_vap->va_mode, ap->a_dvp,
1075 vpp, ap->a_cnp);
1076 vput(ap->a_dvp);
1077 if (error)
1078 return (error);
1079 vp = *vpp;
1080 len = strlen(ap->a_target);
1081 if (len < EXT2_MAXSYMLINKLEN((12 +3) * sizeof (u_int32_t))) {
1082 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1083 memcpy(ip->i_e2din->e2di_shortlink, ap->a_target, len)__builtin_memcpy((ip->dinode_u.e2fs_din->e2di_blocks), (
ap->a_target), (len))
;
1084 error = ext2fs_setsize(ip, len);
1085 if (error)
1086 goto bad;
1087 ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004;
1088 } else
1089 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1090 UIO_SYSSPACE, IO_NODELOCKED0x08, ap->a_cnp->cn_cred, NULL((void *)0),
1091 curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
);
1092bad:
1093 vput(vp);
1094 return (error);
1095}
1096
1097/*
1098 * Return target name of a symbolic link
1099 */
1100int
1101ext2fs_readlink(void *v)
1102{
1103 struct vop_readlink_args *ap = v;
1104 struct vnode *vp = ap->a_vp;
1105 struct inode *ip = VTOI(vp)((struct inode *)(vp)->v_data);
1106 u_int64_t isize;
1107
1108 isize = ext2fs_size(ip);
1109 if (isize < EXT2_MAXSYMLINKLEN((12 +3) * sizeof (u_int32_t))) {
1110 return (uiomove((char *)ip->i_e2dindinode_u.e2fs_din->e2di_shortlinke2di_blocks, isize,
1111 ap->a_uio));
1112 }
1113 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1114}
1115
1116/*
1117 * Return POSIX pathconf information applicable to ext2 filesystems.
1118 */
1119int
1120ext2fs_pathconf(void *v)
1121{
1122 struct vop_pathconf_args *ap = v;
1123 int error = 0;
1124
1125 switch (ap->a_name) {
1126 case _PC_TIMESTAMP_RESOLUTION21:
1127 *ap->a_retval = 1000000000; /* 1 billion nanoseconds */
1128 break;
1129 default:
1130 return (ufs_pathconf(v));
1131 }
1132
1133 return (error);
1134}
1135
1136/*
1137 * Advisory record locking support
1138 */
1139int
1140ext2fs_advlock(void *v)
1141{
1142 struct vop_advlock_args *ap = v;
1143 struct inode *ip = VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data);
1144
1145 return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
1146 ap->a_fl, ap->a_flags));
1147}
1148
1149/*
1150 * Allocate a new inode.
1151 */
1152int
1153ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1154 struct componentname *cnp)
1155{
1156 struct inode *ip, *pdir;
1157 struct vnode *tvp;
1158 int error;
1159
1160 pdir = VTOI(dvp)((struct inode *)(dvp)->v_data);
1161#ifdef DIAGNOSTIC1
1162 if ((cnp->cn_flags & HASBUF0x000400) == 0)
1163 panic("ext2fs_makeinode: no name");
1164#endif
1165 *vpp = NULL((void *)0);
1166 if ((mode & IFMT0170000) == 0)
1167 mode |= IFREG0100000;
1168
1169 if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp))
1170 != 0) {
1171 pool_put(&namei_pool, cnp->cn_pnbuf);
1172 return (error);
1173 }
1174 ip = VTOI(tvp)((struct inode *)(tvp)->v_data);
1175 ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid = pdir->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid;
1176 ip->i_e2fs_uidinode_ext.e2fs.ext2fs_effective_uid = cnp->cn_cred->cr_uid;
1177 ip->i_flag |= IN_ACCESS0x0001 | IN_CHANGE0x0002 | IN_UPDATE0x0004;
1178 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode = mode;
1179 tvp->v_type = IFTOVT(mode)(iftovt_tab[((mode) & 0170000) >> 12]); /* Rest init'd in getnewvnode(). */
1180 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink = 1;
1181 if ((ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode & ISGID0002000) &&
1182 !groupmember(ip->i_e2fs_gidinode_ext.e2fs.ext2fs_effective_gid, cnp->cn_cred) &&
1183 suser_ucred(cnp->cn_cred))
1184 ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode &= ~ISGID0002000;
1185
1186 /*
1187 * Make sure inode goes to disk before directory entry.
1188 */
1189 if ((error = ext2fs_update(ip, 1)) != 0)
1190 goto bad;
1191 error = ext2fs_direnter(ip, dvp, cnp);
1192 if (error != 0)
1193 goto bad;
1194 if ((cnp->cn_flags & SAVESTART0x001000) == 0)
1195 pool_put(&namei_pool, cnp->cn_pnbuf);
1196 *vpp = tvp;
1197 return (0);
1198
1199bad:
1200 /*
1201 * Write error occurred trying to update the inode
1202 * or the directory so must deallocate the inode.
1203 */
1204 pool_put(&namei_pool, cnp->cn_pnbuf);
1205 ip->i_e2fs_nlinkdinode_u.e2fs_din->e2di_nlink = 0;
1206 ip->i_flag |= IN_CHANGE0x0002;
1207 tvp->v_type = VNON;
1208 vput(tvp);
1209 return (error);
1210}
1211
1212/*
1213 * Synch an open file.
1214 */
1215int
1216ext2fs_fsync(void *v)
1217{
1218 struct vop_fsync_args *ap = v;
1219 struct vnode *vp = ap->a_vp;
1220
1221 vflushbuf(vp, ap->a_waitfor == MNT_WAIT1);
1222 return (ext2fs_update(VTOI(ap->a_vp)((struct inode *)(ap->a_vp)->v_data), ap->a_waitfor == MNT_WAIT1));
1223}
1224
1225/*
1226 * Reclaim an inode so that it can be used for other purposes.
1227 */
1228int
1229ext2fs_reclaim(void *v)
1230{
1231 struct vop_reclaim_args *ap = v;
1232 struct vnode *vp = ap->a_vp;
1233 struct inode *ip;
1234#ifdef DIAGNOSTIC1
1235 extern int prtactive;
1236
1237 if (prtactive && vp->v_usecount != 0)
1238 vprint("ext2fs_reclaim: pushing active", vp);
1239#endif
1240
1241 /*
1242 * Remove the inode from its hash chain.
1243 */
1244 ip = VTOI(vp)((struct inode *)(vp)->v_data);
1245 ufs_ihashrem(ip);
1246
1247 /*
1248 * Purge old data structures associated with the inode.
1249 */
1250 cache_purge(vp);
1251 if (ip->i_devvpi_ump->um_devvp)
1252 vrele(ip->i_devvpi_ump->um_devvp);
1253
1254 if (ip->i_e2dindinode_u.e2fs_din != NULL((void *)0))
1255 pool_put(&ext2fs_dinode_pool, ip->i_e2dindinode_u.e2fs_din);
1256
1257 pool_put(&ext2fs_inode_pool, ip);
1258
1259 vp->v_data = NULL((void *)0);
1260
1261 return (0);
1262}
1263
1264/* Global vfs data structures for ext2fs. */
1265const struct vops ext2fs_vops = {
1266 .vop_lookup = ext2fs_lookup,
1267 .vop_create = ext2fs_create,
1268 .vop_mknod = ext2fs_mknod,
1269 .vop_open = ext2fs_open,
1270 .vop_close = ufs_close,
1271 .vop_access = ext2fs_access,
1272 .vop_getattr = ext2fs_getattr,
1273 .vop_setattr = ext2fs_setattr,
1274 .vop_read = ext2fs_read,
1275 .vop_write = ext2fs_write,
1276 .vop_ioctl = ufs_ioctl,
1277 .vop_kqfilter = ufs_kqfilter,
1278 .vop_revoke = NULL((void *)0),
1279 .vop_fsync = ext2fs_fsync,
1280 .vop_remove = ext2fs_remove,
1281 .vop_link = ext2fs_link,
1282 .vop_rename = ext2fs_rename,
1283 .vop_mkdir = ext2fs_mkdir,
1284 .vop_rmdir = ext2fs_rmdir,
1285 .vop_symlink = ext2fs_symlink,
1286 .vop_readdir = ext2fs_readdir,
1287 .vop_readlink = ext2fs_readlink,
1288 .vop_abortop = vop_generic_abortop,
1289 .vop_inactive = ext2fs_inactive,
1290 .vop_reclaim = ext2fs_reclaim,
1291 .vop_lock = ufs_lock,
1292 .vop_unlock = ufs_unlock,
1293 .vop_bmap = ext2fs_bmap,
1294 .vop_strategy = ufs_strategy,
1295 .vop_print = ufs_print,
1296 .vop_islocked = ufs_islocked,
1297 .vop_pathconf = ext2fs_pathconf,
1298 .vop_advlock = ext2fs_advlock,
1299 .vop_bwrite = vop_generic_bwrite,
1300};
1301
1302const struct vops ext2fs_specvops = {
1303 .vop_close = ufsspec_close,
1304 .vop_access = ext2fs_access,
1305 .vop_getattr = ext2fs_getattr,
1306 .vop_setattr = ext2fs_setattr,
1307 .vop_read = ufsspec_read,
1308 .vop_write = ufsspec_write,
1309 .vop_fsync = ext2fs_fsync,
1310 .vop_inactive = ext2fs_inactive,
1311 .vop_reclaim = ext2fs_reclaim,
1312 .vop_lock = ufs_lock,
1313 .vop_unlock = ufs_unlock,
1314 .vop_print = ufs_print,
1315 .vop_islocked = ufs_islocked,
1316
1317 /* XXX: Keep in sync with spec_vops. */
1318 .vop_lookup = vop_generic_lookup,
1319 .vop_create = vop_generic_badop,
1320 .vop_mknod = vop_generic_badop,
1321 .vop_open = spec_open,
1322 .vop_ioctl = spec_ioctl,
1323 .vop_kqfilter = spec_kqfilter,
1324 .vop_revoke = vop_generic_revoke,
1325 .vop_remove = vop_generic_badop,
1326 .vop_link = vop_generic_badop,
1327 .vop_rename = vop_generic_badop,
1328 .vop_mkdir = vop_generic_badop,
1329 .vop_rmdir = vop_generic_badop,
1330 .vop_symlink = vop_generic_badop,
1331 .vop_readdir = vop_generic_badop,
1332 .vop_readlink = vop_generic_badop,
1333 .vop_abortop = vop_generic_badop,
1334 .vop_bmap = vop_generic_bmap,
1335 .vop_strategy = spec_strategy,
1336 .vop_pathconf = spec_pathconf,
1337 .vop_advlock = spec_advlock,
1338 .vop_bwrite = vop_generic_bwrite,
1339};
1340
1341#ifdef FIFO1
1342const struct vops ext2fs_fifovops = {
1343 .vop_close = ufsfifo_close,
1344 .vop_access = ufsfifo_close,
1345 .vop_getattr = ext2fs_getattr,
1346 .vop_setattr = ext2fs_setattr,
1347 .vop_read = ufsfifo_read,
1348 .vop_write = ufsfifo_write,
1349 .vop_fsync = ext2fs_fsync,
1350 .vop_inactive = ext2fs_inactive,
1351 .vop_reclaim = ext2fsfifo_reclaim,
1352 .vop_lock = ufs_lock,
1353 .vop_unlock = ufs_unlock,
1354 .vop_print = ufs_print,
1355 .vop_islocked = ufs_islocked,
1356 .vop_bwrite = vop_generic_bwrite,
1357
1358 /* XXX: Keep in sync with fifo_vops */
1359 .vop_lookup = vop_generic_lookup,
1360 .vop_create = vop_generic_badop,
1361 .vop_mknod = vop_generic_badop,
1362 .vop_open = fifo_open,
1363 .vop_ioctl = fifo_ioctl,
1364 .vop_kqfilter = fifo_kqfilter,
1365 .vop_revoke = vop_generic_revoke,
1366 .vop_remove = vop_generic_badop,
1367 .vop_link = vop_generic_badop,
1368 .vop_rename = vop_generic_badop,
1369 .vop_mkdir = vop_generic_badop,
1370 .vop_rmdir = vop_generic_badop,
1371 .vop_symlink = vop_generic_badop,
1372 .vop_readdir = vop_generic_badop,
1373 .vop_readlink = vop_generic_badop,
1374 .vop_abortop = vop_generic_badop,
1375 .vop_bmap = vop_generic_bmap,
1376 .vop_strategy = vop_generic_badop,
1377 .vop_pathconf = fifo_pathconf,
1378 .vop_advlock = fifo_advlock,
1379};
1380
1381int
1382ext2fsfifo_reclaim(void *v)
1383{
1384 fifo_reclaim(v);
1385 return (ext2fs_reclaim(v));
1386}
1387#endif /* FIFO */