mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-30 05:12:58 +00:00 
			
		
		
		
	Check the filesystem for isReadOnly (#1226)
This commit is contained in:
		| @@ -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; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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()) { | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
| @@ -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 { | ||||||
|   | |||||||
| @@ -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"); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Drew Edwards
					Drew Edwards