From 6897b94afc2d588f047bc7d222802f18141e11db Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 17 Jun 2022 21:15:50 +0200 Subject: [PATCH 1/6] slowly moving to the new file handling api (File -> Path) --- .../core/restore/RestoreBackupRunnable.java | 10 +++--- .../decompressors/GenericTarDecompressor.java | 26 ++++++-------- .../decompressors/ZipDecompressor.java | 34 +++++++++---------- 3 files changed, 34 insertions(+), 36 deletions(-) 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 171bb55..3f8547e 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 @@ -32,6 +32,8 @@ import net.szum123321.textile_backup.core.restore.decompressors.GenericTarDecomp import net.szum123321.textile_backup.core.restore.decompressors.ZipDecompressor; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; public class RestoreBackupRunnable implements Runnable { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); @@ -63,21 +65,21 @@ public class RestoreBackupRunnable implements Runnable { ).run(); } - File worldFile = Utilities.getWorldFolder(ctx.getServer()); + Path worldFile = Utilities.getWorldFolder(ctx.getServer()).toPath(); log.info("Deleting old world..."); if(!deleteDirectory(worldFile)) log.error("Something went wrong while deleting old world!"); - worldFile.mkdirs(); + Files.createDirectories(worldFile); log.info("Starting decompression..."); if(ctx.getFile().getArchiveFormat() == ConfigPOJO.ArchiveFormat.ZIP) - ZipDecompressor.decompress(ctx.getFile().getFile(), worldFile); + ZipDecompressor.decompress(ctx.getFile().getFile().toPath(), worldFile); else - GenericTarDecompressor.decompress(ctx.getFile().getFile(), worldFile); + GenericTarDecompressor.decompress(ctx.getFile().getFile().toPath(), worldFile); if(config.get().deleteOldBackupAfterRestore) { log.info("Deleting old backup"); 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 bc26258..c3eaa49 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 @@ -29,16 +29,17 @@ import org.apache.commons.compress.utils.IOUtils; import java.io.*; import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; import java.time.Instant; public class GenericTarDecompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public static void decompress(File input, File target) { + public static void decompress(Path input, Path target) { Instant start = Instant.now(); - try (InputStream fileInputStream = new FileInputStream(input); + try (InputStream fileInputStream = Files.newInputStream(input); InputStream bufferedInputStream = new BufferedInputStream(fileInputStream); InputStream compressorInputStream = getCompressorInputStream(bufferedInputStream); TarArchiveInputStream archiveInputStream = new TarArchiveInputStream(compressorInputStream)) { @@ -50,22 +51,17 @@ public class GenericTarDecompressor { continue; } - File file = target.toPath().resolve(entry.getName()).toFile(); + Path file = target.resolve(entry.getName()); if(entry.isDirectory()) { - file.mkdirs(); + Files.createDirectories(file); } else { - File parent = file.getParentFile(); - - if (!parent.isDirectory() && !parent.mkdirs()) { - log.error("Failed to create {}", parent); - } else { - try (OutputStream outputStream = Files.newOutputStream(file.toPath()); - BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) { - IOUtils.copy(archiveInputStream, bufferedOutputStream); - } catch (IOException e) { - log.error("An exception occurred while trying to decompress file: {}", file.getName(), e); - } + Files.createDirectories(file.getParent()); + 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); } } } 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 d745f69..7d6ae02 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 @@ -21,41 +21,41 @@ package net.szum123321.textile_backup.core.restore.decompressors; import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileLogger; import net.szum123321.textile_backup.core.Utilities; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.utils.IOUtils; import java.io.*; import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; import java.time.Instant; +import java.util.Iterator; public class ZipDecompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public static void decompress(File inputFile, File target) { + public static void decompress(Path inputFile, Path target) { Instant start = Instant.now(); - try(ZipFile zipFile = new ZipFile(inputFile)) { - zipFile.getEntries().asIterator().forEachRemaining(entry -> { - File file = target.toPath().resolve(entry.getName()).toFile(); + try(ZipFile zipFile = new ZipFile(inputFile.toFile())) { + for (Iterator it = zipFile.getEntries().asIterator(); it.hasNext(); ) { + ZipArchiveEntry entry = it.next(); + Path file = target.resolve(entry.getName()); if(entry.isDirectory()) { - file.mkdirs(); + Files.createDirectories(file); } else { - File parent = file.getParentFile(); - - if (!parent.isDirectory() && !parent.mkdirs()) { - log.error("Failed to create {}", parent); - } else { - try (OutputStream outputStream = Files.newOutputStream(file.toPath()); - 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); - } + Files.createDirectories(file.getParent()); + 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); } From a85db99d82c51c1f9a82db41ac74c0eaa88ea2f7 Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 17 Jun 2022 21:33:13 +0200 Subject: [PATCH 2/6] pt II, slowly moving to the new file handling api (File -> Path) --- .../core/create/MakeBackupRunnable.java | 17 ++++++------ .../compressors/AbstractCompressor.java | 26 +++++++++---------- .../compressors/ParallelZipCompressor.java | 18 +++++++------ .../create/compressors/ZipCompressor.java | 21 ++++++++------- .../compressors/tar/AbstractTarArchiver.java | 11 ++++---- 5 files changed, 49 insertions(+), 44 deletions(-) diff --git a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java index 436b713..70a17ac 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java @@ -30,9 +30,10 @@ import net.szum123321.textile_backup.core.create.compressors.tar.ParallelBZip2Co import net.szum123321.textile_backup.core.create.compressors.tar.ParallelGzipCompressor; import org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream; -import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; public class MakeBackupRunnable implements Runnable { @@ -55,22 +56,22 @@ public class MakeBackupRunnable implements Runnable { log.sendInfoAL(context, "Starting backup"); - File world = Utilities.getWorldFolder(context.getServer()); + Path world = Utilities.getWorldFolder(context.getServer()).toPath(); log.trace("Minecraft world is: {}", world); - File outFile = Utilities + Path outFile = Utilities .getBackupRootPath(Utilities.getLevelName(context.getServer())) .toPath() - .resolve(getFileName()) - .toFile(); - + .resolve(getFileName()); log.trace("Outfile is: {}", outFile); - outFile.getParentFile().mkdirs(); + // outFile.getParentFile().mkdirs(); try { - outFile.createNewFile(); + //outFile.createNewFile(); + Files.createDirectories(outFile.getParent()); + Files.createFile(outFile); } catch (IOException e) { log.error("An exception occurred when trying to create new backup file!", e); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java index 4f7aacf..125c32d 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java @@ -31,27 +31,27 @@ import java.nio.file.Path; import java.time.Duration; import java.time.Instant; import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; public abstract class AbstractCompressor { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); - public void createArchive(File inputFile, File outputFile, BackupContext ctx, int coreLimit) { + public void createArchive(Path inputFile, Path outputFile, BackupContext ctx, int coreLimit) { Instant start = Instant.now(); - try (FileOutputStream outStream = new FileOutputStream(outputFile); + try (OutputStream outStream = Files.newOutputStream(outputFile); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outStream); - OutputStream arc = createArchiveOutputStream(bufferedOutputStream, ctx, coreLimit)) { + OutputStream arc = createArchiveOutputStream(bufferedOutputStream, ctx, coreLimit); + Stream fileStream = Files.walk(inputFile)) { - Files.walk(inputFile.toPath()) - .filter(path -> !Utilities.isBlacklisted(inputFile.toPath().relativize(path))) - .map(Path::toFile) - .filter(File::isFile) - .forEach(file -> { + fileStream + .filter(path -> !Utilities.isBlacklisted(inputFile.relativize(path))) + .filter(Files::isRegularFile).forEach(file -> { try { //hopefully one broken file won't spoil the whole archive - addEntry(file, inputFile.toPath().relativize(file.toPath()).toString(), arc); + addEntry(file, inputFile.relativize(file).toString(), arc); } catch (IOException e) { - log.error("An exception occurred while trying to compress: {}", inputFile.toPath().relativize(file.toPath()).toString(), e); + log.error("An exception occurred while trying to compress: {}", inputFile.relativize(file).toString(), e); if (ctx.getInitiator() == ActionInitiator.Player) log.sendError(ctx, "Something went wrong while compressing files!"); @@ -86,13 +86,13 @@ public abstract class AbstractCompressor { } protected abstract OutputStream createArchiveOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException; - protected abstract void addEntry(File file, String entryName, OutputStream arc) throws IOException; + protected abstract void addEntry(Path file, String entryName, OutputStream arc) throws IOException; protected void finish(OutputStream arc) throws InterruptedException, ExecutionException, IOException { - ;//Basically this function is only needed for the ParallelZipCompressor to write out ParallelScatterZipCreator + //Basically this function is only needed for the ParallelZipCompressor to write out ParallelScatterZipCreator } protected void close() { - ;//Same as above, just for ParallelGzipCompressor to shutdown ExecutorService + //Same as above, just for ParallelGzipCompressor to shut down ExecutorService } } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java index 63a81c7..7933067 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ParallelZipCompressor.java @@ -26,6 +26,8 @@ import org.apache.commons.compress.archivers.zip.*; import org.apache.commons.compress.parallel.InputStreamSupplier; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Objects; import java.util.concurrent.*; import java.util.zip.ZipEntry; @@ -65,13 +67,13 @@ public class ParallelZipCompressor extends ZipCompressor { } @Override - protected void addEntry(File file, String entryName, OutputStream arc) throws IOException { + protected void addEntry(Path file, String entryName, OutputStream arc) throws IOException { ZipArchiveEntry entry = (ZipArchiveEntry)((ZipArchiveOutputStream)arc).createArchiveEntry(file, entryName); - if(ZipCompressor.isDotDat(file.getName())) { - entry.setMethod(ZipArchiveOutputStream.STORED); - entry.setSize(file.length()); - entry.setCompressedSize(file.length()); + if(ZipCompressor.isDotDat(file.getFileName().toString())) { + entry.setMethod(ZipEntry.STORED); + entry.setSize(Files.size(file)); + entry.setCompressedSize(Files.size(file)); entry.setCrc(getCRC(file)); } else entry.setMethod(ZipEntry.DEFLATED); @@ -126,12 +128,12 @@ public class ParallelZipCompressor extends ZipCompressor { } } - record FileInputStreamSupplier(File sourceFile) implements InputStreamSupplier { + record FileInputStreamSupplier(Path sourceFile) implements InputStreamSupplier { public InputStream get() { try { - return new FileInputStream(sourceFile); + return Files.newInputStream(sourceFile); } catch (IOException e) { - log.error("An exception occurred while trying to create an input stream from file: {}!", sourceFile.getName(), e); + log.error("An exception occurred while trying to create an input stream from file: {}!", sourceFile.toString(), e); } return null; diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java index ea98afd..0210708 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/ZipCompressor.java @@ -27,9 +27,12 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; import java.util.zip.CRC32; import java.util.zip.Checksum; +import java.util.zip.ZipEntry; public class ZipCompressor extends AbstractCompressor { private final static ConfigHelper config = ConfigHelper.INSTANCE; @@ -51,14 +54,14 @@ public class ZipCompressor extends AbstractCompressor { } @Override - protected void addEntry(File file, String entryName, OutputStream arc) throws IOException { - try (FileInputStream fileInputStream = new FileInputStream(file)){ + protected void addEntry(Path file, String entryName, OutputStream arc) throws IOException { + try (InputStream fileInputStream = Files.newInputStream(file)){ ZipArchiveEntry entry = (ZipArchiveEntry)((ZipArchiveOutputStream)arc).createArchiveEntry(file, entryName); - if(isDotDat(file.getName())) { - entry.setMethod(ZipArchiveOutputStream.STORED); - entry.setSize(file.length()); - entry.setCompressedSize(file.length()); + if(isDotDat(file.getFileName().toString())) { + entry.setMethod(ZipEntry.STORED); + entry.setSize(Files.size(file)); + entry.setCompressedSize(Files.size(file)); entry.setCrc(getCRC(file)); } @@ -76,15 +79,15 @@ public class ZipCompressor extends AbstractCompressor { return arr[arr.length - 1].contains("dat"); //includes dat_old } - protected static long getCRC(File file) throws IOException { + protected static long getCRC(Path file) throws IOException { Checksum sum = new CRC32(); byte[] buffer = new byte[8192]; int len; - try (InputStream stream = new FileInputStream(file)) { + try (InputStream stream = Files.newInputStream(file)) { while ((len = stream.read(buffer)) != -1) sum.update(buffer, 0, len); } catch (IOException e) { - throw new IOException("Error while calculating CRC of: " + file.getAbsolutePath(), e); + throw new IOException("Error while calculating CRC of: " + file.toAbsolutePath(), e); } return sum.getValue(); diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java index fe066bb..04489b4 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/tar/AbstractTarArchiver.java @@ -24,10 +24,9 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.utils.IOUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; public class AbstractTarArchiver extends AbstractCompressor { protected OutputStream getCompressorOutputStream(OutputStream stream, BackupContext ctx, int coreLimit) throws IOException { @@ -44,8 +43,8 @@ public class AbstractTarArchiver extends AbstractCompressor { } @Override - protected void addEntry(File file, String entryName, OutputStream arc) throws IOException { - try (FileInputStream fileInputStream = new FileInputStream(file)){ + protected void addEntry(Path file, String entryName, OutputStream arc) throws IOException { + try (InputStream fileInputStream = Files.newInputStream(file)){ TarArchiveEntry entry = (TarArchiveEntry)((TarArchiveOutputStream) arc).createArchiveEntry(file, entryName); ((TarArchiveOutputStream)arc).putArchiveEntry(entry); From b4597f6f1f07c60d7617d9b8c4de3cf551a7a13a Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 17 Jun 2022 22:43:41 +0200 Subject: [PATCH 3/6] pt III, slowly moving to the new file handling api (File -> Path) --- .../szum123321/textile_backup/Statics.java | 4 +- .../commands/manage/DeleteCommand.java | 47 +++++------ .../restore/RestoreBackupCommand.java | 2 +- .../textile_backup/core/Utilities.java | 37 +++++---- .../core/create/BackupHelper.java | 80 ++++++++++++------- .../core/create/MakeBackupRunnable.java | 3 +- .../core/restore/RestoreContext.java | 30 +------ .../core/restore/RestoreHelper.java | 56 ++++++++----- 8 files changed, 138 insertions(+), 121 deletions(-) diff --git a/src/main/java/net/szum123321/textile_backup/Statics.java b/src/main/java/net/szum123321/textile_backup/Statics.java index fbf6564..9a98ebb 100644 --- a/src/main/java/net/szum123321/textile_backup/Statics.java +++ b/src/main/java/net/szum123321/textile_backup/Statics.java @@ -20,7 +20,7 @@ package net.szum123321.textile_backup; import net.szum123321.textile_backup.core.restore.AwaitThread; -import java.io.File; +import java.nio.file.Path; import java.time.format.DateTimeFormatter; import java.util.Optional; import java.util.concurrent.ExecutorService; @@ -35,6 +35,6 @@ public class Statics { public static final AtomicBoolean globalShutdownBackupFlag = new AtomicBoolean(true); public static boolean disableWatchdog = false; public static AwaitThread restoreAwaitThread = null; - public static Optional untouchableFile = Optional.empty(); + public static Optional untouchableFile = Optional.empty(); public static boolean disableTMPFiles = false; } diff --git a/src/main/java/net/szum123321/textile_backup/commands/manage/DeleteCommand.java b/src/main/java/net/szum123321/textile_backup/commands/manage/DeleteCommand.java index d2cae78..168c23b 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/manage/DeleteCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/manage/DeleteCommand.java @@ -21,7 +21,6 @@ package net.szum123321.textile_backup.commands.manage; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.szum123321.textile_backup.TextileBackup; @@ -31,11 +30,13 @@ import net.szum123321.textile_backup.Statics; import net.szum123321.textile_backup.commands.FileSuggestionProvider; import net.szum123321.textile_backup.core.Utilities; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; -import java.util.Arrays; import java.util.Optional; +import java.util.stream.Stream; public class DeleteCommand { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); @@ -57,28 +58,28 @@ public class DeleteCommand { throw CommandExceptions.DATE_TIME_PARSE_COMMAND_EXCEPTION_TYPE.create(e); } - File root = Utilities.getBackupRootPath(Utilities.getLevelName(source.getServer())); + Path root = Utilities.getBackupRootPath(Utilities.getLevelName(source.getServer())); - Optional optionalFile = Arrays.stream(root.listFiles()) - .filter(Utilities::isValidBackup) - .filter(file -> Utilities.getFileCreationTime(file).orElse(LocalDateTime.MIN).equals(dateTime)) - .findFirst(); + try (Stream stream = Files.list(root)) { + stream.filter(Utilities::isValidBackup) + .filter(file -> Utilities.getFileCreationTime(file).orElse(LocalDateTime.MIN).equals(dateTime)) + .findFirst().ifPresent(file -> { + if(Statics.untouchableFile.isEmpty() || !Statics.untouchableFile.get().equals(file)) { + try { + Files.delete(file); + log.sendInfo(source, "File {} successfully deleted!", file); - if(optionalFile.isPresent()) { - if(Statics.untouchableFile.isEmpty() || !Statics.untouchableFile.get().equals(optionalFile.get())) { - if(optionalFile.get().delete()) { - log.sendInfo(source, "File {} successfully deleted!", optionalFile.get().getName()); - - if(source.getEntity() instanceof PlayerEntity) - log.info("Player {} deleted {}.", source.getPlayer().getName(), optionalFile.get().getName()); - } else { - log.sendError(source, "Something went wrong while deleting file!"); - } - } else { - log.sendError(source, "Couldn't delete the file because it's being restored right now."); - log.sendHint(source, "If you want to abort restoration then use: /backup killR"); - } - } else { + if(source.isExecutedByPlayer()) + log.info("Player {} deleted {}.", source.getPlayer().getName(), file); + } catch (IOException e) { + log.sendError(source, "Something went wrong while deleting file!"); + } + } else { + log.sendError(source, "Couldn't delete the file because it's being restored right now."); + log.sendHint(source, "If you want to abort restoration then use: /backup killR"); + } + }); + } catch (IOException ignored) { log.sendError(source, "Couldn't find file by this name."); log.sendHint(source, "Maybe try /backup list"); } diff --git a/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java b/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java index bb516c9..85d984b 100644 --- a/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java +++ b/src/main/java/net/szum123321/textile_backup/commands/restore/RestoreBackupCommand.java @@ -82,7 +82,7 @@ public class RestoreBackupCommand { Optional backupFile = RestoreHelper.findFileAndLockIfPresent(dateTime, source.getServer()); if(backupFile.isPresent()) { - log.info("Found file to restore {}", backupFile.get().getFile().getName()); + log.info("Found file to restore {}", backupFile.get().getFile().getFileName().toString()); } else { log.sendInfo(source, "No file created on {} was found!", dateTime.format(Statics.defaultDateTimeFormatter)); 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 8a56b91..bc33d84 100644 --- a/src/main/java/net/szum123321/textile_backup/core/Utilities.java +++ b/src/main/java/net/szum123321/textile_backup/core/Utilities.java @@ -60,19 +60,22 @@ public class Utilities { return ((MinecraftServerSessionAccessor)server).getSession().getDirectoryName(); } - public static File getWorldFolder(MinecraftServer server) { + public static Path getWorldFolder(MinecraftServer server) { return ((MinecraftServerSessionAccessor)server) .getSession() - .getWorldDirectory(World.OVERWORLD) - .toFile(); + .getWorldDirectory(World.OVERWORLD); } - public static File getBackupRootPath(String worldName) { - File path = new File(config.get().path).getAbsoluteFile(); + public static Path getBackupRootPath(String worldName) { + Path path = Path.of(config.get().path).toAbsolutePath(); - if (config.get().perWorldBackup) path = path.toPath().resolve(worldName).toFile(); + if (config.get().perWorldBackup) path = path.resolve(worldName); - if (!path.exists()) path.mkdirs(); + try { + Files.createDirectories(path); + } catch (IOException e) { + //I REALLY shouldn't be handling this here + } return path; } @@ -81,7 +84,7 @@ public class Utilities { boolean flag = false; Path tmp_dir = Path.of(System.getProperty("java.io.tmpdir")); if( - FileUtils.sizeOfDirectory(Utilities.getWorldFolder(server)) >= + FileUtils.sizeOfDirectory(Utilities.getWorldFolder(server).toFile()) >= tmp_dir.toFile().getUsableSpace() ) { log.error("Not enough space left in TMP directory! ({})", tmp_dir); @@ -130,11 +133,11 @@ public class Utilities { .findAny(); } - public static Optional getArchiveExtension(File f) { - return getArchiveExtension(f.getName()); + public static Optional getArchiveExtension(Path f) { + return getArchiveExtension(f.getFileName().toString()); } - public static Optional getFileCreationTime(File file) { + public static Optional getFileCreationTime(Path file) { LocalDateTime creationTime = null; if(getArchiveExtension(file).isPresent()) { @@ -143,7 +146,7 @@ public class Utilities { try { creationTime = LocalDateTime.from( Utilities.getDateTimeFormatter().parse( - file.getName().split(fileExtension)[0].split("#")[0] + file.getFileName().toString().split(fileExtension)[0].split("#")[0] ) ); } catch (Exception ignored) {} @@ -152,7 +155,7 @@ public class Utilities { try { creationTime = LocalDateTime.from( Utilities.getBackupDateTimeFormatter().parse( - file.getName().split(fileExtension)[0].split("#")[0] + file.getFileName().toString().split(fileExtension)[0].split("#")[0] ) ); } catch (Exception ignored2){} @@ -160,7 +163,7 @@ public class Utilities { if(creationTime == null) { try { - FileTime fileTime = (FileTime) Files.getAttribute(file.toPath(), "creationTime"); + FileTime fileTime = (FileTime) Files.getAttribute(file, "creationTime"); creationTime = LocalDateTime.ofInstant(fileTime.toInstant(), ZoneOffset.systemDefault()); } catch (IOException ignored3) {} } @@ -169,7 +172,7 @@ public class Utilities { return Optional.ofNullable(creationTime); } - public static boolean isValidBackup(File f) { + public static boolean isValidBackup(Path f) { return getArchiveExtension(f).isPresent() && getFileCreationTime(f).isPresent() && isFileOk(f); } @@ -177,6 +180,10 @@ public class Utilities { return f.exists() && f.isFile(); } + public static boolean isFileOk(Path f) { + return Files.exists(f) && Files.isRegularFile(f); + } + public static DateTimeFormatter getDateTimeFormatter() { return DateTimeFormatter.ofPattern(config.get().dateTimeFormat); } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java index 864f231..359dc7c 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java @@ -26,11 +26,13 @@ import net.szum123321.textile_backup.config.ConfigHelper; import net.szum123321.textile_backup.core.Utilities; import org.apache.commons.io.FileUtils; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.util.Arrays; import java.util.Comparator; +import java.util.stream.Stream; public class BackupHelper { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); @@ -77,52 +79,76 @@ public class BackupHelper { } public static int executeFileLimit(ServerCommandSource ctx, String worldName) { - File root = Utilities.getBackupRootPath(worldName); + Path root = Utilities.getBackupRootPath(worldName); int deletedFiles = 0; - if (root.isDirectory() && root.exists() && root.listFiles() != null) { + + if (Files.isDirectory(root) && Files.exists(root) && !isEmpty(root)) { if (config.get().maxAge > 0) { // delete files older that configured final LocalDateTime now = LocalDateTime.now(); - deletedFiles += Arrays.stream(root.listFiles()) - .filter(Utilities::isValidBackup)// We check if we can get file's creation date so that the next line won't throw an exception - .filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > config.get().maxAge) - .map(f -> deleteFile(f, ctx)) - .filter(b -> b).count(); //a bit awkward + try(Stream stream = Files.list(root)) { + deletedFiles += stream + .filter(Utilities::isValidBackup)// We check if we can get restoreableFile's creation date so that the next line won't throw an exception + .filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > config.get().maxAge) + .map(f -> deleteFile(f, ctx)) + .filter(b -> b).count(); //a bit awkward + } catch (IOException e) { + throw new RuntimeException(e); + } + } + if (config.get().backupsToKeep > 0 /*&& root.listFiles().length > config.get().backupsToKeep*/) { + try(Stream stream = Files.list(root)) { + deletedFiles += stream + .filter(Utilities::isValidBackup) + .sorted(Comparator.comparing(f -> Utilities.getFileCreationTime((Path) f).get()).reversed()) + .skip(config.get().backupsToKeep) + .map(f -> deleteFile(f, ctx)) + .filter(b -> b).count(); + } catch (IOException e) { + throw new RuntimeException(e); + } } - if (config.get().backupsToKeep > 0 && root.listFiles().length > config.get().backupsToKeep) { - deletedFiles += Arrays.stream(root.listFiles()) - .filter(Utilities::isValidBackup) - .sorted(Comparator.comparing(f -> Utilities.getFileCreationTime((File) f).get()).reversed()) - .skip(config.get().backupsToKeep) - .map(f -> deleteFile(f, ctx)) - .filter(b -> b).count(); - } - - if (config.get().maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) { + //It is fucking quadratic! + /*if (config.get().maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) { deletedFiles += Arrays.stream(root.listFiles()) .filter(Utilities::isValidBackup) .sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get())) .takeWhile(f -> FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) .map(f -> deleteFile(f, ctx)) .filter(b -> b).count(); - } + }*/ } return deletedFiles; } - private static boolean deleteFile(File f, ServerCommandSource ctx) { - if(Statics.untouchableFile.isEmpty()|| !Statics.untouchableFile.get().equals(f)) { - if(f.delete()) { - log.sendInfoAL(ctx, "Deleting: {}", f.getName()); - return true; - } else { - log.sendErrorAL(ctx, "Something went wrong while deleting: {}.", f.getName()); + private static boolean isEmpty(Path path) { + if (Files.isDirectory(path)) { + try (Stream entries = Files.list(path)) { + return entries.findFirst().isEmpty(); + } catch (IOException e) { + return false; } } return false; } + + private static boolean deleteFile(Path f, ServerCommandSource ctx) { + if(Statics.untouchableFile.isEmpty()|| !Statics.untouchableFile.get().equals(f)) { + try { + Files.delete(f); + log.sendInfoAL(ctx, "Deleting: {}", f); + } catch (IOException e) { + if(ctx.isExecutedByPlayer()) log.sendError(ctx, "Something went wrong while deleting: {}.", f); + log.error("Something went wrong while deleting: {}.", f, e); + return false; + } + return true; + } + + return false; + } } \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java index 70a17ac..af8ba94 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java @@ -56,13 +56,12 @@ public class MakeBackupRunnable implements Runnable { log.sendInfoAL(context, "Starting backup"); - Path world = Utilities.getWorldFolder(context.getServer()).toPath(); + Path world = Utilities.getWorldFolder(context.getServer()); log.trace("Minecraft world is: {}", world); Path outFile = Utilities .getBackupRootPath(Utilities.getLevelName(context.getServer())) - .toPath() .resolve(getFileName()); log.trace("Outfile is: {}", outFile); diff --git a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreContext.java b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreContext.java index 01ad8bd..2e597b3 100644 --- a/src/main/java/net/szum123321/textile_backup/core/restore/RestoreContext.java +++ b/src/main/java/net/szum123321/textile_backup/core/restore/RestoreContext.java @@ -21,43 +21,15 @@ package net.szum123321.textile_backup.core.restore; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.util.Util; import net.szum123321.textile_backup.core.ActionInitiator; import javax.annotation.Nullable; -import java.util.UUID; -public record RestoreContext(RestoreHelper.RestoreableFile file, +public record RestoreContext(RestoreHelper.RestoreableFile restoreableFile, MinecraftServer server, @Nullable String comment, ActionInitiator initiator, ServerCommandSource commandSource) { - - public RestoreHelper.RestoreableFile getFile() { - return file; - } - - public MinecraftServer getServer() { - return server; - } - - @Nullable - public String getComment() { - return comment; - } - - public ActionInitiator getInitiator() { - return initiator; - } - - public UUID getInitiatorUUID() { - return initiator.equals(ActionInitiator.Player) && commandSource.getEntity() != null ? commandSource.getEntity().getUuid(): Util.NIL_UUID; - } - - public ServerCommandSource getCommandSource() { - return commandSource; - } - public static final class Builder { private RestoreHelper.RestoreableFile file; private MinecraftServer server; 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 a55c1d9..977fd24 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 @@ -28,23 +28,31 @@ import net.szum123321.textile_backup.core.ActionInitiator; import net.szum123321.textile_backup.core.Utilities; import org.jetbrains.annotations.NotNull; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RestoreHelper { private final static TextileLogger log = new TextileLogger(TextileBackup.MOD_NAME); private final static ConfigHelper config = ConfigHelper.INSTANCE; public static Optional findFileAndLockIfPresent(LocalDateTime backupTime, MinecraftServer server) { - File root = Utilities.getBackupRootPath(Utilities.getLevelName(server)); + Path root = Utilities.getBackupRootPath(Utilities.getLevelName(server)); - Optional optionalFile = Arrays.stream(root.listFiles()) - .map(RestoreableFile::newInstance) - .flatMap(Optional::stream) - .filter(rf -> rf.getCreationTime().equals(backupTime)) - .findFirst(); + Optional optionalFile; + try (Stream stream = Files.list(root)) { + optionalFile = stream + .map(RestoreableFile::newInstance) + .flatMap(Optional::stream) + .filter(rf -> rf.getCreationTime().equals(backupTime)) + .findFirst(); + } catch (IOException e) { + throw new RuntimeException(e); + } Statics.untouchableFile = optionalFile.map(RestoreableFile::getFile); @@ -52,8 +60,8 @@ public class RestoreHelper { } public static AwaitThread create(RestoreContext ctx) { - if(ctx.getInitiator() == ActionInitiator.Player) - log.info("Backup restoration was initiated by: {}", ctx.getCommandSource().getName()); + if(ctx.initiator() == ActionInitiator.Player) + log.info("Backup restoration was initiated by: {}", ctx.commandSource().getName()); else log.info("Backup restoration was initiated form Server Console"); @@ -69,28 +77,32 @@ public class RestoreHelper { } public static List getAvailableBackups(MinecraftServer server) { - File root = Utilities.getBackupRootPath(Utilities.getLevelName(server)); + Path root = Utilities.getBackupRootPath(Utilities.getLevelName(server)); - return Arrays.stream(root.listFiles()) - .filter(Utilities::isValidBackup) - .map(RestoreableFile::newInstance) - .flatMap(Optional::stream) - .collect(Collectors.toList()); + try (Stream stream = Files.list(root)) { + return stream.filter(Utilities::isValidBackup) + .map(RestoreableFile::newInstance) + .flatMap(Optional::stream) + .collect(Collectors.toList()); + } catch (IOException e) { + log.error("Error while listing available backups", e); + return new LinkedList<>(); + } } public static class RestoreableFile implements Comparable { - private final File file; + private final Path file; private final ConfigPOJO.ArchiveFormat archiveFormat; private final LocalDateTime creationTime; private final String comment; - private RestoreableFile(File file) throws NoSuchElementException { + private RestoreableFile(Path file) throws NoSuchElementException { this.file = file; - archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file extension!")); + archiveFormat = Utilities.getArchiveExtension(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile extension!")); String extension = archiveFormat.getCompleteString(); - creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get file creation time!")); + creationTime = Utilities.getFileCreationTime(file).orElseThrow(() -> new NoSuchElementException("Couldn't get restoreableFile creation time!")); - final String filename = file.getName(); + final String filename = file.getFileName().toString(); if(filename.split("#").length > 1) { this.comment = filename.split("#")[1].split(extension)[0]; @@ -99,7 +111,7 @@ public class RestoreHelper { } } - public static Optional newInstance(File file) { + public static Optional newInstance(Path file) { try { return Optional.of(new RestoreableFile(file)); } catch (NoSuchElementException ignored) {} @@ -107,7 +119,7 @@ public class RestoreHelper { return Optional.empty(); } - public File getFile() { + public Path getFile() { return file; } From 3f1f1704b1926568b75c3afbefd07c69da21cb4b Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Fri, 17 Jun 2022 23:14:14 +0200 Subject: [PATCH 4/6] 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()))); From fd02df702200a1768a561247f198b4ac263e1e99 Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Sat, 18 Jun 2022 08:30:36 +0200 Subject: [PATCH 5/6] Cleaner cleanup algorithm --- .../core/create/BackupHelper.java | 86 +++++++++++++------ .../core/restore/RestoreBackupRunnable.java | 6 +- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java index 359dc7c..a6457f7 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java @@ -24,7 +24,6 @@ import net.szum123321.textile_backup.TextileBackup; import net.szum123321.textile_backup.TextileLogger; import net.szum123321.textile_backup.config.ConfigHelper; import net.szum123321.textile_backup.core.Utilities; -import org.apache.commons.io.FileUtils; import java.io.IOException; import java.nio.file.Files; @@ -32,6 +31,8 @@ import java.nio.file.Path; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Comparator; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; public class BackupHelper { @@ -89,41 +90,69 @@ public class BackupHelper { try(Stream stream = Files.list(root)) { deletedFiles += stream - .filter(Utilities::isValidBackup)// We check if we can get restoreableFile's creation date so that the next line won't throw an exception + .filter(Utilities::isValidBackup)// We check if we can get file's creation date so that the next line won't throw an exception .filter(f -> now.toEpochSecond(ZoneOffset.UTC) - Utilities.getFileCreationTime(f).get().toEpochSecond(ZoneOffset.UTC) > config.get().maxAge) - .map(f -> deleteFile(f, ctx)) - .filter(b -> b).count(); //a bit awkward + .mapToInt(f -> deleteFile(f, ctx)) + .sum(); } catch (IOException e) { - throw new RuntimeException(e); - } - } - if (config.get().backupsToKeep > 0 /*&& root.listFiles().length > config.get().backupsToKeep*/) { - try(Stream stream = Files.list(root)) { - deletedFiles += stream - .filter(Utilities::isValidBackup) - .sorted(Comparator.comparing(f -> Utilities.getFileCreationTime((Path) f).get()).reversed()) - .skip(config.get().backupsToKeep) - .map(f -> deleteFile(f, ctx)) - .filter(b -> b).count(); - } catch (IOException e) { - throw new RuntimeException(e); + log.error("An exception occurred while trying to delete old files!", e); } } - //It is fucking quadratic! - /*if (config.get().maxSize > 0 && FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) { - deletedFiles += Arrays.stream(root.listFiles()) + int noToKeep = config.get().backupsToKeep > 0 ? config.get().backupsToKeep : Integer.MAX_VALUE; + long maxSize = config.get().maxSize > 0 ? config.get().maxSize : Long.MAX_VALUE; + + AtomicInteger currentNo = new AtomicInteger(countBackups(root)); + AtomicLong currentSize = new AtomicLong(countSize(root)); + + try(Stream stream = Files.list(root)) { + deletedFiles += stream .filter(Utilities::isValidBackup) .sorted(Comparator.comparing(f -> Utilities.getFileCreationTime(f).get())) - .takeWhile(f -> FileUtils.sizeOfDirectory(root) / 1024 > config.get().maxSize) - .map(f -> deleteFile(f, ctx)) - .filter(b -> b).count(); - }*/ + .takeWhile(f -> (currentNo.get() > noToKeep) || (currentSize.get() > maxSize)) + .peek(f -> currentNo.decrementAndGet()) + .peek(f -> { + try { + currentSize.addAndGet(Files.size(f)); + } catch (IOException e) { + currentSize.set(0); + } + }) + .mapToInt(f -> deleteFile(f, ctx)) + .sum(); + } catch (IOException e) { + log.error("An exception occurred while trying to delete old files!", e); + } } return deletedFiles; } + private static int countBackups(Path path) { + try(Stream stream = Files.list(path)) { + return (int) stream + .filter(Utilities::isValidBackup) + .count(); + } catch (IOException ignored) {} + return 0; + } + + private static long countSize(Path path) { + try(Stream stream = Files.list(path)) { + return (int) stream + .filter(Utilities::isValidBackup) + .mapToLong(f -> { + try { + return Files.size(f); + } catch (IOException e) { + return 0; + } + }) + .sum(); + } catch (IOException ignored) {} + return 0; + } + private static boolean isEmpty(Path path) { if (Files.isDirectory(path)) { try (Stream entries = Files.list(path)) { @@ -136,7 +165,8 @@ public class BackupHelper { return false; } - private static boolean deleteFile(Path f, ServerCommandSource ctx) { + //1 -> ok, 0 -> err + private static int deleteFile(Path f, ServerCommandSource ctx) { if(Statics.untouchableFile.isEmpty()|| !Statics.untouchableFile.get().equals(f)) { try { Files.delete(f); @@ -144,11 +174,11 @@ public class BackupHelper { } catch (IOException e) { if(ctx.isExecutedByPlayer()) log.sendError(ctx, "Something went wrong while deleting: {}.", f); log.error("Something went wrong while deleting: {}.", f, e); - return false; + return 0; } - return true; + return 1; } - return false; + return 0; } } \ No newline at end of file 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 297be32..cbd557d 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 @@ -70,10 +70,10 @@ public class RestoreBackupRunnable implements Runnable { try { Path tmp = Files.createTempDirectory ( worldFile.getParent(), - ctx.restoreableFile().getFile().getFileName().toString() - ); + ctx.restoreableFile().getFile().getFileName().toString()); - tmp.toFile().deleteOnExit(); + //leave it as it is + //tmp.toFile().deleteOnExit(); log.info("Starting decompression..."); From 27aa40027cf5b775483cde4af6031dcc488e9f7b Mon Sep 17 00:00:00 2001 From: Szum123321 Date: Wed, 22 Jun 2022 20:02:37 +0200 Subject: [PATCH 6/6] dropped unnecessary accessors in BackupContext (record) --- gradle.properties | 6 ++-- .../textile_backup/TextileLogger.java | 8 ++--- .../core/create/BackupContext.java | 20 ----------- .../core/create/BackupHelper.java | 12 +++---- .../core/create/MakeBackupRunnable.java | 35 ++++++++----------- .../compressors/AbstractCompressor.java | 6 ++-- .../core/restore/RestoreBackupRunnable.java | 5 +-- 7 files changed, 32 insertions(+), 60 deletions(-) diff --git a/gradle.properties b/gradle.properties index 89f042a..d090592 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ yarn_mappings=1.19+build.4 loader_version=0.14.8 #Fabric api -fabric_version=0.56.0+1.19 +fabric_version=0.56.1+1.19 #Cloth Config cloth_version=7.0.72 @@ -15,12 +15,12 @@ cloth_version=7.0.72 modmenu_version=4.0.0 #Lazy DFU for faster dev start -lazydfu_version=0.1.2 +lazydfu_version=v0.1.3 #Hash of commit form which parallel gzip will be build pgzip_commit_hash=af5f5c297e735f3f2df7aa4eb0e19a5810b8aff6 # Mod Properties -mod_version = 2.3.1 +mod_version = 2.4.0 maven_group = net.szum123321 archives_base_name = textile_backup \ No newline at end of file diff --git a/src/main/java/net/szum123321/textile_backup/TextileLogger.java b/src/main/java/net/szum123321/textile_backup/TextileLogger.java index 385a32c..4485ebb 100644 --- a/src/main/java/net/szum123321/textile_backup/TextileLogger.java +++ b/src/main/java/net/szum123321/textile_backup/TextileLogger.java @@ -120,7 +120,7 @@ public class TextileLogger { } public void sendInfo(BackupContext context, String msg, Object... args) { - sendInfo(context.getCommandSource(), msg, args); + sendInfo(context.commandSource(), msg, args); } public void sendError(ServerCommandSource source, String msg, Object... args) { @@ -128,7 +128,7 @@ public class TextileLogger { } public void sendError(BackupContext context, String msg, Object... args) { - sendError(context.getCommandSource(), msg, args); + sendError(context.commandSource(), msg, args); } public void sendToPlayerAndLog(Level level, ServerCommandSource source, String msg, Object... args) { @@ -142,7 +142,7 @@ public class TextileLogger { } public void sendInfoAL(BackupContext context, String msg, Object... args) { - sendInfoAL(context.getCommandSource(), msg, args); + sendInfoAL(context.commandSource(), msg, args); } public void sendErrorAL(ServerCommandSource source, String msg, Object... args) { @@ -150,6 +150,6 @@ public class TextileLogger { } public void sendErrorAL(BackupContext context, String msg, Object... args) { - sendErrorAL(context.getCommandSource(), msg, args); + sendErrorAL(context.commandSource(), msg, args); } } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java index a132384..ad93166 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupContext.java @@ -33,18 +33,6 @@ public record BackupContext(@NotNull MinecraftServer server, boolean save, String comment) { - public MinecraftServer getServer() { - return server; - } - - public ServerCommandSource getCommandSource() { - return commandSource; - } - - public ActionInitiator getInitiator() { - return initiator; - } - public boolean startedByPlayer() { return initiator == ActionInitiator.Player; } @@ -53,14 +41,6 @@ public record BackupContext(@NotNull MinecraftServer server, return save; } - public String getComment() { - return comment; - } - - public UUID getInitiatorUUID() { - return initiator.equals(ActionInitiator.Player) && commandSource.getEntity() != null ? commandSource.getEntity().getUuid(): Util.NIL_UUID; - } - public static class Builder { private MinecraftServer server; private ServerCommandSource commandSource; diff --git a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java index a6457f7..74e8fbd 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/BackupHelper.java @@ -41,7 +41,7 @@ public class BackupHelper { public static Runnable create(BackupContext ctx) { if(config.get().broadcastBackupStart) { - Utilities.notifyPlayers(ctx.getServer(), + Utilities.notifyPlayers(ctx.server(), "Warning! Server backup will begin shortly. You may experience some lag." ); } else { @@ -52,12 +52,12 @@ public class BackupHelper { builder.append("Backup started "); - builder.append(ctx.getInitiator().getPrefix()); + builder.append(ctx.initiator().getPrefix()); if(ctx.startedByPlayer()) - builder.append(ctx.getCommandSource().getDisplayName().getString()); + builder.append(ctx.commandSource().getDisplayName().getString()); else - builder.append(ctx.getInitiator().getName()); + builder.append(ctx.initiator().getName()); builder.append(" on: "); builder.append(Utilities.getDateTimeFormatter().format(LocalDateTime.now())); @@ -67,10 +67,10 @@ public class BackupHelper { if (ctx.shouldSave()) { log.sendInfoAL(ctx, "Saving server..."); - ctx.getServer().getPlayerManager().saveAllPlayerData(); + ctx.server().getPlayerManager().saveAllPlayerData(); try { - ctx.getServer().save(false, true, true); + ctx.server().save(false, true, true); } catch (Exception e) { log.sendErrorAL(ctx,"An exception occurred when trying to save the world!"); } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java index af8ba94..9ad6aa8 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/MakeBackupRunnable.java @@ -49,32 +49,30 @@ public class MakeBackupRunnable implements Runnable { @Override public void run() { try { - Utilities.disableWorldSaving(context.getServer()); + Utilities.disableWorldSaving(context.server()); Statics.disableWatchdog = true; - Utilities.updateTMPFSFlag(context.getServer()); + Utilities.updateTMPFSFlag(context.server()); log.sendInfoAL(context, "Starting backup"); - Path world = Utilities.getWorldFolder(context.getServer()); + Path world = Utilities.getWorldFolder(context.server()); log.trace("Minecraft world is: {}", world); Path outFile = Utilities - .getBackupRootPath(Utilities.getLevelName(context.getServer())) + .getBackupRootPath(Utilities.getLevelName(context.server())) .resolve(getFileName()); + log.trace("Outfile is: {}", outFile); - // outFile.getParentFile().mkdirs(); - try { - //outFile.createNewFile(); Files.createDirectories(outFile.getParent()); Files.createFile(outFile); } catch (IOException e) { log.error("An exception occurred when trying to create new backup file!", e); - if(context.getInitiator() == ActionInitiator.Player) + if(context.initiator() == ActionInitiator.Player) log.sendError(context, "An exception occurred when trying to create new backup file!"); return; @@ -92,10 +90,13 @@ public class MakeBackupRunnable implements Runnable { switch (config.get().format) { case ZIP -> { - if (coreCount > 1 && !Statics.disableTMPFiles) + if (coreCount > 1 && !Statics.disableTMPFiles) { ParallelZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - else + log.trace("Using PARALLEL Zip Compressor. Threads: {}", coreCount); + } else { ZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); + log.trace("Using REGULAR Zip Compressor. Threads: {}"); + } } case BZIP2 -> ParallelBZip2Compressor.getInstance().createArchive(world, outFile, context, coreCount); case GZIP -> ParallelGzipCompressor.getInstance().createArchive(world, outFile, context, coreCount); @@ -105,26 +106,20 @@ public class MakeBackupRunnable implements Runnable { } }.createArchive(world, outFile, context, coreCount); case TAR -> new AbstractTarArchiver().createArchive(world, outFile, context, coreCount); - default -> { - log.warn("Specified compressor ({}) is not supported! Zip will be used instead!", config.get().format); - if (context.getInitiator() == ActionInitiator.Player) - log.sendError(context.getCommandSource(), "Error! No correct compression format specified! Using default compressor!"); - ZipCompressor.getInstance().createArchive(world, outFile, context, coreCount); - } } - BackupHelper.executeFileLimit(context.getCommandSource(), Utilities.getLevelName(context.getServer())); + BackupHelper.executeFileLimit(context.commandSource(), Utilities.getLevelName(context.server())); if(config.get().broadcastBackupDone) { Utilities.notifyPlayers( - context.getServer(), + context.server(), "Done!" ); } else { log.sendInfoAL(context, "Done!"); } } finally { - Utilities.enableWorldSaving(context.getServer()); + Utilities.enableWorldSaving(context.server()); Statics.disableWatchdog = false; } } @@ -133,7 +128,7 @@ public class MakeBackupRunnable implements Runnable { LocalDateTime now = LocalDateTime.now(); return Utilities.getDateTimeFormatter().format(now) + - (context.getComment() != null ? "#" + context.getComment().replaceAll("[\\\\/:*?\"<>|#]", "") : "") + + (context.comment() != null ? "#" + context.comment().replaceAll("[\\\\/:*?\"<>|#]", "") : "") + config.get().format.getCompleteString(); } } diff --git a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java index 125c32d..5938097 100644 --- a/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java +++ b/src/main/java/net/szum123321/textile_backup/core/create/compressors/AbstractCompressor.java @@ -53,7 +53,7 @@ public abstract class AbstractCompressor { } catch (IOException e) { log.error("An exception occurred while trying to compress: {}", inputFile.relativize(file).toString(), e); - if (ctx.getInitiator() == ActionInitiator.Player) + if (ctx.initiator() == ActionInitiator.Player) log.sendError(ctx, "Something went wrong while compressing files!"); } }); @@ -67,14 +67,14 @@ public abstract class AbstractCompressor { For help see: https://github.com/Szum123321/textile_backup/wiki/ZIP-Problems In case this isn't it here's also the exception itself""", e); - if(ctx.getInitiator() == ActionInitiator.Player) { + if(ctx.initiator() == ActionInitiator.Player) { log.sendError(ctx, "Backup failed. The file is corrupt."); log.error("For help see: https://github.com/Szum123321/textile_backup/wiki/ZIP-Problems"); } } catch (IOException | InterruptedException | ExecutionException e) { log.error("An exception occurred!", e); } catch (Exception e) { - if(ctx.getInitiator() == ActionInitiator.Player) + if(ctx.initiator() == ActionInitiator.Player) log.sendError(ctx, "Something went wrong while compressing files!"); } finally { close(); 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 cbd557d..a803d93 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 @@ -68,13 +68,10 @@ public class RestoreBackupRunnable implements Runnable { Path worldFile = Utilities.getWorldFolder(ctx.server()); try { - Path tmp = Files.createTempDirectory ( + Path tmp = Files.createTempDirectory( worldFile.getParent(), ctx.restoreableFile().getFile().getFileName().toString()); - //leave it as it is - //tmp.toFile().deleteOnExit(); - log.info("Starting decompression..."); if (ctx.restoreableFile().getArchiveFormat() == ConfigPOJO.ArchiveFormat.ZIP)