From 48ef3550aaa6144539c4b896599ba8a830a9d723 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 5 Aug 2022 23:06:53 +0100 Subject: [PATCH] Fallback to a separate file when using a file system that does not attributes. Fixes #696 --- .../fabricmc/loom/util/AttributeHelper.java | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/util/AttributeHelper.java b/src/main/java/net/fabricmc/loom/util/AttributeHelper.java index 587927bb..dc5d8f29 100644 --- a/src/main/java/net/fabricmc/loom/util/AttributeHelper.java +++ b/src/main/java/net/fabricmc/loom/util/AttributeHelper.java @@ -27,6 +27,8 @@ package net.fabricmc.loom.util; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystemException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.UserDefinedFileAttributeView; @@ -37,25 +39,55 @@ public final class AttributeHelper { } public static Optional readAttribute(Path path, String key) throws IOException { - final UserDefinedFileAttributeView attributeView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); + final Path attributesFile = getFallbackPath(path, key); - if (!attributeView.list().contains(key)) { - return Optional.empty(); + if (exists(attributesFile)) { + // Use the fallback file if it exists. + return Optional.of(Files.readString(attributesFile, StandardCharsets.UTF_8)); } - final ByteBuffer buffer = ByteBuffer.allocate(attributeView.size(key)); - attributeView.read(key, buffer); - buffer.flip(); - final String value = StandardCharsets.UTF_8.decode(buffer).toString(); - return Optional.of(value); + try { + final UserDefinedFileAttributeView attributeView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); + + if (!attributeView.list().contains(key)) { + return Optional.empty(); + } + + final ByteBuffer buffer = ByteBuffer.allocate(attributeView.size(key)); + attributeView.read(key, buffer); + buffer.flip(); + final String value = StandardCharsets.UTF_8.decode(buffer).toString(); + return Optional.of(value); + } catch (FileSystemException ignored) { + return Optional.empty(); + } } public static void writeAttribute(Path path, String key, String value) throws IOException { - // TODO may need to fallback to creating a separate file if this isnt supported. - final UserDefinedFileAttributeView attributeView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); - final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - final ByteBuffer buffer = ByteBuffer.wrap(bytes); - final int written = attributeView.write(key, buffer); - assert written == bytes.length; + final Path attributesFile = getFallbackPath(path, key); + + try { + final UserDefinedFileAttributeView attributeView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); + final byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + final ByteBuffer buffer = ByteBuffer.wrap(bytes); + final int written = attributeView.write(key, buffer); + assert written == bytes.length; + + if (exists(attributesFile)) { + Files.delete(attributesFile); + } + } catch (FileSystemException ignored) { + // Fallback to a separate file when using a file system that does not attributes. + Files.writeString(attributesFile, value, StandardCharsets.UTF_8); + } + } + + private static Path getFallbackPath(Path path, String key) { + return path.resolveSibling(path.getFileName() + "." + key + ".att"); + } + + // A faster exists check + private static boolean exists(Path path) { + return path.getFileSystem() == FileSystems.getDefault() ? path.toFile().exists() : Files.exists(path); } }