hashing of files

pull/4/head
Zlatin Balevsky 2018-07-18 19:18:22 +01:00
parent 82cc664fa2
commit f9631e1a4a
2 changed files with 110 additions and 1 deletions

View File

@ -1,5 +1,11 @@
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 {
/** max size of shared file is 128 GB */
@ -21,4 +27,43 @@ class FileHasher {
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)
}
}

View File

@ -2,10 +2,26 @@ package com.muwire.core
import static org.junit.jupiter.api.Assertions.assertEquals
import org.junit.After
import org.junit.Before
import org.junit.Test
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
void testPieceSize() {
assert 18 == FileHasher.getPieceSize(1000000)
@ -14,6 +30,54 @@ class FileHasherTest extends GroovyTestCase {
shouldFail IllegalArgumentException, {
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
}
}