Revision: 5910 http://jnode.svn.sourceforge.net/jnode/?rev=5910&view=rev Author: galatnm Date: 2012-08-10 06:36:07 +0000 (Fri, 10 Aug 2012) Log Message: ----------- Add initial support for ext4 extents
Modified Paths: -------------- trunk/fs/src/fs/org/jnode/fs/ext2/INode.java Added Paths: ----------- trunk/fs/src/fs/org/jnode/fs/ext2/Extent.java trunk/fs/src/fs/org/jnode/fs/ext2/ExtentHeader.java trunk/fs/src/fs/org/jnode/fs/ext2/ExtentIndex.java Added: trunk/fs/src/fs/org/jnode/fs/ext2/Extent.java =================================================================== --- trunk/fs/src/fs/org/jnode/fs/ext2/Extent.java (rev 0) +++ trunk/fs/src/fs/org/jnode/fs/ext2/Extent.java 2012-08-10 06:36:07 UTC (rev 5910) @@ -0,0 +1,44 @@ +package org.jnode.fs.ext2; + +/** + * An ext4 extent object. + * + * @author Luke Quinane + */ +public class Extent { + /** + * The length of an extent. + */ + public static final int EXTENT_LENGTH = 12; + + /** + * The data for the extent. + */ + private byte[] data; + + /** + * Create an extent object. + * + * @param data the data for the extent. + */ + public Extent(byte[] data) { + this.data = new byte[EXTENT_LENGTH]; + System.arraycopy(data, 0, this.data, 0, EXTENT_LENGTH); + } + + public long getBlockIndex() { + return Ext2Utils.get32(data, 0); + } + + public int getBlockCount() { + return Ext2Utils.get16(data, 4); + } + + public long getStartLow() { + return Ext2Utils.get32(data, 8); + } + + public int getStartHigh() { + return Ext2Utils.get16(data, 6); + } +} Added: trunk/fs/src/fs/org/jnode/fs/ext2/ExtentHeader.java =================================================================== --- trunk/fs/src/fs/org/jnode/fs/ext2/ExtentHeader.java (rev 0) +++ trunk/fs/src/fs/org/jnode/fs/ext2/ExtentHeader.java 2012-08-10 06:36:07 UTC (rev 5910) @@ -0,0 +1,134 @@ +package org.jnode.fs.ext2; + +import java.io.IOException; + +/** + * An ext4 extent header. + * + * @author Luke Quinane + */ +public class ExtentHeader { + /** + * The length of an extent header. + */ + public static final int EXTENT_HEADER_LENGTH = 12; + + /** + * The magic number for an extent header. + */ + public static final int MAGIC = 0xf30a; + + /** + * The data for the header. + */ + private byte[] data; + + /** + * The cache copy of the index entries. + */ + private ExtentIndex[] indexEntries; + + /** + * The cache copy of the extent entries. + */ + private Extent[] extentEntries; + + /** + * Create an extent header object. + */ + public ExtentHeader(byte[] data) throws IOException { + this.data = new byte[data.length]; + System.arraycopy(data, 0, this.data, 0, data.length); + + if (getMagic() != ExtentHeader.MAGIC) { + throw new IOException("Extent had the wrong magic: " + getMagic()); + } + } + + public int getMagic() { + return Ext2Utils.get16(data, 0); + } + + public int getEntryCount() { + return Ext2Utils.get16(data, 2); + } + + public int getMaximumEntryCount() { + return Ext2Utils.get16(data, 4); + } + + public int getDepth() { + return Ext2Utils.get16(data, 6); + } + + public ExtentIndex[] getIndexEntries() { + if (getDepth() == 0) { + throw new IllegalStateException("Trying to read index entries from a leaf."); + } + + if (indexEntries == null) { + indexEntries = new ExtentIndex[getEntryCount()]; + int offset = EXTENT_HEADER_LENGTH; + + for (int i = 0; i < getEntryCount(); i++) { + byte[] indexBuffer = new byte[ExtentIndex.EXTENT_INDEX_LENGTH]; + System.arraycopy(data, offset, indexBuffer, 0, indexBuffer.length); + + indexEntries[i] = new ExtentIndex(indexBuffer); + offset += ExtentIndex.EXTENT_INDEX_LENGTH; + } + } + + return indexEntries; + } + + public Extent[] getExtentEntries() { + if (getDepth() != 0) { + throw new IllegalStateException("Trying to read extent entries from a non-leaf."); + } + + if (extentEntries == null) { + extentEntries = new Extent[getEntryCount()]; + int offset = EXTENT_HEADER_LENGTH; + + for (int i = 0; i < getEntryCount(); i++) { + byte[] indexBuffer = new byte[Extent.EXTENT_LENGTH]; + System.arraycopy(data, offset, indexBuffer, 0, indexBuffer.length); + + extentEntries[i] = new Extent(indexBuffer); + offset += Extent.EXTENT_LENGTH; + } + } + + return extentEntries; + } + + public long getBlockNumber(long index) { + if (getDepth() > 0) { + ExtentIndex[] indexes = getIndexEntries(); + + throw new UnsupportedOperationException(); + } + else { + Extent[] extents = getExtentEntries(); + + int lowIndex = 0; + int highIndex = extents.length - 1; + Extent extent = null; + + while (lowIndex <= highIndex) { + int middle = lowIndex + (highIndex - lowIndex) / 2; + extent = extents[middle]; + + if (index < extent.getBlockIndex()) { + highIndex = middle - 1; + } + else { + lowIndex = middle + 1; + } + } + + return extent.getStartLow(); + } + } +} Added: trunk/fs/src/fs/org/jnode/fs/ext2/ExtentIndex.java =================================================================== --- trunk/fs/src/fs/org/jnode/fs/ext2/ExtentIndex.java (rev 0) +++ trunk/fs/src/fs/org/jnode/fs/ext2/ExtentIndex.java 2012-08-10 06:36:07 UTC (rev 5910) @@ -0,0 +1,40 @@ +package org.jnode.fs.ext2; + +/** + * An ext4 extent index. + * + * @author Luke Quinane + */ +public class ExtentIndex { + /** + * The length of an extent index. + */ + public static final int EXTENT_INDEX_LENGTH = 12; + + /** + * The data for the index. + */ + private byte[] data; + + /** + * Create an extent index object. + * + * @param data the data for the index. + */ + public ExtentIndex(byte[] data) { + this.data = new byte[EXTENT_INDEX_LENGTH]; + System.arraycopy(data, 0, this.data, 0, EXTENT_INDEX_LENGTH); + } + + public long getBlockIndex() { + return Ext2Utils.get32(data, 0); + } + + public long getLeafLow() { + return Ext2Utils.get32(data, 4); + } + + public int getLeafHigh() { + return Ext2Utils.get16(data, 8); + } +} Modified: trunk/fs/src/fs/org/jnode/fs/ext2/INode.java =================================================================== --- trunk/fs/src/fs/org/jnode/fs/ext2/INode.java 2012-08-10 06:32:22 UTC (rev 5909) +++ trunk/fs/src/fs/org/jnode/fs/ext2/INode.java 2012-08-10 06:36:07 UTC (rev 5910) @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.Arrays; - import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.jnode.fs.FileSystemException; @@ -60,6 +59,11 @@ private Ext2FileSystem fs; /** + * The cached extent header. + */ + private ExtentHeader extentHeader; + + /** * Create an INode object from an existing inode on the disk. * * @param fs @@ -280,6 +284,36 @@ * @throws IOException */ private long getDataBlockNr(long i) throws IOException { + if ((getFlags() & Ext2Constants.EXT4_INODE_EXTENTS_FLAG) != 0) { + if (extentHeader == null) { + byte[] headerBuffer = new byte[64]; + System.arraycopy(data, 40, headerBuffer, 0, headerBuffer.length); + + extentHeader = new ExtentHeader(headerBuffer); + } + + return extentHeader.getBlockNumber(i); + } + else { + return getDataBlockNrIndirect(i); + } + } + + /** + * Return the number of the block in the filesystem that stores the ith + * block of the inode (i is a sequential index from the beginning of the + * file) using an indirect (ext2 / ext3) lookup. + * + * [Naming convention used: in the code, a <code>...BlockNr</code> always + * means an absolute block nr (of the filesystem), while a + * <code>...BlockIndex</code> means an index relative to the beginning of + * a block] + * + * @param i + * @return the block number + * @throws IOException + */ + private long getDataBlockNrIndirect(long i) throws IOException { final long blockCount = getAllocatedBlockCount(); final int indirectCount = getIndirectCount(); if (i > blockCount - 1) { @@ -910,6 +944,10 @@ public void setDirty(boolean b) { dirty = b; + + if (dirty) { + extentHeader = null; + } } public synchronized boolean isLocked() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ Jnode-svn-commits mailing list Jnode-svn-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits