Skip to content

Commit

Permalink
Merge pull request #236 from magnusja/fix/corrupted-files
Browse files Browse the repository at this point in the history
Fix/corrupted files
  • Loading branch information
magnusja authored Dec 9, 2019
2 parents 77e5e01 + b8ccfce commit adbbf4e
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class FileBlockDeviceDriver : BlockDeviceDriver {
override fun read(deviceOffset: Long, buffer: ByteBuffer) {
file.seek(deviceOffset * blockSize + byteOffset)
val read = file.read(buffer.array(), buffer.position(), buffer.remaining())

if (read == -1) {
throw IOException("EOF")
}

buffer.position(buffer.position() + read)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import java.nio.ByteBuffer
import android.util.Log

import com.github.mjdev.libaums.driver.BlockDeviceDriver
import kotlin.math.max
import kotlin.math.min

/**
* This class represents a cluster chain which can be followed in the FAT of a
Expand Down Expand Up @@ -182,7 +184,7 @@ internal constructor(startCluster: Long, private val blockDevice: BlockDeviceDri
// directly in the cluster
if (offset % clusterSize != 0L) {
val clusterOffset = (offset % clusterSize).toInt()
val size = Math.min(length, (clusterSize - clusterOffset).toInt())
val size = min(length, (clusterSize - clusterOffset).toInt())
source.limit(source.position() + size)

blockDevice.write(getFileSystemOffset(chain[chainIndex], clusterOffset), source)
Expand All @@ -193,26 +195,37 @@ internal constructor(startCluster: Long, private val blockDevice: BlockDeviceDri
length -= size
}

var remainingClusters = (length / clusterSize).toInt()
var remainingClusters = length / clusterSize

// now we can proceed reading the clusters without an offset in the
// cluster
while (length > 0) {
val size: Int
var clusters = 1
var numberOfClusters = 1

// We can only write consecutive clusters, see tests failing in
// https://github.com/magnusja/libaums/pull/236/commits/a4cfe0c57401f922beec849e706b68d94cad3248
var maxConsecutiveClusters = 1
for (i in chainIndex until chain.size - 1) {
if (chain[i] + 1 == chain[i + 1]) {
maxConsecutiveClusters++
} else {
break
}
}
// we write multiple clusters at a time, to speed up the write performance enormously
// currently only 4 or fewer clusters are written at the same time. Set this value too high may cause problems
maxConsecutiveClusters = min(maxConsecutiveClusters, 4)
when {
remainingClusters > 4 -> {
size = (clusterSize * 4).toInt()
clusters = 4
remainingClusters -= 4
remainingClusters > maxConsecutiveClusters -> {
size = (clusterSize * maxConsecutiveClusters).toInt()
numberOfClusters = maxConsecutiveClusters
remainingClusters -= maxConsecutiveClusters
}
remainingClusters > 0 -> {
size = (clusterSize * remainingClusters).toInt()
clusters = remainingClusters
remainingClusters = 0
size = (clusterSize * min(remainingClusters.toInt(), maxConsecutiveClusters)).toInt()
numberOfClusters = min(remainingClusters.toInt(), maxConsecutiveClusters)
remainingClusters -= numberOfClusters
}
else -> size = length
}
Expand All @@ -221,7 +234,7 @@ internal constructor(startCluster: Long, private val blockDevice: BlockDeviceDri

blockDevice.write(getFileSystemOffset(chain[chainIndex], 0), source)

chainIndex += clusters
chainIndex += numberOfClusters
length -= size
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ internal constructor(
*/
@Throws(IOException::class)
private fun init() {
if (!isRoot) {
if (!::chain.isInitialized) {
chain = ClusterChain(entry!!.startCluster, blockDevice, fat, bootSector)
}

Expand Down
62 changes: 62 additions & 0 deletions libaums/src/test/java/com/github/mjdev/libaums/fs/UsbFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,32 @@ public void write() throws Exception {
assertEquals(numberOfFiles + 3, root.listFiles().length);
}

@ContractTest
public void writeWithLength() throws Exception {

int numberOfFiles = root.listFiles().length;

URL bigFileUrl = new URL(expectedValues.get("bigFileToWrite").asString());

UsbFile bigFileLargeBuffer = root.createFile("bigwritetestlargebuffer");
bigFileLargeBuffer.setLength(29876);
copyLarge(bigFileUrl.openStream(),
new UsbFileOutputStream(bigFileLargeBuffer), new byte[7 * 32768]);


assertTrue(IOUtils.contentEquals(bigFileUrl.openStream(), new UsbFileInputStream(bigFileLargeBuffer)));

newInstance();

UsbFile bigFile = root.search("bigwritetestlargebuffer");

assertEquals(bigFileLargeBuffer.getLength(), bigFile.getLength());

assertTrue(IOUtils.contentEquals(bigFileUrl.openStream(), new UsbFileInputStream(bigFile)));

assertEquals(numberOfFiles + 1, root.listFiles().length);
}

@ContractTest
public void flush() throws Exception {
// TODO
Expand Down Expand Up @@ -731,7 +757,43 @@ public void equals() throws Exception {
checkEqualsRecursive(root);
}

@ContractTest
public void createLotsOfFiles() throws IOException {
UsbFile dir = root.createDirectory("test_lots_of_files");
List<String> nameList = new ArrayList<>();

for(int i = 0; i < 600; i++) {
String name = String.format("IMG_09082016_%06d", i);
nameList.add(name);
dir.createFile(name);
}
assertEquals(nameList.size(), dir.list().length);
assertArrayEquals(nameList.toArray(new String[0]), dir.list());

for(int j = 0; j < 12; j++) {
dir = root.createDirectory("test_lots_of_files_" + j);

for(int i = 0; i < 600; i++) {
String name = String.format("IMG_09082016_%06d", i);
dir.createFile(name);
}
assertEquals(nameList.size(), dir.list().length);
assertArrayEquals(nameList.toArray(new String[0]), dir.list());
}

newInstance();

dir = root.search("test_lots_of_files");

assertEquals(nameList.size(), dir.list().length);
assertArrayEquals(nameList.toArray(new String[0]), dir.list());

for(int j = 0; j < 12; j++) {
dir = root.search("test_lots_of_files_" + j);
assertEquals(nameList.size(), dir.list().length);
assertArrayEquals(nameList.toArray(new String[0]), dir.list());
}
}

@ContractTest
public void testIssue187() throws IOException {
Expand Down

0 comments on commit adbbf4e

Please sign in to comment.