11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 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 * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/crc32.h> 171da177e4SLinus Torvalds #include <linux/pagemap.h> 181da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 191da177e4SLinus Torvalds #include <linux/compiler.h> 201da177e4SLinus Torvalds #include "nodelist.h" 211da177e4SLinus Torvalds #include "compr.h" 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 241da177e4SLinus Torvalds struct jffs2_full_dnode *fd, unsigned char *buf, 251da177e4SLinus Torvalds int ofs, int len) 261da177e4SLinus Torvalds { 271da177e4SLinus Torvalds struct jffs2_raw_inode *ri; 281da177e4SLinus Torvalds size_t readlen; 291da177e4SLinus Torvalds uint32_t crc; 301da177e4SLinus Torvalds unsigned char *decomprbuf = NULL; 311da177e4SLinus Torvalds unsigned char *readbuf = NULL; 321da177e4SLinus Torvalds int ret = 0; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds ri = jffs2_alloc_raw_inode(); 351da177e4SLinus Torvalds if (!ri) 361da177e4SLinus Torvalds return -ENOMEM; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri); 391da177e4SLinus Torvalds if (ret) { 401da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 411da177e4SLinus Torvalds printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret); 421da177e4SLinus Torvalds return ret; 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds if (readlen != sizeof(*ri)) { 451da177e4SLinus Torvalds jffs2_free_raw_inode(ri); 461da177e4SLinus Torvalds printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", 471da177e4SLinus Torvalds ref_offset(fd->raw), sizeof(*ri), readlen); 481da177e4SLinus Torvalds return -EIO; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds crc = crc32(0, ri, sizeof(*ri)-8); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", 531da177e4SLinus Torvalds ref_offset(fd->raw), je32_to_cpu(ri->node_crc), 541da177e4SLinus Torvalds crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), 551da177e4SLinus Torvalds je32_to_cpu(ri->offset), buf)); 561da177e4SLinus Torvalds if (crc != je32_to_cpu(ri->node_crc)) { 571da177e4SLinus Torvalds printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", 581da177e4SLinus Torvalds je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); 591da177e4SLinus Torvalds ret = -EIO; 601da177e4SLinus Torvalds goto out_ri; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds /* There was a bug where we wrote hole nodes out with csize/dsize 631da177e4SLinus Torvalds swapped. Deal with it */ 641da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && 651da177e4SLinus Torvalds je32_to_cpu(ri->csize)) { 661da177e4SLinus Torvalds ri->dsize = ri->csize; 671da177e4SLinus Torvalds ri->csize = cpu_to_je32(0); 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds D1(if(ofs + len > je32_to_cpu(ri->dsize)) { 711da177e4SLinus Torvalds printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", 721da177e4SLinus Torvalds len, ofs, je32_to_cpu(ri->dsize)); 731da177e4SLinus Torvalds ret = -EINVAL; 741da177e4SLinus Torvalds goto out_ri; 751da177e4SLinus Torvalds }); 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_ZERO) { 791da177e4SLinus Torvalds memset(buf, 0, len); 801da177e4SLinus Torvalds goto out_ri; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* Cases: 841da177e4SLinus Torvalds Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. 851da177e4SLinus Torvalds Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided 861da177e4SLinus Torvalds Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy 871da177e4SLinus Torvalds Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy 881da177e4SLinus Torvalds */ 891da177e4SLinus Torvalds if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { 901da177e4SLinus Torvalds readbuf = buf; 911da177e4SLinus Torvalds } else { 921da177e4SLinus Torvalds readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); 931da177e4SLinus Torvalds if (!readbuf) { 941da177e4SLinus Torvalds ret = -ENOMEM; 951da177e4SLinus Torvalds goto out_ri; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds if (ri->compr != JFFS2_COMPR_NONE) { 991da177e4SLinus Torvalds if (len < je32_to_cpu(ri->dsize)) { 1001da177e4SLinus Torvalds decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); 1011da177e4SLinus Torvalds if (!decomprbuf) { 1021da177e4SLinus Torvalds ret = -ENOMEM; 1031da177e4SLinus Torvalds goto out_readbuf; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds } else { 1061da177e4SLinus Torvalds decomprbuf = buf; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds } else { 1091da177e4SLinus Torvalds decomprbuf = readbuf; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize), 1131da177e4SLinus Torvalds readbuf)); 1141da177e4SLinus Torvalds ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), 1151da177e4SLinus Torvalds je32_to_cpu(ri->csize), &readlen, readbuf); 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds if (!ret && readlen != je32_to_cpu(ri->csize)) 1181da177e4SLinus Torvalds ret = -EIO; 1191da177e4SLinus Torvalds if (ret) 1201da177e4SLinus Torvalds goto out_decomprbuf; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds crc = crc32(0, readbuf, je32_to_cpu(ri->csize)); 1231da177e4SLinus Torvalds if (crc != je32_to_cpu(ri->data_crc)) { 1241da177e4SLinus Torvalds printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", 1251da177e4SLinus Torvalds je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); 1261da177e4SLinus Torvalds ret = -EIO; 1271da177e4SLinus Torvalds goto out_decomprbuf; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); 1301da177e4SLinus Torvalds if (ri->compr != JFFS2_COMPR_NONE) { 1311da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", 1321da177e4SLinus Torvalds je32_to_cpu(ri->csize), readbuf, 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) { 1351da177e4SLinus Torvalds printk(KERN_WARNING "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 1621da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n", 1631da177e4SLinus Torvalds 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. */ 1691da177e4SLinus Torvalds /* Now we're pointing at the first frag which overlaps our page */ 1701da177e4SLinus Torvalds while(offset < end) { 1711da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); 1721da177e4SLinus Torvalds if (unlikely(!frag || frag->ofs > offset)) { 1731da177e4SLinus Torvalds uint32_t holesize = end - offset; 1741da177e4SLinus Torvalds if (frag) { 1751da177e4SLinus Torvalds D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); 1761da177e4SLinus Torvalds holesize = min(holesize, frag->ofs - offset); 1771da177e4SLinus Torvalds D2(jffs2_print_frag_list(f)); 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); 1801da177e4SLinus Torvalds memset(buf, 0, holesize); 1811da177e4SLinus Torvalds buf += holesize; 1821da177e4SLinus Torvalds offset += holesize; 1831da177e4SLinus Torvalds continue; 1841da177e4SLinus Torvalds } else if (unlikely(!frag->node)) { 1851da177e4SLinus Torvalds uint32_t holeend = min(end, frag->ofs + frag->size); 1861da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); 1871da177e4SLinus Torvalds memset(buf, 0, holeend - offset); 1881da177e4SLinus Torvalds buf += holeend - offset; 1891da177e4SLinus Torvalds offset = holeend; 1901da177e4SLinus Torvalds frag = frag_next(frag); 1911da177e4SLinus Torvalds continue; 1921da177e4SLinus Torvalds } else { 1931da177e4SLinus Torvalds uint32_t readlen; 1941da177e4SLinus Torvalds uint32_t fragofs; /* offset within the frag to start reading */ 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds fragofs = offset - frag->ofs; 1971da177e4SLinus Torvalds readlen = min(frag->size - fragofs, end - offset); 1981da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", 1991da177e4SLinus Torvalds frag->ofs+fragofs, frag->ofs+fragofs+readlen, 2001da177e4SLinus Torvalds ref_offset(frag->node->raw), ref_flags(frag->node->raw))); 2011da177e4SLinus Torvalds ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); 2021da177e4SLinus Torvalds D2(printk(KERN_DEBUG "node read done\n")); 2031da177e4SLinus Torvalds if (ret) { 2041da177e4SLinus Torvalds D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret)); 2051da177e4SLinus Torvalds memset(buf, 0, readlen); 2061da177e4SLinus Torvalds return ret; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds buf += readlen; 2091da177e4SLinus Torvalds offset += readlen; 2101da177e4SLinus Torvalds frag = frag_next(frag); 2111da177e4SLinus Torvalds D2(printk(KERN_DEBUG "node read was OK. Looping\n")); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds return 0; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* Core function to read symlink target. */ 2181da177e4SLinus Torvalds char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds char *buf; 2211da177e4SLinus Torvalds int ret; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds down(&f->sem); 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds if (!f->metadata) { 2261da177e4SLinus Torvalds printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); 2271da177e4SLinus Torvalds up(&f->sem); 2281da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds buf = kmalloc(f->metadata->size+1, GFP_USER); 2311da177e4SLinus Torvalds if (!buf) { 2321da177e4SLinus Torvalds up(&f->sem); 2331da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds buf[f->metadata->size]=0; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds up(&f->sem); 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds if (ret) { 2421da177e4SLinus Torvalds kfree(buf); 2431da177e4SLinus Torvalds return ERR_PTR(ret); 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds return buf; 2461da177e4SLinus Torvalds } 247