1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-15 12:40:30 +00:00

Check the filesystem for isReadOnly (#1226)

This commit is contained in:
Drew Edwards 2022-11-25 20:40:40 +00:00 committed by GitHub
parent b8fce1eecc
commit 47816805fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 2 deletions

View File

@ -78,4 +78,15 @@ public interface IWritableMount extends IMount {
default OptionalLong getCapacity() { default OptionalLong getCapacity() {
return OptionalLong.empty(); return OptionalLong.empty();
} }
/**
* Returns whether a file with a given path is read-only or not.
*
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms".
* @return If the file exists and is read-only.
* @throws IOException If an error occurs when checking whether the file is read-only.
*/
default boolean isReadOnly(String path) throws IOException {
return false;
}
} }

View File

@ -143,6 +143,16 @@ public class FileMount implements IWritableMount {
return file.exists() && file.isDirectory(); return file.exists() && file.isDirectory();
} }
@Override
public boolean isReadOnly(String path) throws IOException {
var file = getRealPath(path);
while (true) {
if (file.exists()) return !file.canWrite();
if (file.equals(rootPath)) return false;
file = file.getParentFile();
}
}
@Override @Override
public void list(String path, List<String> contents) throws IOException { public void list(String path, List<String> contents) throws IOException {
if (!created()) { if (!created()) {

View File

@ -94,6 +94,15 @@ public class FileSystemWrapperMount implements IFileSystem {
} }
} }
@Override
public boolean isReadOnly(String path) throws IOException {
try {
return filesystem.isReadOnly(path);
} catch (FileSystemException e) {
throw new IOException(e.getMessage());
}
}
@Override @Override
public void list(String path, List<String> contents) throws IOException { public void list(String path, List<String> contents) throws IOException {
try { try {

View File

@ -61,8 +61,12 @@ class MountWrapper {
return writableMount == null ? OptionalLong.empty() : writableMount.getCapacity(); return writableMount == null ? OptionalLong.empty() : writableMount.getCapacity();
} }
public boolean isReadOnly(String path) { public boolean isReadOnly(String path) throws FileSystemException {
return writableMount == null; try {
return writableMount == null || writableMount.isReadOnly(path);
} catch (IOException e) {
throw localExceptionOf(path, e);
}
} }
public boolean exists(String path) throws FileSystemException { public boolean exists(String path) throws FileSystemException {

View File

@ -0,0 +1,75 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core.filesystem;
import com.google.common.io.MoreFiles;
import com.google.common.io.RecursiveDeleteOption;
import dan200.computercraft.api.filesystem.IWritableMount;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class FileMountTest {
private static final long CAPACITY = 1_000_000;
private final List<Path> cleanup = new ArrayList<>();
@AfterEach
public void cleanup() throws IOException {
for (var mount : cleanup) MoreFiles.deleteRecursively(mount, RecursiveDeleteOption.ALLOW_INSECURE);
}
private Path createRoot() throws IOException {
var path = Files.createTempDirectory("cctweaked-test");
cleanup.add(path);
return path;
}
private IWritableMount getExisting(long capacity) throws IOException {
return new FileMount(createRoot().toFile(), capacity);
}
private IWritableMount getNotExisting(long capacity) throws IOException {
return new FileMount(createRoot().resolve("mount").toFile(), capacity);
}
@Test
public void testRootWritable() throws IOException {
assertFalse(getExisting(CAPACITY).isReadOnly("/"));
assertFalse(getNotExisting(CAPACITY).isReadOnly("/"));
}
@Test
public void testMissingDirWritable() throws IOException {
assertFalse(getExisting(CAPACITY).isReadOnly("/foo/bar/baz/qux"));
}
@Test
public void testDirReadOnly() throws IOException {
var root = createRoot();
var mount = new FileMount(root.toFile(), CAPACITY);
mount.makeDirectory("read-only");
var attributes = Files.getFileAttributeView(root.resolve("read-only"), PosixFileAttributeView.class);
Assumptions.assumeTrue(attributes != null, "POSIX attributes are not available.");
assertFalse(mount.isReadOnly("read-only"), "Directory should not be read-only yet");
attributes.setPermissions(Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_EXECUTE));
assertTrue(mount.isReadOnly("read-only"), "Directory should not be read-only yet");
assertTrue(mount.isReadOnly("read-only/child"), "Child should be read-only");
}
}