Blame view
fs/jffs2/read.c
6.73 KB
1da177e4c
|
1 2 3 |
/* * JFFS2 -- Journalling Flash File System, Version 2. * |
c00c310ea
|
4 |
* Copyright © 2001-2007 Red Hat, Inc. |
1da177e4c
|
5 6 7 8 9 |
* * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * |
1da177e4c
|
10 |
*/ |
5a528957e
|
11 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c
|
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/crc32.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> #include <linux/compiler.h> #include "nodelist.h" #include "compr.h" int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len) { struct jffs2_raw_inode *ri; size_t readlen; uint32_t crc; unsigned char *decomprbuf = NULL; unsigned char *readbuf = NULL; int ret = 0; ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri); if (ret) { jffs2_free_raw_inode(ri); |
da320f055
|
39 40 41 |
pr_warn("Error reading node from 0x%08x: %d ", ref_offset(fd->raw), ret); |
1da177e4c
|
42 43 44 45 |
return ret; } if (readlen != sizeof(*ri)) { jffs2_free_raw_inode(ri); |
da320f055
|
46 47 48 |
pr_warn("Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx ", ref_offset(fd->raw), sizeof(*ri), readlen); |
1da177e4c
|
49 50 51 |
return -EIO; } crc = crc32(0, ri, sizeof(*ri)-8); |
9c261b33a
|
52 53 |
jffs2_dbg(1, "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p ", |
1da177e4c
|
54 55 |
ref_offset(fd->raw), je32_to_cpu(ri->node_crc), crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), |
9c261b33a
|
56 |
je32_to_cpu(ri->offset), buf); |
1da177e4c
|
57 |
if (crc != je32_to_cpu(ri->node_crc)) { |
da320f055
|
58 59 60 |
pr_warn("Node CRC %08x != calculated CRC %08x for node at %08x ", je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); |
1da177e4c
|
61 62 63 64 65 |
ret = -EIO; goto out_ri; } /* There was a bug where we wrote hole nodes out with csize/dsize swapped. Deal with it */ |
182ec4eee
|
66 |
if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && |
1da177e4c
|
67 68 69 70 71 72 |
je32_to_cpu(ri->csize)) { ri->dsize = ri->csize; ri->csize = cpu_to_je32(0); } D1(if(ofs + len > je32_to_cpu(ri->dsize)) { |
da320f055
|
73 74 75 |
pr_warn("jffs2_read_dnode() asked for %d bytes at %d from %d-byte node ", len, ofs, je32_to_cpu(ri->dsize)); |
1da177e4c
|
76 77 78 |
ret = -EINVAL; goto out_ri; }); |
182ec4eee
|
79 |
|
1da177e4c
|
80 81 82 83 84 85 86 |
if (ri->compr == JFFS2_COMPR_ZERO) { memset(buf, 0, len); goto out_ri; } /* Cases: Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. |
182ec4eee
|
87 88 |
Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy |
1da177e4c
|
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy */ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { readbuf = buf; } else { readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); if (!readbuf) { ret = -ENOMEM; goto out_ri; } } if (ri->compr != JFFS2_COMPR_NONE) { if (len < je32_to_cpu(ri->dsize)) { decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); if (!decomprbuf) { ret = -ENOMEM; goto out_readbuf; } } else { decomprbuf = buf; } } else { decomprbuf = readbuf; } |
9c261b33a
|
113 114 115 |
jffs2_dbg(2, "Read %d bytes to %p ", je32_to_cpu(ri->csize), readbuf); |
1da177e4c
|
116 117 118 119 120 121 122 123 124 125 |
ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), je32_to_cpu(ri->csize), &readlen, readbuf); if (!ret && readlen != je32_to_cpu(ri->csize)) ret = -EIO; if (ret) goto out_decomprbuf; crc = crc32(0, readbuf, je32_to_cpu(ri->csize)); if (crc != je32_to_cpu(ri->data_crc)) { |
da320f055
|
126 127 128 |
pr_warn("Data CRC %08x != calculated CRC %08x for node at %08x ", je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); |
1da177e4c
|
129 130 131 |
ret = -EIO; goto out_decomprbuf; } |
9c261b33a
|
132 133 |
jffs2_dbg(2, "Data CRC matches calculated CRC %08x ", crc); |
1da177e4c
|
134 |
if (ri->compr != JFFS2_COMPR_NONE) { |
9c261b33a
|
135 136 137 138 |
jffs2_dbg(2, "Decompress %d bytes from %p to %d bytes at %p ", je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf); |
1da177e4c
|
139 140 |
ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); if (ret) { |
da320f055
|
141 142 |
pr_warn("Error: jffs2_decompress returned %d ", ret); |
1da177e4c
|
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
goto out_decomprbuf; } } if (len < je32_to_cpu(ri->dsize)) { memcpy(buf, decomprbuf+ofs, len); } out_decomprbuf: if(decomprbuf != buf && decomprbuf != readbuf) kfree(decomprbuf); out_readbuf: if(readbuf != buf) kfree(readbuf); out_ri: jffs2_free_raw_inode(ri); return ret; } int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, unsigned char *buf, uint32_t offset, uint32_t len) { uint32_t end = offset + len; struct jffs2_node_frag *frag; int ret; |
9c261b33a
|
168 169 170 |
jffs2_dbg(1, "%s(): ino #%u, range 0x%08x-0x%08x ", __func__, f->inocache->ino, offset, offset + len); |
1da177e4c
|
171 172 173 174 175 |
frag = jffs2_lookup_node_frag(&f->fragtree, offset); /* XXX FIXME: Where a single physical node actually shows up in two frags, we read it twice. Don't do that. */ |
199bc9ff5
|
176 177 178 |
/* Now we're pointing at the first frag which overlaps our page * (or perhaps is before it, if we've been asked to read off the * end of the file). */ |
1da177e4c
|
179 |
while(offset < end) { |
9c261b33a
|
180 181 182 |
jffs2_dbg(2, "%s(): offset %d, end %d ", __func__, offset, end); |
199bc9ff5
|
183 184 |
if (unlikely(!frag || frag->ofs > offset || frag->ofs + frag->size <= offset)) { |
1da177e4c
|
185 |
uint32_t holesize = end - offset; |
199bc9ff5
|
186 |
if (frag && frag->ofs > offset) { |
9c261b33a
|
187 188 189 |
jffs2_dbg(1, "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x ", f->inocache->ino, frag->ofs, offset); |
1da177e4c
|
190 |
holesize = min(holesize, frag->ofs - offset); |
1da177e4c
|
191 |
} |
9c261b33a
|
192 193 194 |
jffs2_dbg(1, "Filling non-frag hole from %d-%d ", offset, offset + holesize); |
1da177e4c
|
195 196 197 198 199 200 |
memset(buf, 0, holesize); buf += holesize; offset += holesize; continue; } else if (unlikely(!frag->node)) { uint32_t holeend = min(end, frag->ofs + frag->size); |
9c261b33a
|
201 202 203 204 |
jffs2_dbg(1, "Filling frag hole from %d-%d (frag 0x%x 0x%x) ", offset, holeend, frag->ofs, frag->ofs + frag->size); |
1da177e4c
|
205 206 207 208 209 210 211 212 |
memset(buf, 0, holeend - offset); buf += holeend - offset; offset = holeend; frag = frag_next(frag); continue; } else { uint32_t readlen; uint32_t fragofs; /* offset within the frag to start reading */ |
182ec4eee
|
213 |
|
1da177e4c
|
214 215 |
fragofs = offset - frag->ofs; readlen = min(frag->size - fragofs, end - offset); |
9c261b33a
|
216 217 218 219 220 221 |
jffs2_dbg(1, "Reading %d-%d from node at 0x%08x (%d) ", frag->ofs+fragofs, frag->ofs + fragofs+readlen, ref_offset(frag->node->raw), ref_flags(frag->node->raw)); |
1da177e4c
|
222 |
ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); |
9c261b33a
|
223 224 |
jffs2_dbg(2, "node read done "); |
1da177e4c
|
225 |
if (ret) { |
9c261b33a
|
226 227 228 |
jffs2_dbg(1, "%s(): error %d ", __func__, ret); |
1da177e4c
|
229 230 231 232 233 234 |
memset(buf, 0, readlen); return ret; } buf += readlen; offset += readlen; frag = frag_next(frag); |
9c261b33a
|
235 236 |
jffs2_dbg(2, "node read was OK. Looping "); |
1da177e4c
|
237 238 239 240 |
} } return 0; } |