From 3f1f1704b1926568b75c3afbefd07c69da21cb4b Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 17 Jun 2022 23:14:14 +0200 Subject: [PATCH] Added safe restore --- .../textile_backup/TextileLogger.java | 6 +- .../textile_backup/core/Utilities.java | 20 +++++- .../core/restore/RestoreBackupRunnable.java | 61 +++++++++---------- .../core/restore/RestoreHelper.java | 4 +- .../decompressors/GenericTarDecompressor.java | 8 +-- .../decompressors/ZipDecompressor.java | 7 +-- 6 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/main/java/net/szum123321/textile_backup/TextileLogger.java b/src/main/java/net/szum123321/textile_backup/TextileLogger.java index 29b6202..385a32c 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileLogger.java +++ b/src/main/java/net/szum123321/textile_backup/TextileLogger.java @@ -85,12 +85,16 @@ public class TextileLogger { log(Level.ERROR, msg, data); } + void error(String message, Throwable throwable) { + logger.error(prefix + message, throwable); + } + public void fatal(String msg, Object... data) { log(Level.FATAL, msg, data); } boolean sendFeedback(Level level, ServerCommandSource source, String msg, Object... args) { - if(source != null && source.getEntity() instanceof PlayerEntity) { + if(source != null && source.isExecutedByPlayer()) { MutableText text = Text.literal(messageFactory.newMessage(msg, args).getFormattedMessage()); if(level.intLevel() == Level.TRACE.intLevel()) text.formatted(Formatting.GREEN); diff --git a/src/main/java/net/szum123321/textile_backup/core/Utilities.java b/src/main/java/net/szum123321/textile_backup/core/Utilities.java index bc33d84..f0422b5 100644 --- a/src/main/java/net/szum123321/textile_backup/core/Utilities.java +++ b/src/main/java/net/szum123321/textile_backup/core/Utilities.java @@ -32,18 +32,20 @@ import net.szum123321.textile_backup.config.ConfigPOJO; import net.szum123321.textile_backup.Statics; import net.szum123321.textile_backup.mixin.MinecraftServerSessionAccessor; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.file.SimplePathVisitor; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Optional; -import java.util.UUID; public class Utilities { private final static ConfigHelper config = ConfigHelper.INSTANCE; @@ -80,6 +82,22 @@ public class Utilities { return path; } + public static void deleteDirectory(Path path) throws IOException { + Files.walkFileTree(path, new SimplePathVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + public static void updateTMPFSFlag(MinecraftServer server) { boolean flag = false; Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir")); diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java index 3f8547e..297be32 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreBackupRunnable.java @@ -31,7 +31,7 @@ import net.szum123321.textile_backup.core.create.BackupHelper; import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecompressor; import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor; -import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -51,54 +51,60 @@ public class RestoreBackupRunnable implements Runnable { log.info("Shutting down server..."); - ctx.getServer().stop(false); + ctx.server().stop(false); awaitServerShutdown(); if(config.get().backupOldWorlds) { BackupHelper.create( BackupContext.Builder .newBackupContextBuilder() - .setServer(ctx.getServer()) + .setServer(ctx.server()) .setInitiator(ActionInitiator.Restore) - .setComment("Old_World" + (ctx.getComment() != null ? "_" + ctx.getComment() : "")) + .setComment("Old_World" + (ctx.comment() != null ? "_" + ctx.comment() : "")) .build() ).run(); } - Path worldFile = Utilities.getWorldFolder(ctx.getServer()).toPath(); + Path worldFile = Utilities.getWorldFolder(ctx.server()); - log.info("Deleting old world..."); + try { + Path tmp = Files.createTempDirectory ( + worldFile.getParent(), + ctx.restoreableFile().getFile().getFileName().toString() + ); - if(!deleteDirectory(worldFile)) - log.error("Something went wrong while deleting old world!"); + tmp.toFile().deleteOnExit(); - Files.createDirectories(worldFile); + log.info("Starting decompression..."); - log.info("Starting decompression..."); + if (ctx.restoreableFile().getArchiveFormat() == ConfigPOJO.ArchiveFormat.ZIP) + ZipDecompressor.decompress(ctx.restoreableFile().getFile(), tmp); + else + GenericTarDecompressor.decompress(ctx.restoreableFile().getFile(), tmp); - if(ctx.getFile().getArchiveFormat() == ConfigPOJO.ArchiveFormat.ZIP) - ZipDecompressor.decompress(ctx.getFile().getFile().toPath(), worldFile); - else - GenericTarDecompressor.decompress(ctx.getFile().getFile().toPath(), worldFile); + log.info("Deleting old world..."); - if(config.get().deleteOldBackupAfterRestore) { - log.info("Deleting old backup"); + Utilities.deleteDirectory(worldFile); - if(!ctx.getFile().getFile().delete()) log.info("Something went wrong while deleting old backup"); + Files.move(tmp, worldFile); + + if (config.get().deleteOldBackupAfterRestore) { + log.info("Deleting old backup"); + + Files.delete(ctx.restoreableFile().getFile()); + } + } catch (IOException e) { + log.error("An exception occurred while trying to restore a backup!", e); } //in case we're playing on client Statics.globalShutdownBackupFlag.set(true); log.info("Done!"); - - //Might solve #37 - //Idk if it's a good idea... - //Runtime.getRuntime().exit(0); } private void awaitServerShutdown() { - while(((LivingServer)ctx.getServer()).isAlive()) { + while(((LivingServer)ctx.server()).isAlive()) { try { Thread.sleep(100); } catch (InterruptedException e) { @@ -106,15 +112,4 @@ public class RestoreBackupRunnable implements Runnable { } } } - - private static boolean deleteDirectory(File f) { - boolean state = true; - - if(f.isDirectory()) { - for(File f2 : f.listFiles()) - state &= deleteDirectory(f2); - } - - return f.delete() && state; - } } \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreHelper.java b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreHelper.java index 977fd24..c41029c 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreHelper.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreHelper.java @@ -98,9 +98,9 @@ public class RestoreHelper { private RestoreableFile(Path file) throws NoSuchElementException { this.file = file; - archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile extension!")); + archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file extension!")); String extension = archiveFormat.getCompleteString(); - creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile creation time!")); + creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file creation time!")); final String filename = file.getFileName().toString(); diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/GenericTarDecompressor.java b/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/GenericTarDecompressor.java index c3eaa49..de4696c 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/GenericTarDecompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/GenericTarDecompressor.java @@ -36,7 +36,7 @@ import java.time.Instant; public class GenericTarDecompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public static void decompress(Path input, Path target) { + public static void decompress(Path input, Path target) throws IOException { Instant start = Instant.now(); try (InputStream fileInputStream = Files.newInputStream(input); @@ -60,13 +60,11 @@ public class GenericTarDecompressor { try (OutputStream outputStream = Files.newOutputStream(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { IOUtils.copy(archiveInputStream, bufferedOutputStream); - } catch (IOException e) { - log.error("An exception occurred while trying to decompress file: {}", file.getFileName().toString(), e); } } } - } catch (IOException | CompressorException e) { - log.error("An exception occurred! ", e); + } catch (CompressorException e) { + throw new IOException(e); } log.info("Decompression took {} seconds.", Utilities.formatDuration(Duration.between(start, Instant.now()))); diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/ZipDecompressor.java b/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/ZipDecompressor.java index 7d6ae02..0e12347 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/ZipDecompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/decompressors/ZipDecompressor.java @@ -35,7 +35,7 @@ import java.util.Iterator; public class ZipDecompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public static void decompress(Path inputFile, Path target) { + public static void decompress(Path inputFile, Path target) throws IOException { Instant start = Instant.now(); try(ZipFile zipFile = new ZipFile(inputFile.toFile())) { @@ -50,14 +50,9 @@ public class ZipDecompressor { try (OutputStream outputStream = Files.newOutputStream(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { IOUtils.copy(zipFile.getInputStream(entry), bufferedOutputStream); - } catch (IOException e) { - log.error("An exception occurred while trying to decompress file: {}", entry.getName(), e); } } - } - } catch (IOException e) { - log.error("An exception occurred! ", e); } log.info("Decompression took: {} seconds.", Utilities.formatDuration(Duration.between(start, Instant.now())));