229 lines
18 KiB
Diff
229 lines
18 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Xymb <xymb@endcrystal.me>
|
|
Date: Fri, 14 Apr 2023 02:12:58 +0200
|
|
Subject: [PATCH] Crash on broken symlink
|
|
|
|
|
|
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
|
|
index bac11b0e30a86d0689693ff129b53bcad7c2034c..0f0cfd958f7d2c6d2ca4192be1b986900a2bfa53 100644
|
|
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
|
|
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuWorldConfig.java
|
|
@@ -127,6 +127,7 @@ public class KaiijuWorldConfig {
|
|
|
|
public List<String> regionFormatList = Arrays.asList("ANVIL", "LINEAR");
|
|
public String regionFormatName = "ANVIL";
|
|
+ public boolean linearCrashOnBrokenSymlink = true;
|
|
public int regionFormatLinearCompressionLevel = 1;
|
|
|
|
private void regionFormatSettings() {
|
|
@@ -142,6 +143,7 @@ public class KaiijuWorldConfig {
|
|
log(Level.SEVERE, "Falling back to compression level 1.");
|
|
regionFormatLinearCompressionLevel = 1;
|
|
}
|
|
+ linearCrashOnBrokenSymlink = getBoolean("region-format.linear.crash-on-broken-symlink", linearCrashOnBrokenSymlink);
|
|
}
|
|
|
|
public boolean shulkerBoxDropContentsWhenDestroyed = true;
|
|
diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
|
index a62a1b281bd0b6ad7d59b45b9470d84f496f6539..7f87dfa131ab7d40a94cf6355765478f2961342e 100644
|
|
--- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
|
+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
|
@@ -86,10 +86,11 @@ public class ThreadedWorldUpgrader {
|
|
// Kaiiju start
|
|
String formatName = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.regionFormatName;
|
|
int linearCompression = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.regionFormatLinearCompressionLevel;
|
|
+ boolean linearCrashOnBrokenSymlink = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.linearCrashOnBrokenSymlink;
|
|
LOGGER.info("Using format " + formatName + " (" + linearCompression + ")");
|
|
// Kaiiju end
|
|
final WorldInfo info = new WorldInfo(() -> worldPersistentData,
|
|
- new ChunkStorage(formatName, linearCompression, regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey); // Kaiiju
|
|
+ new ChunkStorage(formatName, linearCompression, linearCrashOnBrokenSymlink, regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey); // Kaiiju
|
|
|
|
long expectedChunks = (long)regionFiles.length * (32L * 32L);
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index 5ad209fed6aef1992af0472ac0af0911d178a260..0ef89e0bc214364fd904c3e5022c660b32b2caaa 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -272,7 +272,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Paper end
|
|
|
|
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
|
- super(world.getLevel().kaiijuConfig.regionFormatName, world.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Kaiiju
|
|
+ super(world.getLevel().kaiijuConfig.regionFormatName, world.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, world.getLevel().kaiijuConfig.linearCrashOnBrokenSymlink, session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Kaiiju
|
|
// Paper - rewrite chunk system
|
|
this.tickingGenerated = new AtomicInteger();
|
|
//this.playerMap = new PlayerMap(); // Folia - region threading
|
|
@@ -317,7 +317,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), null, null); // Paper - rewrite chunk system
|
|
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
|
|
this.overworldDataStorage = persistentStateManagerFactory;
|
|
- this.poiManager = new PoiManager(this.level.kaiijuConfig.regionFormatName, this.level.kaiijuConfig.regionFormatLinearCompressionLevel, path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); // Kaiiju
|
|
+ this.poiManager = new PoiManager(this.level.kaiijuConfig.regionFormatName, this.level.kaiijuConfig.regionFormatLinearCompressionLevel, this.level.kaiijuConfig.linearCrashOnBrokenSymlink, path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); // Kaiiju
|
|
this.setViewDistance(viewDistance);
|
|
// Paper start
|
|
this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index 20359c63b19c7e0c703ef1562fb774803d631c41..35ae624be25b66d5615dc19cbe7eb8785c7029b5 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -425,8 +425,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
private final EntityRegionFileStorage entityStorage;
|
|
|
|
private static final class EntityRegionFileStorage extends net.minecraft.world.level.chunk.storage.RegionFileStorage {
|
|
- public EntityRegionFileStorage(String format, int linearCompression, Path directory, boolean dsync) { // Kaiiju
|
|
- super(format, linearCompression, directory, dsync); // Kaiiju
|
|
+ public EntityRegionFileStorage(String format, int linearCompression, boolean linearCrashOnBrokenSymlink, Path directory, boolean dsync) { // Kaiiju
|
|
+ super(format, linearCompression, linearCrashOnBrokenSymlink, directory, dsync); // Kaiiju
|
|
}
|
|
|
|
protected void write(ChunkPos pos, net.minecraft.nbt.CompoundTag nbt) throws IOException {
|
|
@@ -632,7 +632,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
// CraftBukkit end
|
|
boolean flag2 = minecraftserver.forceSynchronousWrites();
|
|
DataFixer datafixer = minecraftserver.getFixerUpper();
|
|
- this.entityStorage = new EntityRegionFileStorage(this.getLevel().kaiijuConfig.regionFormatName, this.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); // Kaiiju
|
|
+ this.entityStorage = new EntityRegionFileStorage(this.getLevel().kaiijuConfig.regionFormatName, this.getLevel().kaiijuConfig.regionFormatLinearCompressionLevel, this.getLevel().kaiijuConfig.linearCrashOnBrokenSymlink, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); // Kaiiju
|
|
|
|
// this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper // Paper - rewrite chunk system
|
|
StructureTemplateManager structuretemplatemanager = minecraftserver.getStructureManager();
|
|
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
index 469802b9c454c5e98c0a55ba89559d9d8ba0c4c0..1652398c211c4366dde1d973bdb8e9d2c5c67ff4 100644
|
|
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
@@ -119,7 +119,8 @@ public class WorldUpgrader {
|
|
String worldName = this.levelStorage.getLevelId();
|
|
String formatName = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.regionFormatName;
|
|
int linearCompression = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.regionFormatLinearCompressionLevel;
|
|
- builder1.put(resourcekey1, new ChunkStorage(formatName, linearCompression, path.resolve("region"), this.dataFixer, true));
|
|
+ boolean linearCrashOnBrokenSymlink = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(worldName)).getHandle().kaiijuConfig.linearCrashOnBrokenSymlink;
|
|
+ builder1.put(resourcekey1, new ChunkStorage(formatName, linearCompression, linearCrashOnBrokenSymlink, path.resolve("region"), this.dataFixer, true));
|
|
// Kaiiju end
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
|
index f560aa13c6c8ffecb456f478687dc6a9eb5e8017..f0354203f974a8d7440407a5561ffa0fcb63182d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java
|
|
@@ -59,8 +59,8 @@ public class PoiManager extends SectionStorage<PoiSection> {
|
|
// Paper end - rewrite chunk system
|
|
|
|
|
|
- public PoiManager(String formatName, int linearCompression, Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { // Kaiiju
|
|
- super(formatName, linearCompression, path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); // Kaiiju
|
|
+ public PoiManager(String formatName, int linearCompression, boolean linearCrashOnBrokenSymlink, Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { // Kaiiju
|
|
+ super(formatName, linearCompression, linearCrashOnBrokenSymlink, path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); // Kaiiju
|
|
this.world = (net.minecraft.server.level.ServerLevel)world; // Paper - rewrite chunk system
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
|
index 52c2e0fe73a5af18535a2b0b9a506919e3f93003..ea54af3f68c6534ff5a71ca0b7a99d126557868e 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
|
@@ -37,12 +37,12 @@ public class ChunkStorage implements AutoCloseable {
|
|
public final RegionFileStorage regionFileCache;
|
|
// Paper end - async chunk loading
|
|
|
|
- public ChunkStorage(String format, int linearCompression, Path directory, DataFixer dataFixer, boolean dsync) { // Kaiiju
|
|
+ public ChunkStorage(String format, int linearCompression, boolean linearCrashOnBrokenSymlink, Path directory, DataFixer dataFixer, boolean dsync) { // Kaiiju
|
|
this.fixerUpper = dataFixer;
|
|
|
|
// Paper start - async chunk io
|
|
// remove IO worker
|
|
- this.regionFileCache = new RegionFileStorage(format, linearCompression, directory, dsync, true); // Paper - nuke IOWorker // Paper
|
|
+ this.regionFileCache = new RegionFileStorage(format, linearCompression, linearCrashOnBrokenSymlink, directory, dsync, true); // Paper - nuke IOWorker // Paper
|
|
// Paper end - async chunk io
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
index c9fbba6f709ed0540dcc22b41e50ce9d01a6381c..70e3ee306283263cdcdb7a66c80fc23484385aac 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
|
@@ -20,6 +20,7 @@ import net.minecraft.world.level.ChunkPos;
|
|
|
|
public class RegionFileStorage implements AutoCloseable {
|
|
|
|
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Kaiiju
|
|
public static final String ANVIL_EXTENSION = ".mca";
|
|
private static final int MAX_CACHE_SIZE = 256;
|
|
public final Long2ObjectLinkedOpenHashMap<dev.kaiijumc.kaiiju.region.AbstractRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap(); // Kaiiju
|
|
@@ -28,6 +29,7 @@ public class RegionFileStorage implements AutoCloseable {
|
|
// Kaiiju start - Per world chunk format
|
|
public final String format;
|
|
public final int linearCompression;
|
|
+ public final boolean linearCrashOnBrokenSymlink;
|
|
// Kaiiju end
|
|
|
|
private final boolean isChunkData; // Paper
|
|
@@ -61,14 +63,15 @@ public class RegionFileStorage implements AutoCloseable {
|
|
}
|
|
// Paper end - cache regionfile does not exist state
|
|
|
|
- protected RegionFileStorage(String format, int linearCompression, Path directory, boolean dsync) { // Paper - protected constructor
|
|
+ protected RegionFileStorage(String format, int linearCompression, boolean linearCrashOnBrokenSymlink, Path directory, boolean dsync) { // Paper - protected constructor
|
|
// Paper start - add isChunkData param
|
|
- this(format, linearCompression, directory, dsync, false);
|
|
+ this(format, linearCompression, linearCrashOnBrokenSymlink, directory, dsync, false);
|
|
}
|
|
- RegionFileStorage(String format, int linearCompression, Path directory, boolean dsync, boolean isChunkData) { // Kaiiju
|
|
+ RegionFileStorage(String format, int linearCompression, boolean linearCrashOnBrokenSymlink, Path directory, boolean dsync, boolean isChunkData) { // Kaiiju
|
|
// Kaiiju start
|
|
this.format = format;
|
|
this.linearCompression = linearCompression;
|
|
+ this.linearCrashOnBrokenSymlink = linearCrashOnBrokenSymlink;
|
|
// Kaiiju end
|
|
this.isChunkData = isChunkData;
|
|
// Paper end - add isChunkData param
|
|
@@ -109,6 +112,20 @@ public class RegionFileStorage implements AutoCloseable {
|
|
return regionfile != null ? regionfile.hasChunk(pos) : false;
|
|
}
|
|
|
|
+ // Kaiiju start
|
|
+ private void guardAgainstBrokenSymlinks(Path path) throws IOException {
|
|
+ if (!linearCrashOnBrokenSymlink) return;
|
|
+ if (!this.format.equals("LINEAR")) return;
|
|
+ if (!java.nio.file.Files.isSymbolicLink(path)) return;
|
|
+ Path link = java.nio.file.Files.readSymbolicLink(path);
|
|
+ if (!java.nio.file.Files.exists(link) || !java.nio.file.Files.isReadable(link)) {
|
|
+ LOGGER.error("Linear region file {} is a broken symbolic link, crashing to prevent data loss", path);
|
|
+ net.minecraft.server.MinecraftServer.getServer().halt(false);
|
|
+ throw new IOException("Linear region file " + path + " is a broken symbolic link, crashing to prevent data loss");
|
|
+ }
|
|
+ }
|
|
+ // Kaiiju end
|
|
+
|
|
public synchronized dev.kaiijumc.kaiiju.region.AbstractRegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Kaiiju
|
|
return this.getRegionFile(chunkcoordintpair, existingOnly, false);
|
|
}
|
|
@@ -144,6 +161,7 @@ public class RegionFileStorage implements AutoCloseable {
|
|
if (existingOnly) {
|
|
Path anvil = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
|
|
Path linear = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".linear");
|
|
+ guardAgainstBrokenSymlinks(linear);
|
|
if (java.nio.file.Files.exists(anvil)) path1 = anvil;
|
|
else if (java.nio.file.Files.exists(linear)) path1 = linear;
|
|
else {
|
|
@@ -156,6 +174,7 @@ public class RegionFileStorage implements AutoCloseable {
|
|
default -> "mca";
|
|
};
|
|
path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + "." + extension);
|
|
+ guardAgainstBrokenSymlinks(path1);
|
|
this.createRegionFile(regionPos);
|
|
}
|
|
if (dev.kaiijumc.kaiiju.KaiijuConfig.regionFormatDebug)
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
index 414aa3ae00c2d28e754235e3e93b6b623d4fd180..15e376fac063430e4355c6ffcd25c35a8ce20c5b 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java
|
|
@@ -47,8 +47,8 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl
|
|
public final RegistryAccess registryAccess; // Paper - rewrite chunk system
|
|
protected final LevelHeightAccessor levelHeightAccessor;
|
|
|
|
- public SectionStorage(String format, int linearCompression, Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) { // Kaiiju
|
|
- super(format, linearCompression, path, dsync); // Paper - remove mojang I/O thread // Kaiiju
|
|
+ public SectionStorage(String format, int linearCompression, boolean linearCrashOnBrokenSymlink, Path path, Function<Runnable, Codec<R>> codecFactory, Function<Runnable, R> factory, DataFixer dataFixer, DataFixTypes dataFixTypes, boolean dsync, RegistryAccess dynamicRegistryManager, LevelHeightAccessor world) { // Kaiiju
|
|
+ super(format, linearCompression, linearCrashOnBrokenSymlink, path, dsync); // Paper - remove mojang I/O thread // Kaiiju
|
|
this.codec = codecFactory;
|
|
this.factory = factory;
|
|
this.fixerUpper = dataFixer;
|