|
From: <ga...@us...> - 2012-08-10 06:36:13
|
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.
|