summaryrefslogtreecommitdiff
path: root/src/main/java/com/keuin/kbackupfabric/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/keuin/kbackupfabric/util')
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java92
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java32
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollection.java65
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java55
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java33
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectElement.java60
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java15
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java13
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java88
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java53
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/StorageObjectLoader.java25
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/incremental/manager/IncrementalBackupStorageManager.java188
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java64
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java37
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java33
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/provider/AvailableBackupProvider.java8
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/provider/IncrementalBackupInformation.java13
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/provider/PrimitiveBackupInformation.java14
-rw-r--r--src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java77
19 files changed, 0 insertions, 965 deletions
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
deleted file mode 100644
index 28ede70..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupFilesystemUtil.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.keuin.kbackupfabric.util.backup;
-
-import com.keuin.kbackupfabric.util.ReflectionUtils;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.dedicated.MinecraftDedicatedServer;
-import net.minecraft.server.world.ThreadedAnvilChunkStorage;
-import net.minecraft.world.World;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Functions deal with file name, directory name about Minecraft saves.
- */
-public final class BackupFilesystemUtil {
-
- private static final String BACKUP_SAVE_DIRECTORY_NAME = "backups";
- private static final String INCREMENTAL_BASE_DIRECTORY_NAME = "incremental";
- private static final String backupFileNamePrefix = "kbackup-";
-
- @Deprecated
- public static String getBackupFileNamePrefix() {
- return backupFileNamePrefix;
- }
-
-
-// @Deprecated
-// public static String getBackupName(String backupFileName) {
-// try {
-// if (backupFileName.matches(backupFileNamePrefix + ".+\\.zip"))
-// return backupFileName.substring(backupFileNamePrefix.length(), backupFileName.length() - 4);
-// } catch (IndexOutOfBoundsException ignored) {
-// }
-// return backupFileName;
-// }
-
- public static boolean isBackupFileExists(String backupFileName, MinecraftServer server) {
- File backupFile = new File(getBackupSaveDirectory(server), backupFileName);
- return backupFile.isFile();
- }
-
- public static File getBackupSaveDirectory(MinecraftServer server) {
- return new File(server.getRunDirectory(), BACKUP_SAVE_DIRECTORY_NAME);
- }
-
- public static File getIncrementalBackupBaseDirectory(MinecraftServer server) {
- return new File(server.getRunDirectory(), INCREMENTAL_BASE_DIRECTORY_NAME);
- }
-
- public static String getLevelPath(MinecraftServer server) throws IOException {
- if (!(server instanceof MinecraftDedicatedServer))
- throw new IllegalStateException("This plugin is server-side only.");
- String path = (new File(server.getRunDirectory().getCanonicalPath(), ((MinecraftDedicatedServer) server).getLevelName())).getAbsolutePath();
- Logger.getLogger("getLevelPath").info(String.format("Level path: %s", path));
- assert (new File(path)).exists();
- return path;
- }
-
- public static String getWorldDirectoryName(World world) throws NoSuchFieldException, IllegalAccessException {
- File saveDir;
- ThreadedAnvilChunkStorage threadedAnvilChunkStorage = (ThreadedAnvilChunkStorage) ReflectionUtils.getPrivateField(world.getChunkManager(), "threadedAnvilChunkStorage");
- saveDir = (File) ReflectionUtils.getPrivateField(threadedAnvilChunkStorage, "saveDir");
- return saveDir.getName();
- }
-
- @Deprecated
- public static long getBackupTimeFromBackupFileName(String backupFileName) {
- Matcher matcher = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2}").matcher(backupFileName);
- if (matcher.find()) {
- String timeString = matcher.group(0);
- long timeStamp = BackupNameTimeFormatter.timeStringToEpochSeconds(timeString);
- System.out.println(backupFileName + " -> " + timeStamp);
- return timeStamp;
- } else {
- System.err.println("Failed to extract time from " + backupFileName);
- }
- return -1;
- }
-
- public static String getFriendlyFileSizeString(long sizeBytes) {
- double fileSize = sizeBytes * 1.0 / 1024 / 1024; // Default unit is MB
- if (fileSize > 1000)
- //msgInfo(context, String.format("File size: %.2fGB", fileSize / 1024));
- return String.format("%.2fGB", fileSize / 1024);
- else
- //msgInfo(context, String.format("File size: %.2fMB", fileSize));
- return String.format("%.2fMB", fileSize);
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java b/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java
deleted file mode 100644
index 3811ae8..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/BackupNameTimeFormatter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.keuin.kbackupfabric.util.backup;
-
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-
-public class BackupNameTimeFormatter {
- private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
-
- @Deprecated
- public static String getTimeString() {
- return LocalDateTime.now().format(formatter);
- }
-
- public static String localDateTimeToString(LocalDateTime localDateTime) {
- return localDateTime.format(formatter);
- }
-
- @Deprecated
- public static long timeStringToEpochSeconds(String timeString) {
- ZoneId systemZone = ZoneId.systemDefault(); // my timezone
- LocalDateTime localDateTime = LocalDateTime.parse(timeString, formatter);
- ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(localDateTime);
- return localDateTime.toEpochSecond(currentOffsetForMyZone);
- }
-
- public static LocalDateTime timeStringToLocalDateTime(String timeString) {
- return LocalDateTime.parse(timeString,formatter);
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollection.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollection.java
deleted file mode 100644
index 16d95e6..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollection.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental;
-
-import java.io.Serializable;
-import java.util.*;
-
-public class ObjectCollection implements Serializable {
- private final String name;
- private final Map<String, ObjectElement> elements;
- private final Map<String, ObjectCollection> subCollections;
-
- ObjectCollection(String name, Set<ObjectElement> elements, Map<String, ObjectCollection> subCollections) {
- this.name = Objects.requireNonNull(name);
- this.elements = new HashMap<>();
- for (ObjectElement e : elements) {
- Objects.requireNonNull(e);
- if (this.elements.put(e.getName(), e) != null) {
- throw new IllegalStateException("elements conflict with the same name");
- }
- }
- this.subCollections = new HashMap<>(Objects.requireNonNull(subCollections));
- }
-
- public String getName() {
- return name;
- }
-
- public Set<ObjectElement> getElementSet() {
- return new HashSet<>(elements.values());
- }
-
- public Map<String, ObjectElement> getElementMap() {
- return Collections.unmodifiableMap(elements);
- }
-
- public ObjectElement getElement(String name) {
- return elements.get(name);
- }
-
- public Set<ObjectCollection> getSubCollectionSet() {
- return new HashSet<>(subCollections.values());
- }
-
- public Map<String, ObjectCollection> getSubCollectionMap() {
- return Collections.unmodifiableMap(subCollections);
- }
-
- public ObjectCollection getSubCollection(String name) {
- return subCollections.get(name);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ObjectCollection that = (ObjectCollection) o;
- return name.equals(that.name) &&
- elements.equals(that.elements) &&
- subCollections.equals(that.subCollections);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, elements, subCollections);
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
deleted file mode 100644
index 2f3761c..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionFactory.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental;
-
-import com.keuin.kbackupfabric.util.PrintUtil;
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.FileIdentifierProvider;
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.ObjectIdentifier;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.*;
-
-/**
- * Incremental backup is implemented as git-like file collection.
- * Files are called `objects`, the collection contains all files distinguished by their
- * identifiers. Usually, identifier is the combination of hash and other short information (such as size and another hash).
- * The identifier should use hashes that are strong enough, to prevent possible collisions.
- */
-public class ObjectCollectionFactory<T extends ObjectIdentifier> {
-
- private final FileIdentifierProvider<T> identifierFactory;
-
- public ObjectCollectionFactory(FileIdentifierProvider<T> identifierFactory) {
- this.identifierFactory = identifierFactory;
- }
-
- public ObjectCollection fromDirectory(File directory, Set<String> ignoredFiles) throws IOException {
- final Set<ObjectElement> subFiles = new HashSet<>();
- final Map<String, ObjectCollection> subCollections = new HashMap<>();
-
- if (!Objects.requireNonNull(directory).isDirectory())
- throw new IllegalArgumentException("given file is not a directory");
-
- for (Iterator<Path> iter = Files.walk(directory.toPath(), 1).iterator(); iter.hasNext(); ) {
- Path path = iter.next();
- if (Files.isSameFile(path, directory.toPath()))
- continue;
- File file = path.toFile();
- if (file.isDirectory()) {
- subCollections.put(file.getName(), fromDirectory(file, ignoredFiles));
- } else if (!ignoredFiles.contains(file.getName())) {
- subFiles.add(new ObjectElement(file.getName(), identifierFactory.fromFile(file)));
- } else {
- PrintUtil.info(String.format("Skipping file %s.", file.getName()));
- }
- }
-
- return new ObjectCollection(directory.getName(), subFiles, subCollections);
- }
-
- public ObjectCollection fromDirectory(File directory) throws IOException {
- return fromDirectory(directory, Collections.emptySet());
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java
deleted file mode 100644
index 6f9b792..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectCollectionSerializer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental;
-
-import java.io.*;
-import java.util.Objects;
-
-/**
- * Serialize and deserialize ObjectCollection from/to the disk file.
- */
-public class ObjectCollectionSerializer {
- public static ObjectCollection fromFile(File file) throws IOException {
- Objects.requireNonNull(file);
- ObjectCollection collection;
- try (FileInputStream fileInputStream = new FileInputStream(file)) {
- try (ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)) {
- collection = (ObjectCollection) objectInputStream.readObject();
- } catch (ClassNotFoundException ignored) {
- // this should not happen
- return null;
- }
- }
- return collection;
- }
-
- public static void toFile(ObjectCollection collection, File file) throws IOException {
- Objects.requireNonNull(collection);
- Objects.requireNonNull(file);
- try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
- try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
- objectOutputStream.writeObject(collection);
- }
- }
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectElement.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectElement.java
deleted file mode 100644
index cbb886e..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/ObjectElement.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental;
-
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.ObjectIdentifier;
-
-import java.io.Serializable;
-import java.util.Objects;
-
-/**
- * Representing a file in a ObjectCollection.
- * Immutable.
- */
-public class ObjectElement implements Serializable {
- private final String name;
- private final ObjectIdentifier identifier;
-
- public ObjectElement(String name, ObjectIdentifier identifier) {
- Objects.requireNonNull(name);
- Objects.requireNonNull(identifier);
- this.name = name;
- this.identifier = identifier;
- }
-
- /**
- * Get file name.
- * @return the file name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Get file identifier, which is considered to be different between files with different contents.
- * @return the identifier.
- */
- public ObjectIdentifier getIdentifier() {
- return identifier;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ObjectElement that = (ObjectElement) o;
- return name.equals(that.name) &&
- identifier.equals(that.identifier);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, identifier);
- }
-
- @Override
- public String toString() {
- return "ObjectElement{" +
- "name='" + name + '\'' +
- ", identifier=" + identifier +
- '}';
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java
deleted file mode 100644
index 3fbe284..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/FileIdentifierProvider.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental.identifier;
-
-import java.io.File;
-import java.io.IOException;
-
-public interface FileIdentifierProvider<T extends ObjectIdentifier> {
- /**
- * Generate file identifier from a random file. The file is not necessarily in the object base.
- *
- * @param file the file.
- * @return the file identifier.
- * @throws IOException when an I/O error occurs.
- */
- 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
deleted file mode 100644
index aece07d..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/ObjectIdentifier.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental.identifier;
-
-import java.io.Serializable;
-
-/**
- * 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.
- * Immutable.
- */
-public interface ObjectIdentifier extends Serializable {
- 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
deleted file mode 100644
index c1c87e1..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/Sha256Identifier.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental.identifier;
-
-import com.keuin.kbackupfabric.util.BytesUtil;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Objects;
-
-/**
- * Identifier based on sha256.
- * Immutable.
- */
-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 FileIdentifierProvider<Sha256Identifier> factory = Sha256Identifier::fromFile;
- private static final String marker = "S2";
-
- public static Sha256Identifier fromFile(File file) throws IOException {
- if (!file.isFile()) {
- throw new IllegalArgumentException("file is not a file");
- }
- return new Sha256Identifier(DUMMY.hash(file));
- }
-
- /**
- * Load sha-256 from a named file. Only used in StorageObjectLoader.
- *
- * @param fileName the file name.
- * @return identifier.
- */
- static Sha256Identifier fromFileName(String fileName) {
- if (!fileName.matches(marker + "-[0-9A-Fa-f]{32}"))
- return null;
- String hexString = fileName.substring(marker.length() + 1);
- return new Sha256Identifier(BytesUtil.hexToBytes(hexString));
- }
-
- public static FileIdentifierProvider<Sha256Identifier> getFactory() {
- return factory;
- }
-
- protected Sha256Identifier(byte[] hash) {
- super(hash, marker);
- 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");
-
- try (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
deleted file mode 100644
index 0f62f2b..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/SingleHashIdentifier.java
+++ /dev/null
@@ -1,53 +0,0 @@
-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;
-import java.util.Objects;
-
-/**
- * A simple identifier based on a single hash function.
- * Immutable.
- */
-public abstract class SingleHashIdentifier implements ObjectIdentifier {
-
- private final byte[] hash;
- private final String type;
-
- protected SingleHashIdentifier(byte[] hash, String type) {
- Objects.requireNonNull(hash);
- Objects.requireNonNull(type);
- this.hash = Arrays.copyOf(hash, hash.length);
- this.type = type;
- }
-
- /**
- * 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 type + "-" + BytesUtil.bytesToHex(hash);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof SingleHashIdentifier)) {
- return false;
- }
- return Arrays.equals(hash, ((SingleHashIdentifier) obj).hash);
- }
-
- @Override
- public int hashCode() {
- int result = Objects.hash(type);
- result = 31 * result + Arrays.hashCode(hash);
- return result;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/StorageObjectLoader.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/StorageObjectLoader.java
deleted file mode 100644
index 96bc295..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/identifier/StorageObjectLoader.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental.identifier;
-
-import java.io.File;
-import java.util.Objects;
-
-public class StorageObjectLoader {
- /**
- * Get identifier from storage file.
- *
- * @param file storage file.
- * @return identifier. If failed, return null.
- */
- public static ObjectIdentifier asIdentifier(File file) {
- Objects.requireNonNull(file);
- String fileName = file.getName();
- ObjectIdentifier identifier;
-
- identifier = Sha256Identifier.fromFileName(fileName);
- if (identifier != null)
- return identifier;
-
- // Add more identifiers.
- return null;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/manager/IncrementalBackupStorageManager.java b/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/manager/IncrementalBackupStorageManager.java
deleted file mode 100644
index 6fd339b..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/incremental/manager/IncrementalBackupStorageManager.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.incremental.manager;
-
-import com.keuin.kbackupfabric.util.PrintUtil;
-import com.keuin.kbackupfabric.util.backup.incremental.ObjectCollection;
-import com.keuin.kbackupfabric.util.backup.incremental.ObjectElement;
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.ObjectIdentifier;
-import com.keuin.kbackupfabric.util.backup.incremental.identifier.StorageObjectLoader;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-
-import static org.apache.commons.io.FileUtils.forceDelete;
-
-public class IncrementalBackupStorageManager {
-
- private final Path backupStorageBase;
- private final Map<ObjectIdentifier, File> map = new HashMap<>();
- private boolean loaded = false;
-
- public IncrementalBackupStorageManager(Path backupStorageBase) {
- this.backupStorageBase = backupStorageBase;
- }
-
- /**
- * Add a object collection to storage base.
- * @param collection the collection.
- * @return objects copied to the base.
- * @throws IOException I/O Error.
- */
- public int addObjectCollection(ObjectCollection collection, File collectionBasePath) throws IOException {
- if (!backupStorageBase.toFile().isDirectory()) {
- if (!backupStorageBase.toFile().mkdirs())
- throw new IOException("Backup storage base directory does not exist, and failed to create it.");
- }
- Objects.requireNonNull(collection);
- Objects.requireNonNull(collectionBasePath);
-
- int copyCount = 0;
-
- // copy sub files
- for (Map.Entry<String, ObjectElement> entry : collection.getElementMap().entrySet()) {
- File copyDestination = new File(backupStorageBase.toFile(), entry.getValue().getIdentifier().getIdentification());
- if (!baseContainsObject(entry.getValue())) {
- // element does not exist. copy.
- Files.copy(Paths.get(collectionBasePath.getAbsolutePath(), entry.getKey()), copyDestination.toPath());
- ++copyCount;
- }
- }
-
- //copy sub dirs recursively
- for (Map.Entry<String, ObjectCollection> entry : collection.getSubCollectionMap().entrySet()) {
- File newBase = new File(collectionBasePath, entry.getKey());
- copyCount += addObjectCollection(entry.getValue(), newBase);
- }
-
- return copyCount;
- }
-
- /**
- * Restore an object collection from the storage base. i.e., restore the save from backup storage.
- * @param collection the collection to be restored.
- * @param collectionBasePath save path of the collection.
- * @return objects restored from the base.
- * @throws IOException I/O Error.
- */
- public int restoreObjectCollection(ObjectCollection collection, File collectionBasePath) throws IOException {
- Objects.requireNonNull(collection);
- Objects.requireNonNull(collectionBasePath);
-
- int copyCount = 0;
-
- // touch directory
- if (!collectionBasePath.exists()) {
- int retryCounter = 0;
- boolean success = false;
- while (retryCounter++ < 5) {
- if (collectionBasePath.mkdirs()) {
- success = true;
- break;
- }
- }
- if (!success) {
- throw new IOException("Failed to create directory " + collectionBasePath.getAbsolutePath());
- }
- }
-
- // copy sub files
- for (Map.Entry<String, ObjectElement> entry : collection.getElementMap().entrySet()) {
- File copySource = new File(backupStorageBase.toFile(), entry.getValue().getIdentifier().getIdentification());
- File copyTarget = new File(collectionBasePath.getAbsolutePath(), entry.getKey());
-
- if (!baseContainsObject(entry.getValue())) {
- throw new IOException(String.format("File %s does not exist in the base.", copySource.getName()));
- }
- if (copyTarget.exists()) {
- boolean successDeleting = false;
- for (int i = 0; i < 5; ++i) {
- try {
- forceDelete(copyTarget);
- successDeleting = true;
- break;
- } catch (FileNotFoundException ignored) {
- break;
- } catch (IOException e) {
- PrintUtil.error(String.format("Failed to delete file %s, retry.", copyTarget.getName()));
- }
- }
- if (!successDeleting) {
- String msg = String.format("Failed to delete file %s.", copyTarget.getName());
- PrintUtil.error(msg);
- throw new IOException(msg);
- }
- }
-
- Files.copy(copySource.toPath(), copyTarget.toPath());
- ++copyCount;
- }
-
- //copy sub dirs recursively
- for (Map.Entry<String, ObjectCollection> entry : collection.getSubCollectionMap().entrySet()) {
- File newBase = new File(collectionBasePath, entry.getKey());
- copyCount += restoreObjectCollection(entry.getValue(), newBase);
- }
-
- return copyCount;
- }
-
- public int cleanUnusedObjects(Iterable<ObjectCollection> collectionIterable) {
- // construct object list in memory
- Set<String> objects = new HashSet<>();
-// backupStorageBase
-
- for (ObjectCollection collection : collectionIterable) {
- for (ObjectElement ele : collection.getElementMap().values()) {
-
- }
- }
- throw new RuntimeException("not impl");
- }
-
- /**
- * Check all objects, return unused ones.
- *
- * @return the unused ones.
- */
- private Map<ObjectIdentifier, File> markUnusedObjects() {
- throw new RuntimeException("not impl");
- }
-
- /**
- * Check if the backup base contains given element.
- *
- * @param objectElement the element.
- * @return true or false.
- */
- private boolean baseContainsObject(ObjectElement objectElement) {
- // This may be extended to use more variants of hash functions and combinations of other attributes (such as file size)
- return (new File(backupStorageBase.toFile(), objectElement.getIdentifier().getIdentification())).exists();
- }
-
- private void lazyLoadStorage() throws IOException {
- if (!loaded) {
- loadStorage();
- loaded = true;
- }
- }
-
- private synchronized void loadStorage() throws IOException {
- map.clear();
- Files.walk(backupStorageBase, 1).forEach(path -> {
- File file = path.toFile();
- ObjectIdentifier identifier = StorageObjectLoader.asIdentifier(file);
- if (identifier == null) {
- map.clear();
- throw new IllegalStateException(String.format(
- "Bad storage object %s: cannot recognize identifier.", file.getName()
- ));
- }
- map.put(identifier, file);
- });
- }
-
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java
deleted file mode 100644
index 8ebc7ff..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/name/BackupFileNameEncoder.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.name;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-
-/**
- * Encode and decode backup file name for a specific backup type.
- */
-public interface BackupFileNameEncoder {
-
- /**
- * Construct full backup file name from custom name and creation time.
- * @param customName the custom name. If the custom name contains invalid chars, an exception will be thrown.
- * @param time the creation time.
- * @return the file name.
- */
- String encode(String customName, LocalDateTime time);
-
- /**
- * Extract custom and backup time from backup file name.
- *
- * @param fileName the backup file name.
- * @return the information. If the given file name is invalid, return null.
- */
- BackupBasicInformation decode(String fileName);
-
- default boolean isValidFileName(String fileName) {
- return decode(fileName) != null;
- }
-
- /**
- * Check if the given string is a valid custom backup name.
- *
- * @param customName the custom backup name.
- * @return if the name is valid.
- */
- default boolean isValidCustomName(String customName) {
- final char[] ILLEGAL_CHARACTERS = {'/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':'};
- for (char c : ILLEGAL_CHARACTERS) {
- if (customName.contains(String.valueOf(c))) {
- return false;
- }
- }
- return true;
- }
-
- class BackupBasicInformation {
-
- public final String customName;
- public final LocalDateTime time;
-
- private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm.ss");
-
- protected BackupBasicInformation(String customName, LocalDateTime time) {
- this.customName = customName;
- this.time = time;
- }
-
- @Override
- public String toString() {
- return String.format("%s, %s", customName, time.format(formatter));
- }
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java
deleted file mode 100644
index 926f47c..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/name/IncrementalBackupFileNameEncoder.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.name;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class IncrementalBackupFileNameEncoder implements BackupFileNameEncoder {
- private static final String backupFileNamePrefix = "incremental";
- private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
-
- // TODO: make this private and use singleton pattern
- public IncrementalBackupFileNameEncoder() {
- }
-
- @Override
- public String encode(String customName, LocalDateTime time) {
- if (!isValidCustomName(customName))
- throw new IllegalArgumentException("Invalid custom name");
- String timeString = time.format(formatter);
- return backupFileNamePrefix + "-" + timeString + "_" + customName + ".kbi";
- }
-
- @Override
- public BackupFileNameEncoder.BackupBasicInformation decode(String fileName) {
- Pattern pattern = Pattern.compile(
- "^" + backupFileNamePrefix + "-" + "([0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2})_(.+)\\.kbi" + "$"
- );
- Matcher matcher = pattern.matcher(fileName);
- if (matcher.find()) {
- String timeString = matcher.group(1);
- String customName = matcher.group(2);
- return new BackupFileNameEncoder.BackupBasicInformation(customName, LocalDateTime.parse(timeString, formatter));
- }
- return null;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java b/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java
deleted file mode 100644
index ef15ae7..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/name/PrimitiveBackupFileNameEncoder.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.name;
-
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class PrimitiveBackupFileNameEncoder implements BackupFileNameEncoder {
- private static final String backupFileNamePrefix = "kbackup";
- private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
-
- @Override
- public String encode(String customName, LocalDateTime time) {
- if (!isValidCustomName(customName))
- throw new IllegalArgumentException("Invalid custom name");
- String timeString = time.format(formatter);
- return backupFileNamePrefix + "-" + timeString + "_" + customName + ".zip";
- }
-
- @Override
- public BackupBasicInformation decode(String fileName) {
- Pattern pattern = Pattern.compile(
- "^" + backupFileNamePrefix + "-" + "([0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}-[0-9]{2})_(.+)\\.zip" + "$"
- );
- Matcher matcher = pattern.matcher(fileName);
- if (matcher.find()) {
- String timeString = matcher.group(1);
- String customName = matcher.group(2);
- return new BackupBasicInformation(customName, LocalDateTime.parse(timeString, formatter));
- }
- return null;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/AvailableBackupProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/provider/AvailableBackupProvider.java
deleted file mode 100644
index caa0e84..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/AvailableBackupProvider.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.provider;
-
-/**
- * List all backup in disk. Provide their basic information as soon as possible.
- */
-public class AvailableBackupProvider {
- // TODO: remove obsolete impl. in command user interface. Use this instead.
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/IncrementalBackupInformation.java b/src/main/java/com/keuin/kbackupfabric/util/backup/provider/IncrementalBackupInformation.java
deleted file mode 100644
index 861d210..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/IncrementalBackupInformation.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.provider;
-
-import com.keuin.kbackupfabric.util.backup.name.BackupFileNameEncoder;
-
-import java.time.LocalDateTime;
-
-public class IncrementalBackupInformation extends BackupFileNameEncoder.BackupBasicInformation {
- // TODO: show total size for incremental backup
-
- public IncrementalBackupInformation(String customName, LocalDateTime time) {
- super(customName, time);
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/PrimitiveBackupInformation.java b/src/main/java/com/keuin/kbackupfabric/util/backup/provider/PrimitiveBackupInformation.java
deleted file mode 100644
index d3d2db8..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/provider/PrimitiveBackupInformation.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.provider;
-
-import com.keuin.kbackupfabric.util.backup.name.BackupFileNameEncoder;
-
-import java.time.LocalDateTime;
-
-public class PrimitiveBackupInformation extends BackupFileNameEncoder.BackupBasicInformation {
- public final long sizeBytes;
-
- public PrimitiveBackupInformation(String customName, LocalDateTime time, long sizeBytes) {
- super(customName, time);
- this.sizeBytes = sizeBytes;
- }
-}
diff --git a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java b/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java
deleted file mode 100644
index 01152c2..0000000
--- a/src/main/java/com/keuin/kbackupfabric/util/backup/suggestion/BackupNameSuggestionProvider.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.keuin.kbackupfabric.util.backup.suggestion;
-
-import com.mojang.brigadier.suggestion.SuggestionProvider;
-import com.mojang.brigadier.suggestion.Suggestions;
-import com.mojang.brigadier.suggestion.SuggestionsBuilder;
-import net.minecraft.server.command.ServerCommandSource;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.CompletableFuture;
-
-public class BackupNameSuggestionProvider {
-
- private static final List<String> candidateCacheList = new ArrayList<>();
- private static final Object syncSetDirectory = new Object();
- private static final Object syncCache = new Object();
- private static final long CACHE_TTL = 8000;
- private static String backupSaveDirectory;
- private static long cacheUpdateTime = 0;
-
- public static void setBackupSaveDirectory(String backupSaveDirectory) {
- synchronized (syncSetDirectory) {
- BackupNameSuggestionProvider.backupSaveDirectory = backupSaveDirectory;
- }
- // Immediately perform an update
- updateCandidateList();
- }
-
- public static void updateCandidateList() {
- synchronized (syncCache) {
- try {
- File file = new File(backupSaveDirectory);
- candidateCacheList.clear();
- File[] files = file.listFiles();
- if (files == null)
- return;
- for (File f : files)
- candidateCacheList.add(f.getName());
- cacheUpdateTime = System.currentTimeMillis();
- } catch (NullPointerException ignored) {
- }
- }
- }
-
-// private static void updateCandidateList(Collection<String> stringCollection) {
-// candidateList.clear();
-// candidateList.addAll(stringCollection);
-// }
-
- public static SuggestionProvider<ServerCommandSource> getProvider() {
- return (context, builder) -> getCompletableFuture(builder);
- }
-
- private static CompletableFuture<Suggestions> getCompletableFuture(SuggestionsBuilder builder) {
- if (isCacheExpired())
- updateCandidateList();
- String remaining = builder.getRemaining().toLowerCase(Locale.ROOT);
- synchronized (syncCache) {
- if (candidateCacheList.isEmpty()) { // If the list is empty then return no suggestions
- return Suggestions.empty(); // No suggestions
- }
-
- for (String string : candidateCacheList) { // Iterate through the supplied list
- if (string.toLowerCase(Locale.ROOT).startsWith(remaining)) {
- builder.suggest(string); // Add every single entry to suggestions list.
- }
- }
- }
- return builder.buildFuture(); // Create the CompletableFuture containing all the suggestions
- }
-
- private static boolean isCacheExpired() {
- return System.currentTimeMillis() - cacheUpdateTime > CACHE_TTL || cacheUpdateTime == 0;
- }
-}