Skip to content

Commit

Permalink
External LZFSE patched in.
Browse files Browse the repository at this point in the history
  • Loading branch information
horrorho committed Jun 27, 2017
1 parent 230f4e5 commit 57d99e0
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@
*/
package com.github.horrorho.inflatabledonkey.file;

import com.github.horrorho.inflatabledonkey.io.DirectoryAssistant;
import com.github.horrorho.inflatabledonkey.args.Property;
import com.github.horrorho.inflatabledonkey.chunk.Chunk;
import com.github.horrorho.inflatabledonkey.data.backup.Asset;
import com.github.horrorho.inflatabledonkey.io.DirectoryAssistant;
import com.github.horrorho.inflatabledonkey.io.IOFunction;
import com.github.horrorho.inflatabledonkey.io.IOSupplier;
import com.github.horrorho.inflatabledonkey.io.IOSupplierSequenceStream;
import com.github.horrorho.inflatabledonkey.util.LZFSEExtInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
Expand All @@ -58,6 +62,8 @@ public final class FileAssembler

private static final Logger logger = LoggerFactory.getLogger(FileAssembler.class);

private static final Path LZFSE = Property.PATH_LZFSE.as(Paths::get).orElse(null);

private final Function<byte[], Optional<XFileKey>> fileKeys;
private final UnaryOperator<Optional<XFileKey>> mutator;
private final FilePath filePath;
Expand Down Expand Up @@ -113,29 +119,61 @@ boolean assemble(Asset asset, List<Chunk> chunks) {

boolean assemble(Path path, Asset asset, List<Chunk> chunks) {
String info = info(asset);
asset.contentCompressionMethod()
.ifPresent(u -> logger.info("-- assemble() - content compression method: {} {}", info, u));
asset.contentEncodingMethod()
.ifPresent(u -> logger.info("-- assemble() - content encoding method: {} {}", info, u));
return asset.encryptionKey()
.map(u -> decrypt(path, info, chunks, u, asset.fileChecksum()))
.orElseGet(() -> write(path, info, chunks, Optional.empty(), asset.fileChecksum()));
.map(u -> decrypt(path, info, chunks, u, asset.fileChecksum(), asset.contentCompressionMethod()))
.orElseGet(() -> write(path, info, chunks, Optional.empty(), asset.fileChecksum(), asset.contentCompressionMethod()));
}

boolean decrypt(Path path, String info, List<Chunk> chunks, byte[] encryptionKey, Optional<byte[]> signature) {
boolean decrypt(Path path,
String info,
List<Chunk> chunks,
byte[] encryptionKey,
Optional<byte[]> signature,
Optional<Integer> compression) {
return fileKeys.apply(encryptionKey)
.map(Optional::of)
.map(mutator)
.map(u -> write(path, info, chunks, u, signature))
.map(u -> write(path, info, chunks, u, signature, compression))
.orElseGet(() -> {
logger.warn("-- decrypt() - failed to unwrap encryption key");
return false;
});
}

boolean write(Path path, String info, List<Chunk> chunks, Optional<XFileKey> keyCipher, Optional<byte[]> signature) {
boolean write(Path path,
String info,
List<Chunk> chunks, Optional<XFileKey> keyCipher,
Optional<byte[]> signature,
Optional<Integer> compression) {
logger.debug("-- write() - path: {} key cipher: {} signature: 0x{}",
path, keyCipher, signature.map(Hex::toHexString).orElse("NULL"));

boolean status = true;
Optional<IOFunction<InputStream, InputStream>> decompress;
if (compression.isPresent()) {
if (compression.get() == 2) {
if (LZFSE == null) {
logger.warn("-- write() - no decompressor: {} -> {}", info, compression.get());
decompress = Optional.empty();
} else {
decompress = Optional.of(u -> LZFSEExtInputStream.create(LZFSE, u));
}
} else {
logger.warn("-- write() - unsupported compression: {} -> {}", info, compression.get());
decompress = Optional.empty();
}
} else {
decompress = Optional.empty();
}

try (OutputStream out = Files.newOutputStream(path);
InputStream in = chunkStream(chunks)) {
boolean status = FileStreamWriter.copy(in, out, keyCipher, signature);
status &= FileStreamWriter.copy(in, out, keyCipher, signature, decompress);
// status &= FileStreamWriter.copy(in, out, keyCipher, signature);

if (keyCipher.isPresent()) {
XFileKey kc = keyCipher.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package com.github.horrorho.inflatabledonkey.file;

import com.github.horrorho.inflatabledonkey.args.Property;
import com.github.horrorho.inflatabledonkey.io.IOFunction;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand Down Expand Up @@ -52,22 +53,47 @@ public final class FileStreamWriter {

private static final int BUFFER_SIZE = Property.FILE_WRITER_BUFFER_LENGTH.asInteger().orElse(8192);

public static boolean
copy(InputStream in, OutputStream out, Optional<XFileKey> keyCipher, Optional<byte[]> signature)
throws IOException {
public static boolean copy(InputStream in,
OutputStream out,
Optional<XFileKey> keyCipher,
Optional<byte[]> signature,
Optional<IOFunction<InputStream, InputStream>> decompress) throws IOException {

Digest digest = signature.flatMap(FileSignature::type)
.orElse(FileSignature.ONE)
.newDigest();

DigestInputStream digestInputStream = new DigestInputStream(in, digest);
DigestInputStream dis = new DigestInputStream(in, digest);

IOUtils.copyLarge(decryptStream(digestInputStream, keyCipher), out, new byte[BUFFER_SIZE]);
InputStream fis = decryptStream(dis, keyCipher);

if (decompress.isPresent()) {
logger.info("-- copy() - decompressing");
fis = decompress.get().apply(fis);
}

IOUtils.copyLarge(fis, out, new byte[BUFFER_SIZE]);
out.flush();

return testSignature(digestInputStream.getDigest(), signature);
return testSignature(dis.getDigest(), signature);
}

// public static boolean
// copy(InputStream in, OutputStream out, Optional<XFileKey> keyCipher, Optional<byte[]> signature)
// throws IOException {
//
// Digest digest = signature.flatMap(FileSignature::type)
// .orElse(FileSignature.ONE)
// .newDigest();
//
// DigestInputStream digestInputStream = new DigestInputStream(in, digest);
//
// IOUtils.copyLarge(decryptStream(digestInputStream, keyCipher), out, new byte[BUFFER_SIZE]);
// out.flush();
//
// return testSignature(digestInputStream.getDigest(), signature);
// }

static InputStream decryptStream(InputStream in, Optional<XFileKey> keyCipher) {
return keyCipher
.map(kc -> decryptStream(in, kc))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,38 @@ public static boolean truncate(Path path, Asset asset) {
try {
// Truncate if the final attribute size is different from the initial size (padded/ encrypted).
// Don't truncate if either optional is missing.
logger.debug("-- truncate() - path: {} asset: {}", path, asset);
asset.attributeSize()
.filter(u -> asset.size().map(t -> !Objects.equals(t, u)).orElse(false))
// .filter(u -> asset.sizeBeforeCopy().isPresent())
.filter(u -> !asset.contentCompressionMethod().isPresent())
.ifPresent(u -> FileTruncater.truncate(path, u));
return true;

} catch (UncheckedIOException ex) {
logger.warn("-- truncate() - UncheckedIOException: ", ex);
return false;
}
}

public static boolean checkSize(Path file, long size) {
try {
return Files.size(file) == size;
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}

public static void truncate(Path file, long to) throws UncheckedIOException {
try {
if (to <= 0) { // TODO consider: to < 0
return;
}

logger.info("-- truncate() - file: {} -> {}", file, to);
long size = Files.size(file);
if (size > to) {
Files.newByteChannel(file, WRITE)
.truncate(to)
.close();
logger.debug("-- truncate() - truncated: {}, {} > {}", file, size, to);

} else if (size < to) {
logger.warn("-- truncate() - cannot truncate: {}, {} > {}", file, size, to);
}
Expand Down

0 comments on commit 57d99e0

Please sign in to comment.