Bug Summary

File:ufs/ext2fs/ext2fs_vnops.c
Warning:line 924, column 2
Value stored to 'error' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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