summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java8
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java10
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java67
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java40
4 files changed, 125 insertions, 0 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java
new file mode 100644
index 0000000..34ad9a0
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierFactory.java
@@ -0,0 +1,8 @@
+package com.keuin.kbackupfabric.util.backup.incremental.identifier;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface FileIdentifierFactory<T extends ObjectIdentifier> {
+ T fromFile(File file) throws IOException;
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java
new file mode 100644
index 0000000..62798e1
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java
@@ -0,0 +1,10 @@
+package com.keuin.kbackupfabric.util.backup.incremental.identifier;
+
+/**
+ * The identifier distinguishing files in the object collection.
+ * It should be based on cryptographic hash function in order to prevent possible attacks to the backup system.
+ * All identifiers should be immutable and implement their own equals method.
+ */
+public interface ObjectIdentifier {
+ String getIdentification();
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
new file mode 100644
index 0000000..9f56b0e
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
@@ -0,0 +1,67 @@
+package com.keuin.kbackupfabric.util.backup.incremental.identifier;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
+
+public class Sha256Identifier extends SingleHashIdentifier {
+
+ private static final int SHA256_LENGTH = 32;
+ private static final Sha256Identifier DUMMY = new Sha256Identifier(new byte[SHA256_LENGTH]); // only for using its hash method
+ private static final FileIdentifierFactory<Sha256Identifier> factory = Sha256Identifier::fromFile;
+
+ public static Sha256Identifier fromFile(File file) throws IOException {
+ if (!Objects.requireNonNull(file).isFile()) {
+ throw new IllegalArgumentException("file is not a file");
+ }
+ return new Sha256Identifier(DUMMY.hash(file));
+ }
+
+ public static FileIdentifierFactory<Sha256Identifier> getFactory() {
+ return factory;
+ }
+
+ protected Sha256Identifier(byte[] hash) {
+ super(hash);
+ Objects.requireNonNull(hash);
+ if (hash.length != SHA256_LENGTH) {
+ throw new IllegalStateException(String.format("SHA256 must be %d bytes", SHA256_LENGTH));
+ }
+ }
+
+ @Override
+ protected byte[] hash(File file) throws IOException {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+
+ FileInputStream inputStream = new FileInputStream(file);
+
+ // This does not work. I don't know why
+// FileChannel channel = inputStream.getChannel();
+// ByteBuffer buffer = ByteBuffer.allocate(128);
+// int readLength;
+// while ((readLength = channel.read(buffer)) > 0)
+// digest.update(buffer);
+
+ // This also works, without warnings
+ byte[] readBuffer = new byte[1024 * 1024];
+ int readLength;
+ while ((readLength = inputStream.read(readBuffer)) > 0)
+ digest.update(readBuffer,0, readLength);
+
+ // The below lines also works, but the IDE will complain about the while loop
+// DigestInputStream digestInputStream = new DigestInputStream(inputStream, digest);
+// while(digestInputStream.read() > 0)
+// ;
+
+ return digest.digest();
+ } catch (NoSuchAlgorithmException ignored) {
+ // this shouldn't happen
+ return new byte[SHA256_LENGTH];
+ }
+ }
+
+}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java
new file mode 100644
index 0000000..62ba47c
--- /dev/null
+++ b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java
@@ -0,0 +1,40 @@
+package com.keuin.kbackupfabric.util.backup.incremental.identifier;
+
+import com.keuin.kbackupfabric.util.BytesUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * A simple identifier based on a single hash function.
+ */
+public abstract class SingleHashIdentifier implements ObjectIdentifier {
+
+ private final byte[] hash;
+
+ protected SingleHashIdentifier(byte[] hash) {
+ this.hash = Arrays.copyOf(hash, hash.length);
+ }
+
+ /**
+ * The hash function.
+ *
+ * @param file the file to be hashed.
+ * @return the hash bytes.
+ */
+ protected abstract byte[] hash(File file) throws IOException;
+
+ @Override
+ public String getIdentification() {
+ return BytesUtil.bytesToHex(hash);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SingleHashIdentifier)) {
+ return false;
+ }
+ return Arrays.equals(hash, ((SingleHashIdentifier) obj).hash);
+ }
+}