diff options
Diffstat (limited to 'Spigot-Server-Patches/0322-Detect-and-repair-corrupt-Region-Files.patch')
-rw-r--r-- | Spigot-Server-Patches/0322-Detect-and-repair-corrupt-Region-Files.patch | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/Spigot-Server-Patches/0322-Detect-and-repair-corrupt-Region-Files.patch b/Spigot-Server-Patches/0322-Detect-and-repair-corrupt-Region-Files.patch new file mode 100644 index 0000000000..a6ed81b198 --- /dev/null +++ b/Spigot-Server-Patches/0322-Detect-and-repair-corrupt-Region-Files.patch @@ -0,0 +1,139 @@ +From 4c3edd05499f6111fd2b4feadc51ebb6a864be3d Mon Sep 17 00:00:00 2001 +From: Aikar <[email protected]> +Date: Sat, 11 Aug 2018 00:49:20 -0400 +Subject: [PATCH] Detect and repair corrupt Region Files + +If the file has partial data written but not the full 8192 bytes, +then the server will be unable to load that region file... + +I don't know why mojang only checks for 4096, when anything less than 8192 is a crash. + +But to be safe, it will attempt to back up the file. + +diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java +index e2d4450e90..c20511588d 100644 +--- a/src/main/java/net/minecraft/server/RegionFile.java ++++ b/src/main/java/net/minecraft/server/RegionFile.java +@@ -25,10 +25,10 @@ public class RegionFile { + private static final boolean ENABLE_EXTENDED_SAVE = Boolean.parseBoolean(System.getProperty("net.minecraft.server.RegionFile.enableExtendedSave", "true")); + // Spigot end + private static final byte[] a = new byte[4096]; +- private final File b; +- private RandomAccessFile c; +- private final int[] d = new int[1024]; +- private final int[] e = new int[1024]; ++ private final File b;private File getFile() { return b; } // Paper - OBFHELPER ++ private RandomAccessFile c;private RandomAccessFile getDataFile() { return c; } // Paper - OBFHELPER ++ private final int[] d = new int[1024];private int[] offsets = d; // Paper - OBFHELPER ++ private final int[] e = new int[1024];private int[] timestamps = e; // Paper - OBFHELPER + private List<Boolean> f; + private int g; + private long h; +@@ -43,7 +43,7 @@ public class RegionFile { + } + + this.c = new RandomAccessFile(file, "rw"); +- if (this.c.length() < 4096L) { ++ if (this.c.length() < 8192L) { // Paper - headers should be 8192 + this.c.write(RegionFile.a); + this.c.write(RegionFile.a); + this.g += 8192; +@@ -93,22 +93,23 @@ public class RegionFile { + this.c.seek(j * 4 + 4); // Go back to where we were + } + } +- if (k != 0 && (k >> 8) + (length) <= this.f.size()) { ++ if (k > 0 && (k >> 8) > 1 && (k >> 8) + (k & 255) <= this.f.size()) { // Paper >= 1 as 0/1 are the headers, and negative isnt valid + for (int l = 0; l < (length); ++l) { + // Spigot end + this.f.set((k >> 8) + l, false); + } + } + // Spigot start +- else if (length > 0) { +- org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Length: {3} runs off end file. {4}", new Object[]{j % 32, (int) (j / 32), k >> 8, length, file}); ++ else if (k != 0) { // Paper ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Invalid chunk: ({0}, {1}) Offset: {2} Length: {3} runs off end file. {4}", new Object[]{j % 32, (int) (j / 32), k >> 8, length, file}); // Paper ++ deleteChunk(j); // Paper + } + // Spigot end + } + + for (j = 0; j < 1024; ++j) { + k = headerAsInts.get(); // Paper +- this.e[j] = k; ++ if (offsets[j] != 0) this.timestamps[j] = k; // Paper - don't set timestamp if it got 0'd above due to corruption + } + } catch (IOException ioexception) { + ioexception.printStackTrace(); +@@ -144,10 +145,10 @@ public class RegionFile { + int j1 = this.c.readInt(); + + if (j1 > 4096 * i1) { +- org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3}>{4} {5}", new Object[]{i, j, l, j1, i1 * 4096, this.b}); // Spigot ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3}>{4} {5}", new Object[]{i, j, l, j1, i1 * 4096, this.b}); // Spigot + return null; + } else if (j1 <= 0) { +- org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.WARNING, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3} {4}", new Object[]{i, j, l, j1, this.b}); // Spigot ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Invalid chunk: ({0}, {1}) Offset: {2} Invalid Size: {3} {4}", new Object[]{i, j, l, j1, this.b}); // Spigot + return null; + } else { + byte b0 = this.c.readByte(); +@@ -327,6 +328,54 @@ public class RegionFile { + + } + ++ // Paper start ++ public synchronized void deleteChunk(int j1) { ++ backup(); ++ int k = offsets[j1]; ++ int x = j1 & 1024; ++ int z = j1 >> 2; ++ int offset = (k >> 8); ++ int len = (k & 255); ++ String debug = "idx:" + + j1 + " - " + x + "," + z + " - offset: " + offset + " - len: " + len; ++ try { ++ timestamps[j1] = 0; ++ offsets[j1] = 0; ++ RandomAccessFile file = getDataFile(); ++ file.seek(j1 * 4); ++ file.writeInt(0); ++ // clear the timestamp ++ file.seek(4096 + j1 * 4); ++ file.writeInt(0); ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Deleted corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e); ++ } catch (IOException e) { ++ ++ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Error deleting corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e); ++ } ++ } ++ private boolean backedUp = false; ++ private synchronized void backup() { ++ if (backedUp) { ++ return; ++ } ++ backedUp = true; ++ File file = this.getFile(); ++ java.text.DateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd"); ++ java.util.Date today = new java.util.Date(); ++ File corrupt = new File(file.getParentFile(), file.getName() + "." + formatter.format(today) + ".corrupt"); ++ if (corrupt.exists()) { ++ return; ++ } ++ org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(); ++ logger.error("Region file " + file.getAbsolutePath() + " was corrupt. Backing up to " + corrupt.getAbsolutePath() + " and repairing"); ++ try { ++ java.nio.file.Files.copy(file.toPath(), corrupt.toPath()); ++ ++ } catch (IOException e) { ++ logger.error("Error backing up corrupt file" + file.getAbsolutePath(), e); ++ } ++ } ++ // Paper end ++ + class ChunkBuffer extends ByteArrayOutputStream { + + private final int b; +-- +2.21.0 + |