Restore no-crash behaviour when read-only config file(s) (#8318)

This commit is contained in:
karthanistyr 2022-09-17 05:22:17 +02:00
parent 39ae9b75e9
commit 24d3f7bb49

View File

@ -120,6 +120,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@
+package io.papermc.paper.configuration;
+
+import com.mojang.logging.LogUtils;
+import io.leangen.geantyref.TypeToken;
+import io.papermc.paper.configuration.constraint.Constraint;
+import io.papermc.paper.configuration.constraint.Constraints;
@ -127,6 +128,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.server.level.ServerLevel;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
+import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode;
@ -138,6 +140,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.file.AccessDeniedException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
@ -148,6 +151,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+
+public abstract class Configurations<G, W> {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+ public static final String WORLD_DEFAULTS = "__world_defaults__";
+ public static final ResourceLocation WORLD_DEFAULTS_KEY = new ResourceLocation("configurations", WORLD_DEFAULTS);
+ protected final Path globalFolder;
@ -217,6 +221,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.initializeGlobalConfiguration(creator(this.globalConfigClass, true));
+ }
+
+ private void trySaveFileNode(YamlConfigurationLoader loader, ConfigurationNode node, String filename) throws ConfigurateException {
+ try {
+ loader.save(node);
+ } catch (ConfigurateException ex) {
+ if (ex.getCause() instanceof AccessDeniedException) {
+ LOGGER.warn("Could not save {}: Paper could not persist the full set of configuration settings in the configuration file. Any setting missing from the configuration file will be set with its default value in memory. Admins should make sure to review the configuration documentation at https://docs.papermc.io/paper/configuration for more details.", filename, ex);
+ } else throw ex;
+ }
+ }
+
+ protected G initializeGlobalConfiguration(final CheckedFunction<ConfigurationNode, G, SerializationException> creator) throws ConfigurateException {
+ final Path configFile = this.globalFolder.resolve(this.globalConfigFileName);
+ final YamlConfigurationLoader loader = this.createGlobalLoaderBuilder()
@ -231,7 +245,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ this.applyGlobalConfigTransformations(node);
+ final G instance = creator.apply(node);
+ loader.save(node);
+ trySaveFileNode(loader, node, configFile.toString());
+ return instance;
+ }
+
@ -249,7 +263,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final ContextMap contextMap = this.createDefaultContextMap()
+ .put(FIRST_DEFAULT)
+ .build();
+ final DefaultWorldLoader result = this.createDefaultWorldLoader(false, contextMap);
+ final Path configFile = this.globalFolder.resolve(this.defaultWorldConfigFileName);
+ final DefaultWorldLoader result = this.createDefaultWorldLoader(false, contextMap, configFile);
+ final YamlConfigurationLoader loader = result.loader();
+ final ConfigurationNode node = loader.load();
+ if (result.isNewFile()) { // add version to new files
@ -258,11 +273,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.applyWorldConfigTransformations(contextMap, node);
+ final W instance = node.require(this.worldConfigClass);
+ node.set(this.worldConfigClass, instance);
+ loader.save(node);
+ trySaveFileNode(loader, node, configFile.toString());
+ }
+
+ private DefaultWorldLoader createDefaultWorldLoader(final boolean requireFile, final ContextMap contextMap) {
+ final Path configFile = this.globalFolder.resolve(this.defaultWorldConfigFileName);
+ private DefaultWorldLoader createDefaultWorldLoader(final boolean requireFile, final ContextMap contextMap, final Path configFile) {
+ boolean willCreate = Files.notExists(configFile);
+ if (requireFile && willCreate) {
+ throw new IllegalStateException("World defaults configuration file '" + configFile + "' doesn't exist");
@ -294,7 +308,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+
+ protected W createWorldConfig(final ContextMap contextMap, final CheckedFunction<ConfigurationNode, W, SerializationException> creator) throws IOException {
+ final YamlConfigurationLoader defaultsLoader = this.createDefaultWorldLoader(true, this.createDefaultContextMap().build()).loader();
+ final Path defaultsConfigFile = this.globalFolder.resolve(this.defaultWorldConfigFileName);
+ final YamlConfigurationLoader defaultsLoader = this.createDefaultWorldLoader(true, this.createDefaultContextMap().build(), defaultsConfigFile).loader();
+ final ConfigurationNode defaultsNode = defaultsLoader.load();
+
+ boolean newFile = false;
@ -316,7 +331,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }
+ this.applyWorldConfigTransformations(contextMap, worldNode);
+ this.applyDefaultsAwareWorldConfigTransformations(contextMap, worldNode, defaultsNode);
+ worldLoader.save(worldNode); // save before loading node NOTE: don't save the backing node after loading it, or you'll fill up the world-specific config
+ trySaveFileNode(worldLoader, worldNode, worldConfigFile.toString()); // save before loading node NOTE: don't save the backing node after loading it, or you'll fill up the world-specific config
+ worldNode.mergeFrom(defaultsNode);
+ return creator.apply(worldNode);
+ }
@ -4265,6 +4280,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
diff --git a/src/main/java/net/minecraft/server/dedicated/Settings.java b/src/main/java/net/minecraft/server/dedicated/Settings.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/dedicated/Settings.java
+++ b/src/main/java/net/minecraft/server/dedicated/Settings.java
@@ -0,0 +0,0 @@ public abstract class Settings<T extends Settings<T>> {
try {
// CraftBukkit start - Don't attempt writing to file if it's read only
if (path.toFile().exists() && !path.toFile().canWrite()) {
+ Settings.LOGGER.warn("Can not write to file {}, skipping.", path); // Paper
return;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java