Workaround Java breaking with symlinks (fixes #660)

This commit is contained in:
Jonas Herzig
2022-02-28 15:57:35 +01:00
parent abfb3d46f3
commit 6cc370a117
5 changed files with 21 additions and 7 deletions

View File

@@ -22,6 +22,7 @@ import java.nio.file.WatchService;
import java.util.List;
import java.util.Map;
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
import static com.replaymod.core.versions.MCVer.getMinecraft;
class SettingsRegistryBackend {
@@ -179,7 +180,7 @@ class SettingsRegistryBackend {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String config = gson.toJson(root);
try {
Files.createDirectories(configFile.getParent());
ensureDirectoryExists(configFile.getParent());
Files.write(configFile, config.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();

View File

@@ -10,6 +10,8 @@ import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import static com.replaymod.core.utils.Utils.ensureDirectoryExists;
public class ReplayFoldersService {
private final Path mcDir = MinecraftClient.getInstance().runDirectory.toPath();
private final SettingsRegistry settings;
@@ -19,14 +21,14 @@ public class ReplayFoldersService {
}
public Path getReplayFolder() throws IOException {
return Files.createDirectories(mcDir.resolve(settings.get(Setting.RECORDING_PATH)));
return ensureDirectoryExists(mcDir.resolve(settings.get(Setting.RECORDING_PATH)));
}
/**
* Folder into which replay backups are saved before the MarkerProcessor is unleashed.
*/
public Path getRawReplayFolder() throws IOException {
return Files.createDirectories(getReplayFolder().resolve("raw"));
return ensureDirectoryExists(getReplayFolder().resolve("raw"));
}
/**
@@ -34,7 +36,7 @@ public class ReplayFoldersService {
* Distinct from the main folder, so they cannot be opened while they are still saving.
*/
public Path getRecordingFolder() throws IOException {
return Files.createDirectories(getReplayFolder().resolve("recording"));
return ensureDirectoryExists(getReplayFolder().resolve("recording"));
}
/**
@@ -42,7 +44,7 @@ public class ReplayFoldersService {
* Distinct from the recording folder cause people kept confusing them with recordings.
*/
public Path getCacheFolder() throws IOException {
Path path = Files.createDirectories(mcDir.resolve(settings.get(Setting.CACHE_PATH)));
Path path = ensureDirectoryExists(mcDir.resolve(settings.get(Setting.CACHE_PATH)));
try {
Files.setAttribute(path, "dos:hidden", true);
} catch (UnsupportedOperationException ignored) {

View File

@@ -57,6 +57,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -356,4 +359,14 @@ public class Utils {
configure.accept(instance);
return instance;
}
/**
* Like {@link Files#createDirectories(Path, FileAttribute[])} but doesn't explode if it's a symlink.
*/
public static Path ensureDirectoryExists(Path path) throws IOException {
// Who in their right mind thought the default behavior of throwing when the target is a link to a directory
// was the preferred behavior?! Everyone has to fall for this at least once to learn it...
// https://bugs.openjdk.java.net/browse/JDK-8130464
return Files.createDirectories(Files.exists(path) ? path.toRealPath() : path);
}
}

View File

@@ -133,7 +133,6 @@ public class MarkerProcessor {
for (int i = 1; Files.exists(inputPath); i++) {
inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr");
}
Files.createDirectories(inputPath.getParent());
Files.move(path, inputPath);
try (ReplayFile inputReplayFile = mod.files.open(inputPath)) {

View File

@@ -285,7 +285,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter {
for (int i = 1; Files.exists(rawPath); i++) {
rawPath = rawPath.resolveSibling(replayName + "." + i + ".mcpr");
}
Files.createDirectories(rawPath.getParent());
replayFile.saveTo(rawPath.toFile());
replayFile.close();