hashing of files
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
package com.muwire.core
|
package com.muwire.core
|
||||||
|
|
||||||
|
import java.nio.MappedByteBuffer
|
||||||
|
import java.nio.channels.FileChannel
|
||||||
|
import java.nio.channels.FileChannel.MapMode
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.NoSuchAlgorithmException
|
||||||
|
|
||||||
class FileHasher {
|
class FileHasher {
|
||||||
|
|
||||||
/** max size of shared file is 128 GB */
|
/** max size of shared file is 128 GB */
|
||||||
@@ -21,4 +27,43 @@ class FileHasher {
|
|||||||
|
|
||||||
throw new IllegalArgumentException("File too large $size")
|
throw new IllegalArgumentException("File too large $size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final MessageDigest digest
|
||||||
|
|
||||||
|
FileHasher() {
|
||||||
|
try {
|
||||||
|
digest = MessageDigest.getInstance("SHA-256")
|
||||||
|
} catch (NoSuchAlgorithmException impossible) {
|
||||||
|
digest = null
|
||||||
|
System.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoHash hashFile(File file) {
|
||||||
|
final long length = file.length()
|
||||||
|
final int size = 0x1 << getPieceSize(length)
|
||||||
|
int numPieces = (int) (length / size)
|
||||||
|
if (numPieces * size < length)
|
||||||
|
numPieces++
|
||||||
|
|
||||||
|
def output = new ByteArrayOutputStream()
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(file, "r")
|
||||||
|
try {
|
||||||
|
MappedByteBuffer buf
|
||||||
|
for (int i = 0; i < numPieces - 1; i++) {
|
||||||
|
buf = raf.getChannel().map(MapMode.READ_ONLY, size * i, size)
|
||||||
|
digest.update buf
|
||||||
|
output.write(digest.digest(), 0, 32)
|
||||||
|
}
|
||||||
|
def lastPieceLength = length - (numPieces - 1) * size
|
||||||
|
buf = raf.getChannel().map(MapMode.READ_ONLY, length - lastPieceLength, lastPieceLength)
|
||||||
|
digest.update buf
|
||||||
|
output.write(digest.digest(), 0, 32)
|
||||||
|
} finally {
|
||||||
|
raf.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
byte [] hashList = output.toByteArray()
|
||||||
|
InfoHash.fromHashList(hashList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,26 @@ package com.muwire.core
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals
|
import static org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class FileHasherTest extends GroovyTestCase {
|
class FileHasherTest extends GroovyTestCase {
|
||||||
|
|
||||||
|
def hasher = new FileHasher()
|
||||||
|
File tmp
|
||||||
|
|
||||||
|
@Before
|
||||||
|
void setUp() {
|
||||||
|
tmp = File.createTempFile("testFile", "test")
|
||||||
|
tmp.deleteOnExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
void tearDown() {
|
||||||
|
tmp?.delete()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPieceSize() {
|
void testPieceSize() {
|
||||||
assert 18 == FileHasher.getPieceSize(1000000)
|
assert 18 == FileHasher.getPieceSize(1000000)
|
||||||
@@ -14,6 +30,54 @@ class FileHasherTest extends GroovyTestCase {
|
|||||||
shouldFail IllegalArgumentException, {
|
shouldFail IllegalArgumentException, {
|
||||||
FileHasher.getPieceSize(Long.MAX_VALUE)
|
FileHasher.getPieceSize(Long.MAX_VALUE)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHash1Byte() {
|
||||||
|
def fos = new FileOutputStream(tmp)
|
||||||
|
fos.write(0)
|
||||||
|
fos.close()
|
||||||
|
def ih = hasher.hashFile(tmp)
|
||||||
|
assert ih.getHashList().length == 32
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHash1PieceExact() {
|
||||||
|
def fos = new FileOutputStream(tmp)
|
||||||
|
byte [] b = new byte[ 0x1 << 18]
|
||||||
|
fos.write b
|
||||||
|
fos.close()
|
||||||
|
def ih = hasher.hashFile tmp
|
||||||
|
assert ih.getHashList().length == 32
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHash1Piece1Byte() {
|
||||||
|
def fos = new FileOutputStream(tmp)
|
||||||
|
byte [] b = new byte[ (0x1 << 18) + 1]
|
||||||
|
fos.write b
|
||||||
|
fos.close()
|
||||||
|
def ih = hasher.hashFile tmp
|
||||||
|
assert ih.getHashList().length == 64
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHash2Pieces() {
|
||||||
|
def fos = new FileOutputStream(tmp)
|
||||||
|
byte [] b = new byte[ (0x1 << 19)]
|
||||||
|
fos.write b
|
||||||
|
fos.close()
|
||||||
|
def ih = hasher.hashFile tmp
|
||||||
|
assert ih.getHashList().length == 64
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHash2Pieces2Bytes() {
|
||||||
|
def fos = new FileOutputStream(tmp)
|
||||||
|
byte [] b = new byte[ (0x1 << 19) + 2]
|
||||||
|
fos.write b
|
||||||
|
fos.close()
|
||||||
|
def ih = hasher.hashFile tmp
|
||||||
|
assert ih.getHashList().length == 32 * 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user