11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/crc32.h> 151da177e4SLinus Torvalds #include <linux/pagemap.h> 161da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 171da177e4SLinus Torvalds #include <linux/compiler.h> 181da177e4SLinus Torvalds #include "nodelist.h" 191da177e4SLinus Torvalds #include "compr.h" 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 221da177e4SLinus Torvalds struct jffs2_full_dnode *fd, unsigned char *buf, 231da177e4SLinus Torvalds int ofs, int len) 241da177e4SLinus Torvalds { 251da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 261da177e4SLinus Torvalds size_t readlen; 271da177e4SLinus Torvalds uint32_t crc; 281da177e4SLinus Torvalds unsigned char *decomprbuf = NULL; 291da177e4SLinus Torvalds unsigned char *readbuf = NULL; 301da177e4SLinus Torvalds int ret = 0; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 331da177e4SLinus Torvalds if (!ri) 341da177e4SLinus Torvalds return -ENOMEM; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri); 371da177e4SLinus Torvalds if (ret) { 381da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 39da320f05SJoe Perches pr_warn("Error reading node from 0x%08x: %d\n", 40da320f05SJoe Perches ref_offset(fd->raw), ret); 411da177e4SLinus Torvalds return ret; 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds if (readlen != sizeof(*ri)) { 441da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 45da320f05SJoe Perches pr_warn("Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", 461da177e4SLinus Torvalds ref_offset(fd->raw), sizeof(*ri), readlen); 471da177e4SLinus Torvalds return -EIO; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds crc = crc32(0, ri, sizeof(*ri)-8); 501da177e4SLinus Torvalds 519c261b33SJoe Perches jffs2_dbg(1, "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", 521da177e4SLinus Torvalds ref_offset(fd->raw), je32_to_cpu(ri->node_crc), 531da177e4SLinus Torvalds crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), 549c261b33SJoe Perches je32_to_cpu(ri->offset), buf); 551da177e4SLinus Torvalds if (crc != je32_to_cpu(ri->node_crc)) { 56da320f05SJoe Perches pr_warn("Node CRC %08x != calculated CRC %08x for node at %08x\n", 571da177e4SLinus Torvalds je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); 581da177e4SLinus Torvalds ret = -EIO; 591da177e4SLinus Torvalds goto out_ri; 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds /* There was a bug where we wrote hole nodes out with csize/dsize 621da177e4SLinus Torvalds swapped. Deal with it */ 631da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && 641da177e4SLinus Torvalds je32_to_cpu(ri->csize)) { 651da177e4SLinus Torvalds ri->dsize = ri->csize; 661da177e4SLinus Torvalds ri->csize = cpu_to_je32(0); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds D1(if(ofs + len > je32_to_cpu(ri->dsize)) { 70da320f05SJoe Perches pr_warn("jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", 711da177e4SLinus Torvalds len, ofs, je32_to_cpu(ri->dsize)); 721da177e4SLinus Torvalds ret = -EINVAL; 731da177e4SLinus Torvalds goto out_ri; 741da177e4SLinus Torvalds }); 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_ZERO) { 781da177e4SLinus Torvalds memset(buf, 0, len); 791da177e4SLinus Torvalds goto out_ri; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* Cases: 831da177e4SLinus Torvalds Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. 841da177e4SLinus Torvalds Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided 851da177e4SLinus Torvalds Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy 861da177e4SLinus Torvalds Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { 891da177e4SLinus Torvalds readbuf = buf; 901da177e4SLinus Torvalds } else { 911da177e4SLinus Torvalds readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); 921da177e4SLinus Torvalds if (!readbuf) { 931da177e4SLinus Torvalds ret = -ENOMEM; 941da177e4SLinus Torvalds goto out_ri; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds if (ri->compr != JFFS2_COMPR_NONE) { 981da177e4SLinus Torvalds if (len < je32_to_cpu(ri->dsize)) { 991da177e4SLinus Torvalds decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); 1001da177e4SLinus Torvalds if (!decomprbuf) { 1011da177e4SLinus Torvalds ret = -ENOMEM; 1021da177e4SLinus Torvalds goto out_readbuf; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds } else { 1051da177e4SLinus Torvalds decomprbuf = buf; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds } else { 1081da177e4SLinus Torvalds decomprbuf = readbuf; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1119c261b33SJoe Perches jffs2_dbg(2, "Read %d bytes to %p\n", je32_to_cpu(ri->csize), 1129c261b33SJoe Perches readbuf); 1131da177e4SLinus Torvalds ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), 1141da177e4SLinus Torvalds je32_to_cpu(ri->csize), &readlen, readbuf); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds if (!ret && readlen != je32_to_cpu(ri->csize)) 1171da177e4SLinus Torvalds ret = -EIO; 1181da177e4SLinus Torvalds if (ret) 1191da177e4SLinus Torvalds goto out_decomprbuf; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds crc = crc32(0, readbuf, je32_to_cpu(ri->csize)); 1221da177e4SLinus Torvalds if (crc != je32_to_cpu(ri->data_crc)) { 123da320f05SJoe Perches pr_warn("Data CRC %08x != calculated CRC %08x for node at %08x\n", 1241da177e4SLinus Torvalds je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); 1251da177e4SLinus Torvalds ret = -EIO; 1261da177e4SLinus Torvalds goto out_decomprbuf; 1271da177e4SLinus Torvalds } 1289c261b33SJoe Perches jffs2_dbg(2, "Data CRC matches calculated CRC %08x\n", crc); 1291da177e4SLinus Torvalds if (ri->compr != JFFS2_COMPR_NONE) { 1309c261b33SJoe Perches jffs2_dbg(2, "Decompress %d bytes from %p to %d bytes at %p\n", 1319c261b33SJoe Perches je32_to_cpu(ri->csize), readbuf, 1329c261b33SJoe Perches je32_to_cpu(ri->dsize), decomprbuf); 1331da177e4SLinus Torvalds ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); 1341da177e4SLinus Torvalds if (ret) { 135da320f05SJoe Perches pr_warn("Error: jffs2_decompress returned %d\n", ret); 1361da177e4SLinus Torvalds goto out_decomprbuf; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds if (len < je32_to_cpu(ri->dsize)) { 1411da177e4SLinus Torvalds memcpy(buf, decomprbuf+ofs, len); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds out_decomprbuf: 1441da177e4SLinus Torvalds if(decomprbuf != buf && decomprbuf != readbuf) 1451da177e4SLinus Torvalds kfree(decomprbuf); 1461da177e4SLinus Torvalds out_readbuf: 1471da177e4SLinus Torvalds if(readbuf != buf) 1481da177e4SLinus Torvalds kfree(readbuf); 1491da177e4SLinus Torvalds out_ri: 1501da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds return ret; 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 1561da177e4SLinus Torvalds unsigned char *buf, uint32_t offset, uint32_t len) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds uint32_t end = offset + len; 1591da177e4SLinus Torvalds struct jffs2_node_frag *frag; 1601da177e4SLinus Torvalds int ret; 1611da177e4SLinus Torvalds 1629c261b33SJoe Perches jffs2_dbg(1, "%s(): ino #%u, range 0x%08x-0x%08x\n", 1639c261b33SJoe Perches __func__, f->inocache->ino, offset, offset + len); 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds frag = jffs2_lookup_node_frag(&f->fragtree, offset); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* XXX FIXME: Where a single physical node actually shows up in two 1681da177e4SLinus Torvalds frags, we read it twice. Don't do that. */ 169199bc9ffSDavid Woodhouse /* Now we're pointing at the first frag which overlaps our page 170199bc9ffSDavid Woodhouse * (or perhaps is before it, if we've been asked to read off the 171199bc9ffSDavid Woodhouse * end of the file). */ 1721da177e4SLinus Torvalds while(offset < end) { 1739c261b33SJoe Perches jffs2_dbg(2, "%s(): offset %d, end %d\n", 1749c261b33SJoe Perches __func__, offset, end); 175199bc9ffSDavid Woodhouse if (unlikely(!frag || frag->ofs > offset || 176199bc9ffSDavid Woodhouse frag->ofs + frag->size <= offset)) { 1771da177e4SLinus Torvalds uint32_t holesize = end - offset; 178199bc9ffSDavid Woodhouse if (frag && frag->ofs > offset) { 1799c261b33SJoe Perches jffs2_dbg(1, "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", 1809c261b33SJoe Perches f->inocache->ino, frag->ofs, offset); 1811da177e4SLinus Torvalds holesize = min(holesize, frag->ofs - offset); 1821da177e4SLinus Torvalds } 1839c261b33SJoe Perches jffs2_dbg(1, "Filling non-frag hole from %d-%d\n", 1849c261b33SJoe Perches offset, offset + holesize); 1851da177e4SLinus Torvalds memset(buf, 0, holesize); 1861da177e4SLinus Torvalds buf += holesize; 1871da177e4SLinus Torvalds offset += holesize; 1881da177e4SLinus Torvalds continue; 1891da177e4SLinus Torvalds } else if (unlikely(!frag->node)) { 1901da177e4SLinus Torvalds uint32_t holeend = min(end, frag->ofs + frag->size); 1919c261b33SJoe Perches jffs2_dbg(1, "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", 1929c261b33SJoe Perches offset, holeend, frag->ofs, 1939c261b33SJoe Perches frag->ofs + frag->size); 1941da177e4SLinus Torvalds memset(buf, 0, holeend - offset); 1951da177e4SLinus Torvalds buf += holeend - offset; 1961da177e4SLinus Torvalds offset = holeend; 1971da177e4SLinus Torvalds frag = frag_next(frag); 1981da177e4SLinus Torvalds continue; 1991da177e4SLinus Torvalds } else { 2001da177e4SLinus Torvalds uint32_t readlen; 2011da177e4SLinus Torvalds uint32_t fragofs; /* offset within the frag to start reading */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds fragofs = offset - frag->ofs; 2041da177e4SLinus Torvalds readlen = min(frag->size - fragofs, end - offset); 2059c261b33SJoe Perches jffs2_dbg(1, "Reading %d-%d from node at 0x%08x (%d)\n", 2069c261b33SJoe Perches frag->ofs+fragofs, 2079c261b33SJoe Perches frag->ofs + fragofs+readlen, 2089c261b33SJoe Perches ref_offset(frag->node->raw), 2099c261b33SJoe Perches ref_flags(frag->node->raw)); 2101da177e4SLinus Torvalds ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); 2119c261b33SJoe Perches jffs2_dbg(2, "node read done\n"); 2121da177e4SLinus Torvalds if (ret) { 2139c261b33SJoe Perches jffs2_dbg(1, "%s(): error %d\n", 2149c261b33SJoe Perches __func__, ret); 2151da177e4SLinus Torvalds memset(buf, 0, readlen); 2161da177e4SLinus Torvalds return ret; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds buf += readlen; 2191da177e4SLinus Torvalds offset += readlen; 2201da177e4SLinus Torvalds frag = frag_next(frag); 2219c261b33SJoe Perches jffs2_dbg(2, "node read was OK. Looping\n"); 2221da177e4SLinus Torvalds } 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds return 0; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 227