228 lines
19 KiB
Diff
228 lines
19 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 55dcbb48450b24f80e0a04bedeb54f64e94ebb9e..f3f824d0ab1a2a72825c40b67192386479a0b34c 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 RegionFileFormat regionFormatName = RegionFileFormat.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 abf5e2a06af9853b58ac9107cd6e9787c4185c66..389c68c0becd2f69dc1004d0b383f1a8784214c0 100644
|
|
--- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
|
+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
|
@@ -87,10 +87,11 @@ public class ThreadedWorldUpgrader {
|
|
// Kaiiju start
|
|
dev.kaiijumc.kaiiju.region.RegionFileFormat 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 61c6bc2859235874aefac71e9e55162f0a89f29f..24bd63c596c9f61f1e89ec5b001b7cb7a29a09ff 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -269,7 +269,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
|
|
@@ -314,7 +314,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 4774d3f357d62b0818b4713f8085d05be09eaa5c..1bbd8b475cdc57fb15ca05ffe122220a5539da10 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -426,8 +426,8 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
|
|
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(dev.kaiijumc.kaiiju.region.RegionFileFormat 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 {
|
|
@@ -666,7 +666,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 ac35e7eb8cb5f19391a18eb9d6b5ba26769ce2f6..a9c6ca7c621bb2431bcf0ae879b192f748bf931b 100644
|
|
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
|
@@ -120,7 +120,8 @@ public class WorldUpgrader {
|
|
String worldName = this.levelStorage.getLevelId();
|
|
dev.kaiijumc.kaiiju.region.RegionFileFormat 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 187ff795192c7eb56dffafa1ff6fa3068ac341c3..b9cf3b9f2cdb554d267c6dc3436e011c7e607228 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(dev.kaiijumc.kaiiju.region.RegionFileFormat 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(dev.kaiijumc.kaiiju.region.RegionFileFormat 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 1d880f27dd147da683fc30ed6f1bfa43ecdb7d93..41598adf6d49a44bcaadfff3797221460a6d93ba 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,11 +37,11 @@ public class ChunkStorage implements AutoCloseable {
|
|
public final RegionFileStorage regionFileCache;
|
|
// Paper end - async chunk loading
|
|
|
|
- public ChunkStorage(dev.kaiijumc.kaiiju.region.RegionFileFormat format, int linearCompression, Path directory, DataFixer dataFixer, boolean dsync) { // Kaiiju
|
|
+ public ChunkStorage(dev.kaiijumc.kaiiju.region.RegionFileFormat 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 b35a6a7daf768af3bc453fe18deec823f4b63a3a..8409293b3f329715d6dff3d455c6a484d5b133ee 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 dev.kaiijumc.kaiiju.region.RegionFileFormat format;
|
|
public final int linearCompression;
|
|
+ public final boolean linearCrashOnBrokenSymlink;
|
|
// Kaiiju end
|
|
private final boolean isChunkData; // Paper
|
|
|
|
@@ -60,14 +62,15 @@ public class RegionFileStorage implements AutoCloseable {
|
|
}
|
|
// Paper end - cache regionfile does not exist state
|
|
|
|
- protected RegionFileStorage(dev.kaiijumc.kaiiju.region.RegionFileFormat format, int linearCompression, Path directory, boolean dsync) { // Paper - protected constructor
|
|
+ protected RegionFileStorage(dev.kaiijumc.kaiiju.region.RegionFileFormat 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(dev.kaiijumc.kaiiju.region.RegionFileFormat format, int linearCompression, Path directory, boolean dsync, boolean isChunkData) { // Kaiiju
|
|
+ RegionFileStorage(dev.kaiijumc.kaiiju.region.RegionFileFormat 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
|
|
@@ -111,6 +114,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);
|
|
}
|
|
@@ -146,6 +163,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 {
|
|
@@ -161,6 +179,7 @@ public class RegionFileStorage implements AutoCloseable {
|
|
};
|
|
path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + "." + extension);
|
|
// Kaiiju end
|
|
+ guardAgainstBrokenSymlinks(path1); // Kaiiju - Crash on broken symlink
|
|
this.createRegionFile(regionPos);
|
|
}
|
|
// Kaiiju start - Polyglot
|
|
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 9394d191c56aab78e63fd3f283efedd69384e323..dcfe4a285cc5865be3b0c1b8104b722895135dd0 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(dev.kaiijumc.kaiiju.region.RegionFileFormat 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(dev.kaiijumc.kaiiju.region.RegionFileFormat 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;
|