File: | ufs/ext2fs/ext2fs_readwrite.c |
Warning: | line 209, column 30 The left operand of '<<' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ext2fs_readwrite.c,v 1.46 2023/03/08 04:43:09 guenther Exp $ */ | |||
2 | /* $NetBSD: ext2fs_readwrite.c,v 1.16 2001/02/27 04:37:47 chs Exp $ */ | |||
3 | ||||
4 | /*- | |||
5 | * Copyright (c) 1997 Manuel Bouyer. | |||
6 | * Copyright (c) 1993 | |||
7 | * The Regents of the University of California. All rights reserved. | |||
8 | * | |||
9 | * Redistribution and use in source and binary forms, with or without | |||
10 | * modification, are permitted provided that the following conditions | |||
11 | * are met: | |||
12 | * 1. Redistributions of source code must retain the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer. | |||
14 | * 2. Redistributions in binary form must reproduce the above copyright | |||
15 | * notice, this list of conditions and the following disclaimer in the | |||
16 | * documentation and/or other materials provided with the distribution. | |||
17 | * 3. Neither the name of the University nor the names of its contributors | |||
18 | * may be used to endorse or promote products derived from this software | |||
19 | * without specific prior written permission. | |||
20 | * | |||
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
31 | * SUCH DAMAGE. | |||
32 | * | |||
33 | * @(#)ufs_readwrite.c 8.8 (Berkeley) 8/4/94 | |||
34 | * Modified for ext2fs by Manuel Bouyer. | |||
35 | */ | |||
36 | ||||
37 | #include <sys/param.h> | |||
38 | #include <sys/systm.h> | |||
39 | #include <sys/resourcevar.h> | |||
40 | #include <sys/kernel.h> | |||
41 | #include <sys/stat.h> | |||
42 | #include <sys/buf.h> | |||
43 | #include <sys/mount.h> | |||
44 | #include <sys/vnode.h> | |||
45 | #include <sys/malloc.h> | |||
46 | #include <sys/signalvar.h> | |||
47 | #include <sys/event.h> | |||
48 | ||||
49 | #include <ufs/ufs/quota.h> | |||
50 | #include <ufs/ufs/ufsmount.h> | |||
51 | #include <ufs/ufs/inode.h> | |||
52 | #include <ufs/ext2fs/ext2fs.h> | |||
53 | #include <ufs/ext2fs/ext2fs_extern.h> | |||
54 | ||||
55 | ||||
56 | static int ext2_ind_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *); | |||
57 | static int ext4_ext_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *); | |||
58 | ||||
59 | /* | |||
60 | * Vnode op for reading. | |||
61 | */ | |||
62 | int | |||
63 | ext2fs_read(void *v) | |||
64 | { | |||
65 | struct vop_read_args *ap = v; | |||
66 | struct vnode *vp; | |||
67 | struct inode *ip; | |||
68 | struct uio *uio; | |||
69 | struct m_ext2fs *fs; | |||
70 | ||||
71 | vp = ap->a_vp; | |||
72 | ip = VTOI(vp)((struct inode *)(vp)->v_data); | |||
73 | uio = ap->a_uio; | |||
74 | fs = ip->i_e2fsinode_u.e2fs; | |||
75 | ||||
76 | if (ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT4_EXTENTS0x00080000) | |||
| ||||
77 | return ext4_ext_read(vp, ip, fs, uio); | |||
78 | else | |||
79 | return ext2_ind_read(vp, ip, fs, uio); | |||
80 | } | |||
81 | ||||
82 | static int | |||
83 | ext2_ind_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs, | |||
84 | struct uio *uio) | |||
85 | { | |||
86 | struct buf *bp; | |||
87 | daddr_t lbn, nextlbn; | |||
88 | off_t bytesinfile; | |||
89 | int size, xfersize, blkoffset; | |||
90 | int error; | |||
91 | ||||
92 | #ifdef DIAGNOSTIC1 | |||
93 | if (uio->uio_rw != UIO_READ) | |||
94 | panic("%s: mode", "ext2fs_read"); | |||
95 | ||||
96 | if (vp->v_type == VLNK) { | |||
97 | if (ext2fs_size(ip) < EXT2_MAXSYMLINKLEN((12 +3) * sizeof (u_int32_t))) | |||
98 | panic("%s: short symlink", "ext2fs_read"); | |||
99 | } else if (vp->v_type != VREG && vp->v_type != VDIR) | |||
100 | panic("%s: type %d", "ext2fs_read", vp->v_type); | |||
101 | #endif | |||
102 | if (uio->uio_offset < 0) | |||
103 | return (EINVAL22); | |||
104 | if (uio->uio_resid == 0) | |||
105 | return (0); | |||
106 | ||||
107 | for (error = 0, bp = NULL((void *)0); uio->uio_resid > 0; bp = NULL((void *)0)) { | |||
108 | if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0) | |||
109 | break; | |||
110 | lbn = lblkno(fs, uio->uio_offset)((uio->uio_offset) >> (fs)->e2fs_bshift); | |||
111 | nextlbn = lbn + 1; | |||
112 | size = fs->e2fs_bsize; | |||
113 | blkoffset = blkoff(fs, uio->uio_offset)((uio->uio_offset) & (fs)->e2fs_qbmask); | |||
114 | xfersize = fs->e2fs_bsize - blkoffset; | |||
115 | if (uio->uio_resid < xfersize) | |||
116 | xfersize = uio->uio_resid; | |||
117 | if (bytesinfile < xfersize) | |||
118 | xfersize = bytesinfile; | |||
119 | ||||
120 | if (lblktosize(fs, nextlbn)((nextlbn) << (fs)->e2fs_bshift) >= ext2fs_size(ip)) | |||
121 | error = bread(vp, lbn, size, &bp); | |||
122 | else if (lbn - 1 == ip->i_ci.ci_lastr) { | |||
123 | int nextsize = fs->e2fs_bsize; | |||
124 | error = breadn(vp, lbn, size, &nextlbn, &nextsize, | |||
125 | 1, &bp); | |||
126 | } else | |||
127 | error = bread(vp, lbn, size, &bp); | |||
128 | if (error) | |||
129 | break; | |||
130 | ip->i_ci.ci_lastr = lbn; | |||
131 | ||||
132 | /* | |||
133 | * We should only get non-zero b_resid when an I/O error | |||
134 | * has occurred, which should cause us to break above. | |||
135 | * However, if the short read did not cause an error, | |||
136 | * then we want to ensure that we do not uiomove bad | |||
137 | * or uninitialized data. | |||
138 | */ | |||
139 | size -= bp->b_resid; | |||
140 | if (size < xfersize) { | |||
141 | if (size == 0) | |||
142 | break; | |||
143 | xfersize = size; | |||
144 | } | |||
145 | error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio); | |||
146 | if (error) | |||
147 | break; | |||
148 | brelse(bp); | |||
149 | } | |||
150 | if (bp != NULL((void *)0)) | |||
151 | brelse(bp); | |||
152 | ||||
153 | if (!(vp->v_mount->mnt_flag & MNT_NOATIME0x00008000)) { | |||
154 | ip->i_flag |= IN_ACCESS0x0001; | |||
155 | } | |||
156 | return (error); | |||
157 | } | |||
158 | ||||
159 | int | |||
160 | ext4_ext_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs, struct uio *uio) | |||
161 | { | |||
162 | struct ext4_extent_path path; | |||
163 | struct ext4_extent nex, *ep; | |||
164 | struct buf *bp; | |||
165 | daddr_t lbn, pos; | |||
166 | off_t bytesinfile; | |||
167 | int size, xfersize, blkoffset; | |||
168 | int error, cache_type; | |||
169 | ||||
170 | memset(&path, 0, sizeof path)__builtin_memset((&path), (0), (sizeof path)); | |||
171 | ||||
172 | if (uio->uio_offset < 0) | |||
173 | return (EINVAL22); | |||
174 | if (uio->uio_resid == 0) | |||
175 | return (0); | |||
176 | ||||
177 | while (uio->uio_resid
| |||
178 | if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0) | |||
179 | break; | |||
180 | lbn = lblkno(fs, uio->uio_offset)((uio->uio_offset) >> (fs)->e2fs_bshift); | |||
181 | size = fs->e2fs_bsize; | |||
182 | blkoffset = blkoff(fs, uio->uio_offset)((uio->uio_offset) & (fs)->e2fs_qbmask); | |||
183 | ||||
184 | xfersize = fs->e2fs_fsize - blkoffset; | |||
185 | xfersize = MIN(xfersize, uio->uio_resid)(((xfersize)<(uio->uio_resid))?(xfersize):(uio->uio_resid )); | |||
186 | xfersize = MIN(xfersize, bytesinfile)(((xfersize)<(bytesinfile))?(xfersize):(bytesinfile)); | |||
187 | ||||
188 | cache_type = ext4_ext_in_cache(ip, lbn, &nex); | |||
189 | switch (cache_type) { | |||
190 | case EXT4_EXT_CACHE_NO0: | |||
191 | ext4_ext_find_extent(fs, ip, lbn, &path); | |||
192 | if ((ep = path.ep_ext) == NULL((void *)0)) | |||
193 | return (EIO5); | |||
194 | ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN2); | |||
195 | ||||
196 | pos = lbn - ep->e_blk + (((daddr_t) ep->e_start_hi << 32) | ep->e_start_lo); | |||
197 | if (path.ep_bp != NULL((void *)0)) { | |||
198 | brelse(path.ep_bp); | |||
199 | path.ep_bp = NULL((void *)0); | |||
200 | } | |||
201 | break; | |||
202 | case EXT4_EXT_CACHE_GAP1: | |||
203 | /* block has not been allocated yet */ | |||
204 | return (0); | |||
205 | case EXT4_EXT_CACHE_IN2: | |||
206 | pos = lbn - nex.e_blk + (((daddr_t) nex.e_start_hi << 32) | nex.e_start_lo); | |||
207 | break; | |||
208 | } | |||
209 | error = bread(ip->i_devvpi_ump->um_devvp, fsbtodb(fs, pos)((pos) << (fs)->e2fs_fsbtodb), size, &bp); | |||
| ||||
210 | if (error) { | |||
211 | brelse(bp); | |||
212 | return (error); | |||
213 | } | |||
214 | size -= bp->b_resid; | |||
215 | if (size < xfersize) { | |||
216 | if (size == 0) { | |||
217 | brelse(bp); | |||
218 | break; | |||
219 | } | |||
220 | xfersize = size; | |||
221 | } | |||
222 | error = uiomove(bp->b_data + blkoffset, xfersize, uio); | |||
223 | brelse(bp); | |||
224 | if (error) | |||
225 | return (error); | |||
226 | } | |||
227 | return (0); | |||
228 | } | |||
229 | ||||
230 | /* | |||
231 | * Vnode op for writing. | |||
232 | */ | |||
233 | int | |||
234 | ext2fs_write(void *v) | |||
235 | { | |||
236 | struct vop_write_args *ap = v; | |||
237 | struct vnode *vp; | |||
238 | struct uio *uio; | |||
239 | struct inode *ip; | |||
240 | struct m_ext2fs *fs; | |||
241 | struct buf *bp; | |||
242 | int32_t lbn; | |||
243 | off_t osize; | |||
244 | int blkoffset, error, extended, flags, ioflag, size, xfersize; | |||
245 | size_t resid; | |||
246 | ssize_t overrun; | |||
247 | ||||
248 | extended = 0; | |||
249 | ioflag = ap->a_ioflag; | |||
250 | uio = ap->a_uio; | |||
251 | vp = ap->a_vp; | |||
252 | ip = VTOI(vp)((struct inode *)(vp)->v_data); | |||
253 | ||||
254 | #ifdef DIAGNOSTIC1 | |||
255 | if (uio->uio_rw != UIO_WRITE) | |||
256 | panic("%s: mode", "ext2fs_write"); | |||
257 | #endif | |||
258 | ||||
259 | /* | |||
260 | * If writing 0 bytes, succeed and do not change | |||
261 | * update time or file offset (standards compliance) | |||
262 | */ | |||
263 | if (uio->uio_resid == 0) | |||
264 | return (0); | |||
265 | ||||
266 | switch (vp->v_type) { | |||
267 | case VREG: | |||
268 | if (ioflag & IO_APPEND0x02) | |||
269 | uio->uio_offset = ext2fs_size(ip); | |||
270 | if ((ip->i_e2fs_flagsdinode_u.e2fs_din->e2di_flags & EXT2_APPEND0x00000020) && | |||
271 | uio->uio_offset != ext2fs_size(ip)) | |||
272 | return (EPERM1); | |||
273 | /* FALLTHROUGH */ | |||
274 | case VLNK: | |||
275 | break; | |||
276 | case VDIR: | |||
277 | if ((ioflag & IO_SYNC0x04) == 0) | |||
278 | panic("%s: nonsync dir write", "ext2fs_write"); | |||
279 | break; | |||
280 | default: | |||
281 | panic("%s: type", "ext2fs_write"); | |||
282 | } | |||
283 | ||||
284 | fs = ip->i_e2fsinode_u.e2fs; | |||
285 | if (e2fs_overflow(fs, uio->uio_resid, uio->uio_offset + uio->uio_resid)) | |||
286 | return (EFBIG27); | |||
287 | ||||
288 | /* do the filesize rlimit check */ | |||
289 | if ((error = vn_fsizechk(vp, uio, ioflag, &overrun))) | |||
290 | return (error); | |||
291 | ||||
292 | resid = uio->uio_resid; | |||
293 | osize = ext2fs_size(ip); | |||
294 | flags = ioflag & IO_SYNC0x04 ? B_SYNC0x02 : 0; | |||
295 | ||||
296 | for (error = 0; uio->uio_resid > 0;) { | |||
297 | lbn = lblkno(fs, uio->uio_offset)((uio->uio_offset) >> (fs)->e2fs_bshift); | |||
298 | blkoffset = blkoff(fs, uio->uio_offset)((uio->uio_offset) & (fs)->e2fs_qbmask); | |||
299 | xfersize = fs->e2fs_bsize - blkoffset; | |||
300 | if (uio->uio_resid < xfersize) | |||
301 | xfersize = uio->uio_resid; | |||
302 | if (fs->e2fs_bsize > xfersize) | |||
303 | flags |= B_CLRBUF0x01; | |||
304 | else | |||
305 | flags &= ~B_CLRBUF0x01; | |||
306 | ||||
307 | error = ext2fs_buf_alloc(ip, | |||
308 | lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); | |||
309 | if (error) | |||
310 | break; | |||
311 | if (uio->uio_offset + xfersize > ext2fs_size(ip)) { | |||
312 | error = ext2fs_setsize(ip, uio->uio_offset + xfersize); | |||
313 | if (error) | |||
314 | break; | |||
315 | uvm_vnp_setsize(vp, ext2fs_size(ip)); | |||
316 | extended = 1; | |||
317 | } | |||
318 | uvm_vnp_uncache(vp); | |||
319 | ||||
320 | size = fs->e2fs_bsize - bp->b_resid; | |||
321 | if (size < xfersize) | |||
322 | xfersize = size; | |||
323 | ||||
324 | error = uiomove(bp->b_data + blkoffset, xfersize, uio); | |||
325 | /* | |||
326 | * If the buffer is not already filled and we encounter an | |||
327 | * error while trying to fill it, we have to clear out any | |||
328 | * garbage data from the pages instantiated for the buffer. | |||
329 | * If we do not, a failed uiomove() during a write can leave | |||
330 | * the prior contents of the pages exposed to a userland mmap. | |||
331 | * | |||
332 | * Note that we don't need to clear buffers that were | |||
333 | * allocated with the B_CLRBUF flag set. | |||
334 | */ | |||
335 | if (error != 0 && !(flags & B_CLRBUF0x01)) | |||
336 | memset(bp->b_data + blkoffset, 0, xfersize)__builtin_memset((bp->b_data + blkoffset), (0), (xfersize) ); | |||
337 | ||||
338 | if (ioflag & IO_NOCACHE0x40) | |||
339 | bp->b_flags |= B_NOCACHE0x00001000; | |||
340 | ||||
341 | if (ioflag & IO_SYNC0x04) | |||
342 | (void)bwrite(bp); | |||
343 | else if (xfersize + blkoffset == fs->e2fs_bsize) | |||
344 | bawrite(bp); | |||
345 | else | |||
346 | bdwrite(bp); | |||
347 | if (error || xfersize == 0) | |||
348 | break; | |||
349 | ip->i_flag |= IN_CHANGE0x0002 | IN_UPDATE0x0004; | |||
350 | } | |||
351 | /* | |||
352 | * If we successfully wrote any data, and we are not the superuser | |||
353 | * we clear the setuid and setgid bits as a precaution against | |||
354 | * tampering. | |||
355 | */ | |||
356 | if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0) | |||
357 | ip->i_e2fs_modedinode_u.e2fs_din->e2di_mode &= ~(ISUID0004000 | ISGID0002000); | |||
358 | if (resid > uio->uio_resid) | |||
359 | VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0))knote_locked(&vp->v_klist, (0x0002 | (extended ? 0x0004 : 0))); | |||
360 | if (error) { | |||
361 | if (ioflag & IO_UNIT0x01) { | |||
362 | (void)ext2fs_truncate(ip, osize, | |||
363 | ioflag & IO_SYNC0x04, ap->a_cred); | |||
364 | uio->uio_offset -= resid - uio->uio_resid; | |||
365 | uio->uio_resid = resid; | |||
366 | } | |||
367 | } else if (resid > uio->uio_resid && (ioflag & IO_SYNC0x04)) { | |||
368 | error = ext2fs_update(ip, 1); | |||
369 | } | |||
370 | /* correct the result for writes clamped by vn_fsizechk() */ | |||
371 | uio->uio_resid += overrun; | |||
372 | return (error); | |||
373 | } |