├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jimfs ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── google │ │ └── common │ │ └── jimfs │ │ ├── AbstractAttributeView.java │ │ ├── AbstractWatchService.java │ │ ├── AclAttributeProvider.java │ │ ├── AttributeCopyOption.java │ │ ├── AttributeProvider.java │ │ ├── AttributeService.java │ │ ├── BasicAttributeProvider.java │ │ ├── Configuration.java │ │ ├── Directory.java │ │ ├── DirectoryEntry.java │ │ ├── DosAttributeProvider.java │ │ ├── DowngradedDirectoryStream.java │ │ ├── DowngradedSeekableByteChannel.java │ │ ├── Feature.java │ │ ├── File.java │ │ ├── FileFactory.java │ │ ├── FileLookup.java │ │ ├── FileSystemState.java │ │ ├── FileSystemView.java │ │ ├── FileTimeSource.java │ │ ├── FileTree.java │ │ ├── GlobToRegex.java │ │ ├── GuardedBy.java │ │ ├── Handler.java │ │ ├── HeapDisk.java │ │ ├── InternalCharMatcher.java │ │ ├── Java8Compatibility.java │ │ ├── Jimfs.java │ │ ├── JimfsAsynchronousFileChannel.java │ │ ├── JimfsFileChannel.java │ │ ├── JimfsFileStore.java │ │ ├── JimfsFileSystem.java │ │ ├── JimfsFileSystemProvider.java │ │ ├── JimfsFileSystems.java │ │ ├── JimfsInputStream.java │ │ ├── JimfsOutputStream.java │ │ ├── JimfsPath.java │ │ ├── JimfsSecureDirectoryStream.java │ │ ├── Name.java │ │ ├── Options.java │ │ ├── OwnerAttributeProvider.java │ │ ├── PathMatchers.java │ │ ├── PathNormalization.java │ │ ├── PathService.java │ │ ├── PathType.java │ │ ├── PathURLConnection.java │ │ ├── PollingWatchService.java │ │ ├── PosixAttributeProvider.java │ │ ├── RegularFile.java │ │ ├── StandardAttributeProviders.java │ │ ├── SymbolicLink.java │ │ ├── SystemFileTimeSource.java │ │ ├── SystemJimfsFileSystemProvider.java │ │ ├── UnixAttributeProvider.java │ │ ├── UnixFileAttributeView.java │ │ ├── UnixPathType.java │ │ ├── UserDefinedAttributeProvider.java │ │ ├── UserLookupService.java │ │ ├── Util.java │ │ ├── WatchServiceConfiguration.java │ │ ├── WindowsPathType.java │ │ └── package-info.java │ └── test │ └── java │ └── com │ └── google │ └── common │ └── jimfs │ ├── AbstractAttributeProviderTest.java │ ├── AbstractGlobMatcherTest.java │ ├── AbstractJimfsIntegrationTest.java │ ├── AbstractPathMatcherTest.java │ ├── AbstractWatchServiceTest.java │ ├── AclAttributeProviderTest.java │ ├── AttributeServiceTest.java │ ├── BasicAttributeProviderTest.java │ ├── BasicFileAttribute.java │ ├── ByteBufferChannel.java │ ├── ClassLoaderTest.java │ ├── ConfigurationTest.java │ ├── DirectoryTest.java │ ├── DosAttributeProviderTest.java │ ├── FakeFileTimeSource.java │ ├── FileFactoryTest.java │ ├── FileSystemStateTest.java │ ├── FileTest.java │ ├── FileTreeTest.java │ ├── HeapDiskTest.java │ ├── JimfsAsynchronousFileChannelTest.java │ ├── JimfsFileChannelTest.java │ ├── JimfsFileSystemCloseTest.java │ ├── JimfsInputStreamTest.java │ ├── JimfsOutputStreamTest.java │ ├── JimfsPathTest.java │ ├── JimfsUnixLikeFileSystemTest.java │ ├── JimfsWindowsLikeFileSystemTest.java │ ├── NameTest.java │ ├── OwnerAttributeProviderTest.java │ ├── PathNormalizationTest.java │ ├── PathServiceTest.java │ ├── PathSubject.java │ ├── PathTester.java │ ├── PathTypeTest.java │ ├── PollingWatchServiceTest.java │ ├── PosixAttributeProviderTest.java │ ├── RegexGlobMatcherTest.java │ ├── RegularFileBlocksTest.java │ ├── RegularFileTest.java │ ├── TestAttributeProvider.java │ ├── TestAttributeView.java │ ├── TestAttributes.java │ ├── TestUtils.java │ ├── UnixAttributeProviderTest.java │ ├── UnixPathTypeTest.java │ ├── UrlTest.java │ ├── UserDefinedAttributeProviderTest.java │ ├── UserLookupServiceTest.java │ ├── WatchServiceConfigurationTest.java │ └── WindowsPathTypeTest.java ├── pom.xml └── util └── update_snapshot_docs.sh /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | groups: 8 | dependencies: 9 | applies-to: version-updates 10 | patterns: 11 | - "*" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "monthly" 16 | groups: 17 | github-actions: 18 | applies-to: version-updates 19 | patterns: 20 | - "*" 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | test: 13 | name: "JDK ${{ matrix.java }} on ${{ matrix.os }}" 14 | strategy: 15 | matrix: 16 | os: [ ubuntu-latest ] 17 | java: [ 21, 11, 8 ] 18 | # Only test on macos and windows with a single recent JDK to avoid a 19 | # combinatorial explosion of test configurations. 20 | # Most OS-specific issues are not specific to a particular JDK version. 21 | include: 22 | - os: macos-latest 23 | java: 21 24 | - os: windows-latest 25 | java: 21 26 | runs-on: ${{ matrix.os }} 27 | steps: 28 | # Cancel any previous runs for the same branch that are still running. 29 | - name: 'Cancel previous runs' 30 | uses: styfle/cancel-workflow-action@85880fa0301c86cca9da44039ee3bb12d3bedbfa 31 | with: 32 | access_token: ${{ github.token }} 33 | - name: 'Check out repository' 34 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 35 | - name: 'Cache local Maven repository' 36 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 37 | with: 38 | path: ~/.m2/repository 39 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 40 | restore-keys: | 41 | ${{ runner.os }}-maven- 42 | - name: 'Set up JDK ${{ matrix.java }}' 43 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 44 | with: 45 | java-version: ${{ matrix.java }} 46 | distribution: 'zulu' 47 | - name: 'Install' 48 | shell: bash 49 | run: mvn -B install -U -DskipTests=true 50 | - name: 'Test' 51 | shell: bash 52 | run: mvn -B verify -U -Dmaven.javadoc.skip=true 53 | 54 | publish_snapshot: 55 | name: 'Publish snapshot' 56 | needs: test 57 | if: github.event_name == 'push' && github.repository == 'google/jimfs' 58 | runs-on: ubuntu-latest 59 | steps: 60 | - name: 'Check out repository' 61 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 62 | - name: 'Cache local Maven repository' 63 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 64 | with: 65 | path: ~/.m2/repository 66 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 67 | restore-keys: | 68 | ${{ runner.os }}-maven- 69 | - name: 'Set up JDK 8' 70 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 71 | with: 72 | java-version: 8 73 | distribution: 'zulu' 74 | server-id: sonatype-nexus-snapshots 75 | server-username: CI_DEPLOY_USERNAME 76 | server-password: CI_DEPLOY_PASSWORD 77 | - name: 'Publish' 78 | env: 79 | CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }} 80 | CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }} 81 | run: mvn -B clean source:jar javadoc:jar deploy -DskipTests=true 82 | 83 | generate_docs: 84 | name: 'Generate latest docs' 85 | needs: test 86 | if: github.event_name == 'push' && github.repository == 'google/jimfs' 87 | runs-on: ubuntu-latest 88 | steps: 89 | - name: 'Check out repository' 90 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 91 | - name: 'Cache local Maven repository' 92 | uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 93 | with: 94 | path: ~/.m2/repository 95 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 96 | restore-keys: | 97 | ${{ runner.os }}-maven- 98 | - name: 'Set up JDK 11' 99 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 100 | with: 101 | java-version: 11 102 | distribution: 'zulu' 103 | - name: 'Generate latest docs' 104 | env: 105 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 106 | run: ./util/update_snapshot_docs.sh 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.ims 3 | *.iml 4 | 5 | .classpath 6 | .project 7 | .settings/ 8 | 9 | target/ 10 | 11 | bin/ 12 | out/ 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Jimfs 2 | ===================== 3 | 4 | Contributions to Jimfs can be made by forking the repostitory and sending 5 | a pull request. Before we can merge any pull requests from you, you must 6 | first sign the Google [Contributor License Agreement][1]. 7 | 8 | When making changes to the code, please try to stay consistent with the 9 | style of the existing code, specified by the [Google Java Style Guide][2]. 10 | Please also ensure that the code compiles and that changes have appropriate 11 | tests. 12 | 13 | [1]: https://developers.google.com/open-source/cla/individual 14 | [2]: https://google.github.io/styleguide/javaguide.html 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jimfs 2 | ===== 3 | 4 | Jimfs is an in-memory file system for Java 8 and above, implementing the 5 | [java.nio.file](http://docs.oracle.com/javase/7/docs/api/java/nio/file/package-summary.html) 6 | abstract file system APIs. 7 | 8 | [![Build Status](https://github.com/google/jimfs/workflows/CI/badge.svg?branch=master)](https://github.com/google/jimfs/actions) 9 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.google.jimfs/jimfs/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.google.jimfs/jimfs) 10 | 11 | Getting started 12 | --------------- 13 | 14 | The latest release is 15 | [1.3.0](https://github.com/google/jimfs/releases/tag/v1.3.0). 16 | 17 | It is available in Maven Central as 18 | [com.google.jimfs:jimfs:1.3.0](http://search.maven.org/#artifactdetails%7Ccom.google.jimfs%7Cjimfs%7C1.3.0%7Cjar): 19 | 20 | ```xml 21 | 22 | com.google.jimfs 23 | jimfs 24 | 1.3.0 25 | 26 | ``` 27 | 28 | Basic use 29 | --------- 30 | 31 | The simplest way to use Jimfs is to just get a new `FileSystem` instance from the `Jimfs` class and 32 | start using it: 33 | 34 | ```java 35 | import com.google.common.jimfs.Configuration; 36 | import com.google.common.jimfs.Jimfs; 37 | ... 38 | 39 | // For a simple file system with Unix-style paths and behavior: 40 | FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); 41 | Path foo = fs.getPath("/foo"); 42 | Files.createDirectory(foo); 43 | 44 | Path hello = foo.resolve("hello.txt"); // /foo/hello.txt 45 | Files.write(hello, ImmutableList.of("hello world"), StandardCharsets.UTF_8); 46 | ``` 47 | 48 | What's supported? 49 | ----------------- 50 | 51 | Jimfs supports almost all the APIs under `java.nio.file`. It supports: 52 | 53 | - Creating, deleting, moving and copying files and directories. 54 | - Reading and writing files with `FileChannel` or `SeekableByteChannel`, `InputStream`, 55 | `OutputStream`, etc. 56 | - Symbolic links. 57 | - Hard links to regular files. 58 | - `SecureDirectoryStream`, for operations relative to an _open_ directory. 59 | - Glob and regex path filtering with `PathMatcher`. 60 | - Watching for changes to a directory with a `WatchService`. 61 | - File attributes. Built-in attribute views that can be supported include "basic", "owner", 62 | "posix", "unix", "dos", "acl" and "user". Do note, however, that not all attribute views provide 63 | _useful_ attributes. For example, while setting and reading POSIX file permissions is possible 64 | with the "posix" view, those permissions will not actually affect the behavior of the file system. 65 | 66 | Jimfs also supports creating file systems that, for example, use Windows-style paths and (to an 67 | extent) behavior. In general, however, file system behavior is modeled after UNIX and may not 68 | exactly match any particular real file system or platform. 69 | 70 | License 71 | ------- 72 | 73 | ``` 74 | Copyright 2013 Google Inc. 75 | 76 | Licensed under the Apache License, Version 2.0 (the "License"); 77 | you may not use this file except in compliance with the License. 78 | You may obtain a copy of the License at 79 | 80 | http://www.apache.org/licenses/LICENSE-2.0 81 | 82 | Unless required by applicable law or agreed to in writing, software 83 | distributed under the License is distributed on an "AS IS" BASIS, 84 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 | See the License for the specific language governing permissions and 86 | limitations under the License. 87 | ``` 88 | -------------------------------------------------------------------------------- /jimfs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 4.0.0 22 | 23 | com.google.jimfs 24 | jimfs-parent 25 | HEAD-SNAPSHOT 26 | 27 | 28 | jimfs 29 | 30 | bundle 31 | 32 | Jimfs 33 | 34 | 35 | Jimfs is an in-memory implementation of Java 7's java.nio.file abstract file system API. 36 | 37 | 38 | 39 | 40 | 41 | com.google.guava 42 | guava 43 | 44 | 45 | 46 | 47 | com.ibm.icu 48 | icu4j 49 | true 50 | 51 | 52 | 53 | 54 | com.google.auto.service 55 | auto-service-annotations 56 | true 57 | 58 | 59 | com.google.code.findbugs 60 | jsr305 61 | true 62 | 63 | 64 | org.jspecify 65 | jspecify 66 | true 67 | 68 | 69 | 70 | 71 | junit 72 | junit 73 | 74 | 75 | com.google.guava 76 | guava-testlib 77 | 78 | 79 | com.google.truth 80 | truth 81 | 82 | 83 | 84 | 85 | 86 | 87 | maven-javadoc-plugin 88 | 89 | com.google.jimfs.internal 90 | 91 | 92 | 93 | attach-docs 94 | post-integration-test 95 | 96 | jar 97 | 98 | 99 | 100 | 101 | 102 | 103 | org.apache.felix 104 | maven-bundle-plugin 105 | true 106 | 107 | 108 | com.google.common.jimfs.* 109 | 110 | META-INF/services=target/classes/META-INF/services 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/AbstractAttributeView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import java.io.IOException; 22 | import java.nio.file.attribute.FileAttributeView; 23 | 24 | /** 25 | * Abstract base class for {@link FileAttributeView} implementations. 26 | * 27 | * @author Colin Decker 28 | */ 29 | abstract class AbstractAttributeView implements FileAttributeView { 30 | 31 | private final FileLookup lookup; 32 | 33 | protected AbstractAttributeView(FileLookup lookup) { 34 | this.lookup = checkNotNull(lookup); 35 | } 36 | 37 | /** Looks up the file to get or set attributes on. */ 38 | protected final File lookupFile() throws IOException { 39 | return lookup.lookup(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/AclAttributeProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import com.google.common.collect.ImmutableList; 22 | import com.google.common.collect.ImmutableMap; 23 | import com.google.common.collect.ImmutableSet; 24 | import java.io.IOException; 25 | import java.nio.file.attribute.AclEntry; 26 | import java.nio.file.attribute.AclFileAttributeView; 27 | import java.nio.file.attribute.FileAttributeView; 28 | import java.nio.file.attribute.FileOwnerAttributeView; 29 | import java.nio.file.attribute.UserPrincipal; 30 | import java.util.List; 31 | import java.util.Map; 32 | import org.jspecify.annotations.Nullable; 33 | 34 | /** 35 | * Attribute provider that provides the {@link AclFileAttributeView} ("acl"). 36 | * 37 | * @author Colin Decker 38 | */ 39 | final class AclAttributeProvider extends AttributeProvider { 40 | 41 | private static final ImmutableSet ATTRIBUTES = ImmutableSet.of("acl"); 42 | 43 | private static final ImmutableSet INHERITED_VIEWS = ImmutableSet.of("owner"); 44 | 45 | private static final ImmutableList DEFAULT_ACL = ImmutableList.of(); 46 | 47 | @Override 48 | public String name() { 49 | return "acl"; 50 | } 51 | 52 | @Override 53 | public ImmutableSet inherits() { 54 | return INHERITED_VIEWS; 55 | } 56 | 57 | @Override 58 | public ImmutableSet fixedAttributes() { 59 | return ATTRIBUTES; 60 | } 61 | 62 | @Override 63 | public ImmutableMap defaultValues(Map userProvidedDefaults) { 64 | Object userProvidedAcl = userProvidedDefaults.get("acl:acl"); 65 | 66 | ImmutableList acl = DEFAULT_ACL; 67 | if (userProvidedAcl != null) { 68 | acl = toAcl(checkType("acl", "acl", userProvidedAcl, List.class)); 69 | } 70 | 71 | return ImmutableMap.of("acl:acl", acl); 72 | } 73 | 74 | @Override 75 | public @Nullable Object get(File file, String attribute) { 76 | if (attribute.equals("acl")) { 77 | return file.getAttribute("acl", "acl"); 78 | } 79 | 80 | return null; 81 | } 82 | 83 | @Override 84 | public void set(File file, String view, String attribute, Object value, boolean create) { 85 | if (attribute.equals("acl")) { 86 | checkNotCreate(view, attribute, create); 87 | file.setAttribute("acl", "acl", toAcl(checkType(view, attribute, value, List.class))); 88 | } 89 | } 90 | 91 | @SuppressWarnings("unchecked") // only cast after checking each element's type 92 | private static ImmutableList toAcl(List list) { 93 | ImmutableList copy = ImmutableList.copyOf(list); 94 | for (Object obj : copy) { 95 | if (!(obj instanceof AclEntry)) { 96 | throw new IllegalArgumentException( 97 | "invalid element for attribute 'acl:acl': should be List, " 98 | + "found element of type " 99 | + obj.getClass()); 100 | } 101 | } 102 | 103 | return (ImmutableList) copy; 104 | } 105 | 106 | @Override 107 | public Class viewType() { 108 | return AclFileAttributeView.class; 109 | } 110 | 111 | @Override 112 | public AclFileAttributeView view( 113 | FileLookup lookup, ImmutableMap inheritedViews) { 114 | return new View(lookup, (FileOwnerAttributeView) inheritedViews.get("owner")); 115 | } 116 | 117 | /** Implementation of {@link AclFileAttributeView}. */ 118 | private static final class View extends AbstractAttributeView implements AclFileAttributeView { 119 | 120 | private final FileOwnerAttributeView ownerView; 121 | 122 | public View(FileLookup lookup, FileOwnerAttributeView ownerView) { 123 | super(lookup); 124 | this.ownerView = checkNotNull(ownerView); 125 | } 126 | 127 | @Override 128 | public String name() { 129 | return "acl"; 130 | } 131 | 132 | @SuppressWarnings("unchecked") 133 | @Override 134 | public List getAcl() throws IOException { 135 | return (List) lookupFile().getAttribute("acl", "acl"); 136 | } 137 | 138 | @Override 139 | public void setAcl(List acl) throws IOException { 140 | checkNotNull(acl); 141 | lookupFile().setAttribute("acl", "acl", ImmutableList.copyOf(acl)); 142 | } 143 | 144 | @Override 145 | public UserPrincipal getOwner() throws IOException { 146 | return ownerView.getOwner(); 147 | } 148 | 149 | @Override 150 | public void setOwner(UserPrincipal owner) throws IOException { 151 | ownerView.setOwner(owner); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/AttributeCopyOption.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | /** 20 | * Options for how to handle copying of file attributes when copying a file. 21 | * 22 | * @author Colin Decker 23 | */ 24 | enum AttributeCopyOption { 25 | /** Copy all attributes on the file. */ 26 | ALL, 27 | /** Copy only the basic attributes (file times) of the file. */ 28 | BASIC, 29 | /** Do not copy any of the file's attributes. */ 30 | NONE 31 | } 32 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/DirectoryEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.base.Preconditions.checkState; 21 | 22 | import com.google.common.base.MoreObjects; 23 | import com.google.errorprone.annotations.CanIgnoreReturnValue; 24 | import java.nio.file.FileAlreadyExistsException; 25 | import java.nio.file.NoSuchFileException; 26 | import java.nio.file.NotDirectoryException; 27 | import java.nio.file.NotLinkException; 28 | import java.nio.file.Path; 29 | import java.util.Objects; 30 | import org.jspecify.annotations.Nullable; 31 | 32 | /** 33 | * Entry in a directory, containing references to the directory itself, the file the entry links to 34 | * and the name of the entry. 35 | * 36 | *

May also represent a non-existent entry if the name does not link to any file in the 37 | * directory. 38 | */ 39 | final class DirectoryEntry { 40 | 41 | private final Directory directory; 42 | private final Name name; 43 | 44 | private final @Nullable File file; 45 | 46 | @Nullable DirectoryEntry next; // for use in Directory 47 | 48 | DirectoryEntry(Directory directory, Name name, @Nullable File file) { 49 | this.directory = checkNotNull(directory); 50 | this.name = checkNotNull(name); 51 | this.file = file; 52 | } 53 | 54 | /** Returns {@code true} if and only if this entry represents an existing file. */ 55 | public boolean exists() { 56 | return file != null; 57 | } 58 | 59 | /** 60 | * Checks that this entry exists, throwing an exception if not. 61 | * 62 | * @return this 63 | * @throws NoSuchFileException if this entry does not exist 64 | */ 65 | @CanIgnoreReturnValue 66 | public DirectoryEntry requireExists(Path pathForException) throws NoSuchFileException { 67 | if (!exists()) { 68 | throw new NoSuchFileException(pathForException.toString()); 69 | } 70 | return this; 71 | } 72 | 73 | /** 74 | * Checks that this entry does not exist, throwing an exception if it does. 75 | * 76 | * @return this 77 | * @throws FileAlreadyExistsException if this entry does not exist 78 | */ 79 | @CanIgnoreReturnValue 80 | public DirectoryEntry requireDoesNotExist(Path pathForException) 81 | throws FileAlreadyExistsException { 82 | if (exists()) { 83 | throw new FileAlreadyExistsException(pathForException.toString()); 84 | } 85 | return this; 86 | } 87 | 88 | /** 89 | * Checks that this entry exists and links to a directory, throwing an exception if not. 90 | * 91 | * @return this 92 | * @throws NoSuchFileException if this entry does not exist 93 | * @throws NotDirectoryException if this entry does not link to a directory 94 | */ 95 | @CanIgnoreReturnValue 96 | public DirectoryEntry requireDirectory(Path pathForException) 97 | throws NoSuchFileException, NotDirectoryException { 98 | requireExists(pathForException); 99 | if (!file().isDirectory()) { 100 | throw new NotDirectoryException(pathForException.toString()); 101 | } 102 | return this; 103 | } 104 | 105 | /** 106 | * Checks that this entry exists and links to a symbolic link, throwing an exception if not. 107 | * 108 | * @return this 109 | * @throws NoSuchFileException if this entry does not exist 110 | * @throws NotLinkException if this entry does not link to a symbolic link 111 | */ 112 | @CanIgnoreReturnValue 113 | public DirectoryEntry requireSymbolicLink(Path pathForException) 114 | throws NoSuchFileException, NotLinkException { 115 | requireExists(pathForException); 116 | if (!file().isSymbolicLink()) { 117 | throw new NotLinkException(pathForException.toString()); 118 | } 119 | return this; 120 | } 121 | 122 | /** Returns the directory containing this entry. */ 123 | public Directory directory() { 124 | return directory; 125 | } 126 | 127 | /** Returns the name of this entry. */ 128 | public Name name() { 129 | return name; 130 | } 131 | 132 | /** 133 | * Returns the file this entry links to. 134 | * 135 | * @throws IllegalStateException if the file does not exist 136 | */ 137 | public File file() { 138 | checkState(exists()); 139 | return file; 140 | } 141 | 142 | /** Returns the file this entry links to or {@code null} if the file does not exist */ 143 | public @Nullable File fileOrNull() { 144 | return file; 145 | } 146 | 147 | @Override 148 | public boolean equals(Object obj) { 149 | if (obj instanceof DirectoryEntry) { 150 | DirectoryEntry other = (DirectoryEntry) obj; 151 | return directory.equals(other.directory) 152 | && name.equals(other.name) 153 | && Objects.equals(file, other.file); 154 | } 155 | return false; 156 | } 157 | 158 | @Override 159 | public int hashCode() { 160 | return Objects.hash(directory, name, file); 161 | } 162 | 163 | @Override 164 | public String toString() { 165 | return MoreObjects.toStringHelper(this) 166 | .add("directory", directory) 167 | .add("name", name) 168 | .add("file", file) 169 | .toString(); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/DowngradedDirectoryStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import java.io.IOException; 22 | import java.nio.file.DirectoryStream; 23 | import java.nio.file.Path; 24 | import java.nio.file.SecureDirectoryStream; 25 | import java.util.Iterator; 26 | 27 | /** 28 | * A thin wrapper around a {@link SecureDirectoryStream} that exists only to implement {@link 29 | * DirectoryStream} and NOT implement {@link SecureDirectoryStream}. 30 | * 31 | * @author Colin Decker 32 | */ 33 | final class DowngradedDirectoryStream implements DirectoryStream { 34 | 35 | private final SecureDirectoryStream secureDirectoryStream; 36 | 37 | DowngradedDirectoryStream(SecureDirectoryStream secureDirectoryStream) { 38 | this.secureDirectoryStream = checkNotNull(secureDirectoryStream); 39 | } 40 | 41 | @Override 42 | public Iterator iterator() { 43 | return secureDirectoryStream.iterator(); 44 | } 45 | 46 | @Override 47 | public void close() throws IOException { 48 | secureDirectoryStream.close(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/DowngradedSeekableByteChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import com.google.errorprone.annotations.CanIgnoreReturnValue; 22 | import java.io.IOException; 23 | import java.nio.ByteBuffer; 24 | import java.nio.channels.FileChannel; 25 | import java.nio.channels.SeekableByteChannel; 26 | 27 | /** 28 | * A thin wrapper around a {@link FileChannel} that exists only to implement {@link 29 | * SeekableByteChannel} but NOT extend {@link FileChannel}. 30 | * 31 | * @author Colin Decker 32 | */ 33 | final class DowngradedSeekableByteChannel implements SeekableByteChannel { 34 | 35 | private final FileChannel channel; 36 | 37 | DowngradedSeekableByteChannel(FileChannel channel) { 38 | this.channel = checkNotNull(channel); 39 | } 40 | 41 | @Override 42 | public int read(ByteBuffer dst) throws IOException { 43 | return channel.read(dst); 44 | } 45 | 46 | @Override 47 | public int write(ByteBuffer src) throws IOException { 48 | return channel.write(src); 49 | } 50 | 51 | @Override 52 | public long position() throws IOException { 53 | return channel.position(); 54 | } 55 | 56 | @Override 57 | @CanIgnoreReturnValue 58 | public SeekableByteChannel position(long newPosition) throws IOException { 59 | channel.position(newPosition); 60 | return this; 61 | } 62 | 63 | @Override 64 | public long size() throws IOException { 65 | return channel.size(); 66 | } 67 | 68 | @Override 69 | @CanIgnoreReturnValue 70 | public SeekableByteChannel truncate(long size) throws IOException { 71 | channel.truncate(size); 72 | return this; 73 | } 74 | 75 | @Override 76 | public boolean isOpen() { 77 | return channel.isOpen(); 78 | } 79 | 80 | @Override 81 | public void close() throws IOException { 82 | channel.close(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Feature.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.nio.channels.AsynchronousFileChannel; 20 | import java.nio.channels.FileChannel; 21 | import java.nio.channels.SeekableByteChannel; 22 | import java.nio.file.DirectoryStream; 23 | import java.nio.file.Files; 24 | import java.nio.file.OpenOption; 25 | import java.nio.file.Path; 26 | import java.nio.file.SecureDirectoryStream; 27 | import java.nio.file.attribute.FileAttribute; 28 | import java.util.Set; 29 | import java.util.concurrent.ExecutorService; 30 | 31 | /** 32 | * Optional file system features that may be supported or unsupported by a Jimfs file system 33 | * instance. 34 | * 35 | * @author Colin Decker 36 | */ 37 | public enum Feature { 38 | 39 | /** 40 | * Feature controlling support for hard links to regular files. 41 | * 42 | *

Affected method: 43 | * 44 | *

    45 | *
  • {@link Files#createLink(Path, Path)} 46 | *
47 | * 48 | *

If this feature is not enabled, this method will throw {@link 49 | * UnsupportedOperationException}. 50 | */ 51 | LINKS, 52 | 53 | /** 54 | * Feature controlling support for symbolic links. 55 | * 56 | *

Affected methods: 57 | * 58 | *

    59 | *
  • {@link Files#createSymbolicLink(Path, Path, FileAttribute...)} 60 | *
  • {@link Files#readSymbolicLink(Path)} 61 | *
62 | * 63 | *

If this feature is not enabled, these methods will throw {@link 64 | * UnsupportedOperationException}. 65 | */ 66 | SYMBOLIC_LINKS, 67 | 68 | /** 69 | * Feature controlling support for {@link SecureDirectoryStream}. 70 | * 71 | *

Affected methods: 72 | * 73 | *

    74 | *
  • {@link Files#newDirectoryStream(Path)} 75 | *
  • {@link Files#newDirectoryStream(Path, DirectoryStream.Filter)} 76 | *
  • {@link Files#newDirectoryStream(Path, String)} 77 | *
78 | * 79 | *

If this feature is enabled, the {@link DirectoryStream} instances returned by these methods 80 | * will also implement {@link SecureDirectoryStream}. 81 | */ 82 | SECURE_DIRECTORY_STREAM, 83 | 84 | /** 85 | * Feature controlling support for {@link FileChannel}. 86 | * 87 | *

Affected methods: 88 | * 89 | *

    90 | *
  • {@link Files#newByteChannel(Path, OpenOption...)} 91 | *
  • {@link Files#newByteChannel(Path, Set, FileAttribute...)} 92 | *
  • {@link FileChannel#open(Path, OpenOption...)} 93 | *
  • {@link FileChannel#open(Path, Set, FileAttribute...)} 94 | *
  • {@link AsynchronousFileChannel#open(Path, OpenOption...)} 95 | *
  • {@link AsynchronousFileChannel#open(Path, Set, ExecutorService, FileAttribute...)} 96 | *
97 | * 98 | *

If this feature is not enabled, the {@link SeekableByteChannel} instances returned by the 99 | * {@code Files} methods will not be {@code FileChannel} instances and the {@code 100 | * FileChannel.open} and {@code AsynchronousFileChannel.open} methods will throw {@link 101 | * UnsupportedOperationException}. 102 | */ 103 | // TODO(cgdecker): Should support for AsynchronousFileChannel be a separate feature? 104 | FILE_CHANNEL 105 | } 106 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/FileFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import com.google.common.annotations.VisibleForTesting; 22 | import com.google.common.base.Supplier; 23 | import java.io.IOException; 24 | import java.util.concurrent.atomic.AtomicInteger; 25 | 26 | /** 27 | * Factory for creating new files and copying files. One piece of the file store implementation. 28 | * 29 | * @author Colin Decker 30 | */ 31 | final class FileFactory { 32 | 33 | private final AtomicInteger idGenerator = new AtomicInteger(); 34 | 35 | private final HeapDisk disk; 36 | private final FileTimeSource fileTimeSource; 37 | 38 | /** 39 | * Creates a new file factory using the given disk for regular files and the given time source. 40 | */ 41 | public FileFactory(HeapDisk disk, FileTimeSource fileTimeSource) { 42 | this.disk = checkNotNull(disk); 43 | this.fileTimeSource = checkNotNull(fileTimeSource); 44 | } 45 | 46 | private int nextFileId() { 47 | return idGenerator.getAndIncrement(); 48 | } 49 | 50 | /** Creates a new directory. */ 51 | public Directory createDirectory() { 52 | return Directory.create(nextFileId(), fileTimeSource.now()); 53 | } 54 | 55 | /** Creates a new root directory with the given name. */ 56 | public Directory createRootDirectory(Name name) { 57 | return Directory.createRoot(nextFileId(), fileTimeSource.now(), name); 58 | } 59 | 60 | /** Creates a new regular file. */ 61 | @VisibleForTesting 62 | RegularFile createRegularFile() { 63 | return RegularFile.create(nextFileId(), fileTimeSource.now(), disk); 64 | } 65 | 66 | /** Creates a new symbolic link referencing the given target path. */ 67 | @VisibleForTesting 68 | SymbolicLink createSymbolicLink(JimfsPath target) { 69 | return SymbolicLink.create(nextFileId(), fileTimeSource.now(), target); 70 | } 71 | 72 | /** Creates and returns a copy of the given file. */ 73 | public File copyWithoutContent(File file) throws IOException { 74 | return file.copyWithoutContent(nextFileId(), fileTimeSource.now()); 75 | } 76 | 77 | // suppliers to act as file creation callbacks 78 | 79 | private final Supplier directorySupplier = new DirectorySupplier(); 80 | 81 | private final Supplier regularFileSupplier = new RegularFileSupplier(); 82 | 83 | /** Returns a supplier that creates directories. */ 84 | public Supplier directoryCreator() { 85 | return directorySupplier; 86 | } 87 | 88 | /** Returns a supplier that creates regular files. */ 89 | public Supplier regularFileCreator() { 90 | return regularFileSupplier; 91 | } 92 | 93 | /** Returns a supplier that creates a symbolic links to the given path. */ 94 | public Supplier symbolicLinkCreator(JimfsPath target) { 95 | return new SymbolicLinkSupplier(target); 96 | } 97 | 98 | private final class DirectorySupplier implements Supplier { 99 | @Override 100 | public Directory get() { 101 | return createDirectory(); 102 | } 103 | } 104 | 105 | private final class RegularFileSupplier implements Supplier { 106 | @Override 107 | public RegularFile get() { 108 | return createRegularFile(); 109 | } 110 | } 111 | 112 | private final class SymbolicLinkSupplier implements Supplier { 113 | 114 | private final JimfsPath target; 115 | 116 | protected SymbolicLinkSupplier(JimfsPath target) { 117 | this.target = checkNotNull(target); 118 | } 119 | 120 | @Override 121 | public SymbolicLink get() { 122 | return createSymbolicLink(target); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/FileLookup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.io.IOException; 20 | 21 | /** 22 | * Callback for looking up a file. 23 | * 24 | * @author Colin Decker 25 | */ 26 | public interface FileLookup { 27 | 28 | /** 29 | * Looks up the file. 30 | * 31 | * @throws IOException if the lookup fails for any reason, such as the file not existing 32 | */ 33 | File lookup() throws IOException; 34 | } 35 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/FileSystemState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.base.Throwables.throwIfInstanceOf; 21 | import static com.google.common.base.Throwables.throwIfUnchecked; 22 | 23 | import com.google.common.collect.Sets; 24 | import com.google.errorprone.annotations.CanIgnoreReturnValue; 25 | import java.io.Closeable; 26 | import java.io.IOException; 27 | import java.nio.file.ClosedFileSystemException; 28 | import java.nio.file.attribute.FileTime; 29 | import java.util.Set; 30 | import java.util.concurrent.atomic.AtomicBoolean; 31 | import java.util.concurrent.atomic.AtomicInteger; 32 | 33 | /** 34 | * Object that manages the open/closed state of a file system, ensuring that all open resources are 35 | * closed when the file system is closed and that file system methods throw an exception when the 36 | * file system has been closed. 37 | * 38 | * @author Colin Decker 39 | */ 40 | final class FileSystemState implements Closeable { 41 | 42 | private final Set resources = Sets.newConcurrentHashSet(); 43 | private final FileTimeSource fileTimeSource; 44 | private final Runnable onClose; 45 | 46 | private final AtomicBoolean open = new AtomicBoolean(true); 47 | 48 | /** Count of resources currently in the process of being registered. */ 49 | private final AtomicInteger registering = new AtomicInteger(); 50 | 51 | FileSystemState(FileTimeSource fileTimeSource, Runnable onClose) { 52 | this.fileTimeSource = checkNotNull(fileTimeSource); 53 | this.onClose = checkNotNull(onClose); 54 | } 55 | 56 | /** Returns whether or not the file system is open. */ 57 | public boolean isOpen() { 58 | return open.get(); 59 | } 60 | 61 | /** 62 | * Checks that the file system is open, throwing {@link ClosedFileSystemException} if it is not. 63 | */ 64 | public void checkOpen() { 65 | if (!open.get()) { 66 | throw new ClosedFileSystemException(); 67 | } 68 | } 69 | 70 | /** 71 | * Registers the given resource to be closed when the file system is closed. Should be called when 72 | * the resource is opened. 73 | */ 74 | @CanIgnoreReturnValue 75 | public C register(C resource) { 76 | // Initial open check to avoid incrementing registering if we already know it's closed. 77 | // This is to prevent any possibility of a weird pathalogical situation where the do/while 78 | // loop in close() keeps looping as register() is called repeatedly from multiple threads. 79 | checkOpen(); 80 | 81 | registering.incrementAndGet(); 82 | try { 83 | // Need to check again after marking registration in progress to avoid a potential race. 84 | // (close() could have run completely between the first checkOpen() and 85 | // registering.incrementAndGet().) 86 | checkOpen(); 87 | resources.add(resource); 88 | return resource; 89 | } finally { 90 | registering.decrementAndGet(); 91 | } 92 | } 93 | 94 | /** Unregisters the given resource. Should be called when the resource is closed. */ 95 | public void unregister(Closeable resource) { 96 | resources.remove(resource); 97 | } 98 | 99 | /** Returns the current {@link FileTime}. */ 100 | public FileTime now() { 101 | return fileTimeSource.now(); 102 | } 103 | 104 | /** 105 | * Closes the file system, runs the {@code onClose} callback and closes all registered resources. 106 | */ 107 | @Override 108 | public void close() throws IOException { 109 | if (open.compareAndSet(true, false)) { 110 | onClose.run(); 111 | 112 | Throwable thrown = null; 113 | do { 114 | for (Closeable resource : resources) { 115 | try { 116 | resource.close(); 117 | } catch (Throwable e) { 118 | if (thrown == null) { 119 | thrown = e; 120 | } else { 121 | thrown.addSuppressed(e); 122 | } 123 | } finally { 124 | // ensure the resource is removed even if it doesn't remove itself when closed 125 | resources.remove(resource); 126 | } 127 | } 128 | 129 | // It's possible for a thread registering a resource to register that resource after open 130 | // has been set to false and even after we've looped through and closed all the resources. 131 | // Since registering must be incremented *before* checking the state of open, however, 132 | // when we reach this point in that situation either the register call is still in progress 133 | // (registering > 0) or the new resource has been successfully added (resources not empty). 134 | // In either case, we just need to repeat the loop until there are no more register calls 135 | // in progress (no new calls can start and no resources left to close. 136 | } while (registering.get() > 0 || !resources.isEmpty()); 137 | if (thrown != null) { 138 | throwIfInstanceOf(thrown, IOException.class); 139 | throwIfUnchecked(thrown); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/FileTimeSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.nio.file.attribute.FileTime; 20 | 21 | /** 22 | * A source of the current time as a {@link FileTime}, to enable fake time sources for testing. 23 | * 24 | * @since 1.3 25 | */ 26 | public interface FileTimeSource { 27 | /** Returns the current time according to this source as a {@link FileTime}. */ 28 | FileTime now(); 29 | } 30 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/GuardedBy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The Error Prone Authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.common.jimfs; 17 | 18 | import static java.lang.annotation.ElementType.FIELD; 19 | import static java.lang.annotation.ElementType.METHOD; 20 | import static java.lang.annotation.RetentionPolicy.CLASS; 21 | 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.Target; 24 | 25 | // TODO(cpovirk): Delete this in favor of the copy in Error Prone once that has a module name. 26 | /** Indicates that the annotated element should be used only while holding the specified lock. */ 27 | @Target({FIELD, METHOD}) 28 | @Retention(CLASS) 29 | @interface GuardedBy { 30 | /** 31 | * The lock that should be held, specified in the format given in Java 33 | * Concurrency in Practice. 34 | */ 35 | String value(); 36 | } 37 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Handler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | 21 | import java.io.IOException; 22 | import java.net.InetAddress; 23 | import java.net.URL; 24 | import java.net.URLConnection; 25 | import java.net.URLStreamHandler; 26 | import org.jspecify.annotations.Nullable; 27 | 28 | /** 29 | * {@link URLStreamHandler} implementation for jimfs. Named {@code Handler} so that the class can be 30 | * found by Java as described in the documentation for {@link URL#URL(String, String, int, String) 31 | * URL}. 32 | * 33 | *

This class is only public because it is necessary for Java to find it. It is not intended to 34 | * be used directly. 35 | * 36 | * @author Colin Decker 37 | * @since 1.1 38 | */ 39 | public final class Handler extends URLStreamHandler { 40 | 41 | private static final String JAVA_PROTOCOL_HANDLER_PACKAGES = "java.protocol.handler.pkgs"; 42 | 43 | /** 44 | * Registers this handler by adding the package {@code com.google.common} to the system property 45 | * {@code "java.protocol.handler.pkgs"}. Java will then look for this class in the {@code jimfs} 46 | * (the name of the protocol) package of {@code com.google.common}. 47 | * 48 | * @throws SecurityException if the system property that needs to be set to register this handler 49 | * can't be read or written. 50 | */ 51 | static void register() { 52 | register(Handler.class); 53 | } 54 | 55 | /** Generic method that would allow registration of any properly placed {@code Handler} class. */ 56 | static void register(Class handlerClass) { 57 | checkArgument("Handler".equals(handlerClass.getSimpleName())); 58 | 59 | String pkg = handlerClass.getPackage().getName(); 60 | int lastDot = pkg.lastIndexOf('.'); 61 | checkArgument(lastDot > 0, "package for Handler (%s) must have a parent package", pkg); 62 | 63 | String parentPackage = pkg.substring(0, lastDot); 64 | 65 | String packages = System.getProperty(JAVA_PROTOCOL_HANDLER_PACKAGES); 66 | if (packages == null) { 67 | packages = parentPackage; 68 | } else { 69 | packages += "|" + parentPackage; 70 | } 71 | System.setProperty(JAVA_PROTOCOL_HANDLER_PACKAGES, packages); 72 | } 73 | 74 | /** @deprecated Not intended to be called directly; this class is only for use by Java itself. */ 75 | @Deprecated 76 | public Handler() {} // a public, no-arg constructor is required 77 | 78 | @Override 79 | protected URLConnection openConnection(URL url) throws IOException { 80 | return new PathURLConnection(url); 81 | } 82 | 83 | @Override 84 | @SuppressWarnings("UnsynchronizedOverridesSynchronized") // no need to synchronize to return null 85 | protected @Nullable InetAddress getHostAddress(URL url) { 86 | // jimfs uses the URI host to specify the name of the file system being used. 87 | // In the default implementation of getHostAddress(URL), a non-null host would cause an attempt 88 | // to look up the IP address, causing a slowdown on calling equals/hashCode methods on the URL 89 | // object. By returning null, we speed up equality checks on URL's (since there isn't an IP to 90 | // connect to). 91 | return null; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/InternalCharMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.util.Arrays; 20 | 21 | /** 22 | * Simple replacement for the real CharMatcher until it's out of @Beta. 23 | * 24 | * @author Colin Decker 25 | */ 26 | final class InternalCharMatcher { 27 | 28 | public static InternalCharMatcher anyOf(String chars) { 29 | return new InternalCharMatcher(chars); 30 | } 31 | 32 | private final char[] chars; 33 | 34 | private InternalCharMatcher(String chars) { 35 | this.chars = chars.toCharArray(); 36 | Arrays.sort(this.chars); 37 | } 38 | 39 | public boolean matches(char c) { 40 | return Arrays.binarySearch(chars, c) >= 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Java8Compatibility.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.google.common.jimfs; 16 | 17 | import java.nio.Buffer; 18 | 19 | /** 20 | * Wrappers around {@link Buffer} methods that are covariantly overridden in Java 9+. See 21 | * https://github.com/google/guava/issues/3990 22 | */ 23 | final class Java8Compatibility { 24 | static void clear(Buffer b) { 25 | b.clear(); 26 | } 27 | 28 | private Java8Compatibility() {} 29 | } 30 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/JimfsFileSystems.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.io.IOException; 20 | import java.lang.reflect.InvocationTargetException; 21 | import java.lang.reflect.Method; 22 | import java.net.URI; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | 26 | /** 27 | * Initializes and configures new file system instances. 28 | * 29 | * @author Colin Decker 30 | */ 31 | final class JimfsFileSystems { 32 | 33 | private JimfsFileSystems() {} 34 | 35 | private static final Runnable DO_NOTHING = 36 | new Runnable() { 37 | @Override 38 | public void run() {} 39 | }; 40 | 41 | /** 42 | * Returns a {@code Runnable} that will remove the file system with the given {@code URI} from the 43 | * system provider's cache when called. 44 | */ 45 | private static Runnable removeFileSystemRunnable(URI uri) { 46 | if (Jimfs.systemProvider == null) { 47 | // TODO(cgdecker): Use Runnables.doNothing() when it's out of @Beta 48 | return DO_NOTHING; 49 | } 50 | 51 | // We have to invoke the SystemJimfsFileSystemProvider.removeFileSystemRunnable(URI) 52 | // method reflectively since the system-loaded instance of it may be a different class 53 | // than the one we'd get if we tried to cast it and call it like normal here. 54 | try { 55 | Method method = 56 | Jimfs.systemProvider.getClass().getDeclaredMethod("removeFileSystemRunnable", URI.class); 57 | return (Runnable) method.invoke(null, uri); 58 | } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { 59 | throw new RuntimeException( 60 | "Unable to get Runnable for removing the FileSystem from the cache when it is closed", e); 61 | } 62 | } 63 | 64 | /** 65 | * Initialize and configure a new file system with the given provider and URI, using the given 66 | * configuration. 67 | */ 68 | public static JimfsFileSystem newFileSystem( 69 | JimfsFileSystemProvider provider, URI uri, Configuration config) throws IOException { 70 | PathService pathService = new PathService(config); 71 | FileSystemState state = 72 | new FileSystemState(config.fileTimeSource, removeFileSystemRunnable(uri)); 73 | 74 | JimfsFileStore fileStore = createFileStore(config, pathService, state); 75 | FileSystemView defaultView = createDefaultView(config, fileStore, pathService); 76 | WatchServiceConfiguration watchServiceConfig = config.watchServiceConfig; 77 | 78 | JimfsFileSystem fileSystem = 79 | new JimfsFileSystem(provider, uri, fileStore, pathService, defaultView, watchServiceConfig); 80 | 81 | pathService.setFileSystem(fileSystem); 82 | return fileSystem; 83 | } 84 | 85 | /** Creates the file store for the file system. */ 86 | private static JimfsFileStore createFileStore( 87 | Configuration config, PathService pathService, FileSystemState state) { 88 | AttributeService attributeService = new AttributeService(config); 89 | 90 | HeapDisk disk = new HeapDisk(config); 91 | FileFactory fileFactory = new FileFactory(disk, config.fileTimeSource); 92 | 93 | Map roots = new HashMap<>(); 94 | 95 | // create roots 96 | for (String root : config.roots) { 97 | JimfsPath path = pathService.parsePath(root); 98 | if (!path.isAbsolute() && path.getNameCount() == 0) { 99 | throw new IllegalArgumentException("Invalid root path: " + root); 100 | } 101 | 102 | Name rootName = path.root(); 103 | 104 | Directory rootDir = fileFactory.createRootDirectory(rootName); 105 | attributeService.setInitialAttributes(rootDir); 106 | roots.put(rootName, rootDir); 107 | } 108 | 109 | return new JimfsFileStore( 110 | new FileTree(roots), fileFactory, disk, attributeService, config.supportedFeatures, state); 111 | } 112 | 113 | /** Creates the default view of the file system using the given working directory. */ 114 | private static FileSystemView createDefaultView( 115 | Configuration config, JimfsFileStore fileStore, PathService pathService) throws IOException { 116 | JimfsPath workingDirPath = pathService.parsePath(config.workingDirectory); 117 | 118 | Directory dir = fileStore.getRoot(workingDirPath.root()); 119 | if (dir == null) { 120 | throw new IllegalArgumentException("Invalid working dir path: " + workingDirPath); 121 | } 122 | 123 | for (Name name : workingDirPath.names()) { 124 | Directory newDir = fileStore.directoryCreator().get(); 125 | fileStore.setInitialAttributes(newDir); 126 | dir.link(name, newDir); 127 | 128 | dir = newDir; 129 | } 130 | 131 | return new FileSystemView(fileStore, dir, workingDirPath); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/JimfsInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.base.Preconditions.checkPositionIndexes; 21 | 22 | import com.google.common.annotations.VisibleForTesting; 23 | import com.google.common.primitives.Ints; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | 27 | /** 28 | * {@link InputStream} for reading from a file's {@link RegularFile}. 29 | * 30 | * @author Colin Decker 31 | */ 32 | final class JimfsInputStream extends InputStream { 33 | 34 | @GuardedBy("this") 35 | @VisibleForTesting 36 | RegularFile file; 37 | 38 | @GuardedBy("this") 39 | private long pos; 40 | 41 | @GuardedBy("this") 42 | private boolean finished; 43 | 44 | private final FileSystemState fileSystemState; 45 | 46 | public JimfsInputStream(RegularFile file, FileSystemState fileSystemState) { 47 | this.file = checkNotNull(file); 48 | this.fileSystemState = fileSystemState; 49 | fileSystemState.register(this); 50 | } 51 | 52 | @Override 53 | public synchronized int read() throws IOException { 54 | checkNotClosed(); 55 | if (finished) { 56 | return -1; 57 | } 58 | 59 | file.readLock().lock(); 60 | try { 61 | 62 | int b = file.read(pos++); // it's ok for pos to go beyond size() 63 | if (b == -1) { 64 | finished = true; 65 | } else { 66 | file.setLastAccessTime(fileSystemState.now()); 67 | } 68 | return b; 69 | } finally { 70 | file.readLock().unlock(); 71 | } 72 | } 73 | 74 | @Override 75 | public int read(byte[] b) throws IOException { 76 | return readInternal(b, 0, b.length); 77 | } 78 | 79 | @Override 80 | public int read(byte[] b, int off, int len) throws IOException { 81 | checkPositionIndexes(off, off + len, b.length); 82 | return readInternal(b, off, len); 83 | } 84 | 85 | private synchronized int readInternal(byte[] b, int off, int len) throws IOException { 86 | checkNotClosed(); 87 | if (finished) { 88 | return -1; 89 | } 90 | 91 | file.readLock().lock(); 92 | try { 93 | int read = file.read(pos, b, off, len); 94 | if (read == -1) { 95 | finished = true; 96 | } else { 97 | pos += read; 98 | } 99 | 100 | file.setLastAccessTime(fileSystemState.now()); 101 | return read; 102 | } finally { 103 | file.readLock().unlock(); 104 | } 105 | } 106 | 107 | @Override 108 | public long skip(long n) throws IOException { 109 | if (n <= 0) { 110 | return 0; 111 | } 112 | 113 | synchronized (this) { 114 | checkNotClosed(); 115 | if (finished) { 116 | return 0; 117 | } 118 | 119 | // available() must be an int, so the min must be also 120 | int skip = (int) Math.min(Math.max(file.size() - pos, 0), n); 121 | pos += skip; 122 | return skip; 123 | } 124 | } 125 | 126 | @Override 127 | public synchronized int available() throws IOException { 128 | checkNotClosed(); 129 | if (finished) { 130 | return 0; 131 | } 132 | long available = Math.max(file.size() - pos, 0); 133 | return Ints.saturatedCast(available); 134 | } 135 | 136 | @GuardedBy("this") 137 | private void checkNotClosed() throws IOException { 138 | if (file == null) { 139 | throw new IOException("stream is closed"); 140 | } 141 | } 142 | 143 | @Override 144 | public synchronized void close() throws IOException { 145 | if (isOpen()) { 146 | fileSystemState.unregister(this); 147 | file.closed(); 148 | 149 | // file is set to null here and only here 150 | file = null; 151 | } 152 | } 153 | 154 | @GuardedBy("this") 155 | private boolean isOpen() { 156 | return file != null; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/JimfsOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.base.Preconditions.checkPositionIndexes; 21 | 22 | import com.google.common.annotations.VisibleForTesting; 23 | import java.io.IOException; 24 | import java.io.OutputStream; 25 | 26 | /** 27 | * {@link OutputStream} for writing to a {@link RegularFile}. 28 | * 29 | * @author Colin Decker 30 | */ 31 | final class JimfsOutputStream extends OutputStream { 32 | 33 | @GuardedBy("this") 34 | @VisibleForTesting 35 | RegularFile file; 36 | 37 | @GuardedBy("this") 38 | private long pos; 39 | 40 | private final boolean append; 41 | private final FileSystemState fileSystemState; 42 | 43 | JimfsOutputStream(RegularFile file, boolean append, FileSystemState fileSystemState) { 44 | this.file = checkNotNull(file); 45 | this.append = append; 46 | this.fileSystemState = fileSystemState; 47 | fileSystemState.register(this); 48 | } 49 | 50 | @Override 51 | public synchronized void write(int b) throws IOException { 52 | checkNotClosed(); 53 | 54 | file.writeLock().lock(); 55 | try { 56 | if (append) { 57 | pos = file.sizeWithoutLocking(); 58 | } 59 | file.write(pos++, (byte) b); 60 | 61 | file.setLastModifiedTime(fileSystemState.now()); 62 | } finally { 63 | file.writeLock().unlock(); 64 | } 65 | } 66 | 67 | @Override 68 | public void write(byte[] b) throws IOException { 69 | writeInternal(b, 0, b.length); 70 | } 71 | 72 | @Override 73 | public void write(byte[] b, int off, int len) throws IOException { 74 | checkPositionIndexes(off, off + len, b.length); 75 | writeInternal(b, off, len); 76 | } 77 | 78 | private synchronized void writeInternal(byte[] b, int off, int len) throws IOException { 79 | checkNotClosed(); 80 | 81 | file.writeLock().lock(); 82 | try { 83 | if (append) { 84 | pos = file.sizeWithoutLocking(); 85 | } 86 | pos += file.write(pos, b, off, len); 87 | 88 | file.setLastModifiedTime(fileSystemState.now()); 89 | } finally { 90 | file.writeLock().unlock(); 91 | } 92 | } 93 | 94 | @GuardedBy("this") 95 | private void checkNotClosed() throws IOException { 96 | if (file == null) { 97 | throw new IOException("stream is closed"); 98 | } 99 | } 100 | 101 | @Override 102 | public synchronized void close() throws IOException { 103 | if (isOpen()) { 104 | fileSystemState.unregister(this); 105 | file.closed(); 106 | 107 | // file is set to null here and only here 108 | file = null; 109 | } 110 | } 111 | 112 | @GuardedBy("this") 113 | private boolean isOpen() { 114 | return file != null; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Name.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import com.google.common.annotations.VisibleForTesting; 22 | import java.util.Comparator; 23 | import org.jspecify.annotations.Nullable; 24 | 25 | /** 26 | * Immutable representation of a file name. Used both for the name components of paths and as the 27 | * keys for directory entries. 28 | * 29 | *

A name has both a display string (used in the {@code toString()} form of a {@code Path} as 30 | * well as for {@code Path} equality and sort ordering) and a canonical string, which is used for 31 | * determining equality of the name during file lookup. 32 | * 33 | *

Note: all factory methods return a constant name instance when given the original string "." 34 | * or "..", ensuring that those names can be accessed statically elsewhere in the code while still 35 | * being equal to any names created for those values, regardless of normalization settings. 36 | * 37 | * @author Colin Decker 38 | */ 39 | final class Name { 40 | 41 | /** The empty name. */ 42 | static final Name EMPTY = new Name("", ""); 43 | 44 | /** The name to use for a link from a directory to itself. */ 45 | public static final Name SELF = new Name(".", "."); 46 | 47 | /** The name to use for a link from a directory to its parent directory. */ 48 | public static final Name PARENT = new Name("..", ".."); 49 | 50 | /** Creates a new name with no normalization done on the given string. */ 51 | @VisibleForTesting 52 | static Name simple(String name) { 53 | switch (name) { 54 | case ".": 55 | return SELF; 56 | case "..": 57 | return PARENT; 58 | default: 59 | return new Name(name, name); 60 | } 61 | } 62 | 63 | /** 64 | * Creates a name with the given display representation and the given canonical representation. 65 | */ 66 | public static Name create(String display, String canonical) { 67 | return new Name(display, canonical); 68 | } 69 | 70 | private final String display; 71 | private final String canonical; 72 | 73 | private Name(String display, String canonical) { 74 | this.display = checkNotNull(display); 75 | this.canonical = checkNotNull(canonical); 76 | } 77 | 78 | @Override 79 | public boolean equals(@Nullable Object obj) { 80 | if (obj instanceof Name) { 81 | Name other = (Name) obj; 82 | return canonical.equals(other.canonical); 83 | } 84 | return false; 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | return Util.smearHash(canonical.hashCode()); 90 | } 91 | 92 | @Override 93 | public String toString() { 94 | return display; 95 | } 96 | 97 | /** Returns a comparator that orders names by their display representation. */ 98 | static Comparator displayComparator() { 99 | return DISPLAY_COMPARATOR; 100 | } 101 | 102 | /** Returns a comparator that orders names by their canonical representation. */ 103 | static Comparator canonicalComparator() { 104 | return CANONICAL_COMPARATOR; 105 | } 106 | 107 | private static final Comparator DISPLAY_COMPARATOR = 108 | Comparator.comparing((Name n) -> n.display); 109 | 110 | private static final Comparator CANONICAL_COMPARATOR = 111 | Comparator.comparing((Name n) -> n.canonical); 112 | } 113 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Options.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; 21 | import static java.nio.file.StandardOpenOption.APPEND; 22 | import static java.nio.file.StandardOpenOption.CREATE; 23 | import static java.nio.file.StandardOpenOption.READ; 24 | import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; 25 | import static java.nio.file.StandardOpenOption.WRITE; 26 | 27 | import com.google.common.collect.ImmutableSet; 28 | import com.google.common.collect.Lists; 29 | import java.nio.file.CopyOption; 30 | import java.nio.file.LinkOption; 31 | import java.nio.file.OpenOption; 32 | import java.util.Arrays; 33 | import java.util.Collection; 34 | import java.util.Set; 35 | 36 | /** 37 | * Utility methods for normalizing user-provided options arrays and sets to canonical immutable sets 38 | * of options. 39 | * 40 | * @author Colin Decker 41 | */ 42 | final class Options { 43 | 44 | private Options() {} 45 | 46 | /** Immutable set containing LinkOption.NOFOLLOW_LINKS. */ 47 | public static final ImmutableSet NOFOLLOW_LINKS = 48 | ImmutableSet.of(LinkOption.NOFOLLOW_LINKS); 49 | 50 | /** Immutable empty LinkOption set. */ 51 | public static final ImmutableSet FOLLOW_LINKS = ImmutableSet.of(); 52 | 53 | private static final ImmutableSet DEFAULT_READ = ImmutableSet.of(READ); 54 | 55 | private static final ImmutableSet DEFAULT_READ_NOFOLLOW_LINKS = 56 | ImmutableSet.of(READ, LinkOption.NOFOLLOW_LINKS); 57 | 58 | private static final ImmutableSet DEFAULT_WRITE = 59 | ImmutableSet.of(WRITE, CREATE, TRUNCATE_EXISTING); 60 | 61 | /** Returns an immutable set of link options. */ 62 | public static ImmutableSet getLinkOptions(LinkOption... options) { 63 | return options.length == 0 ? FOLLOW_LINKS : NOFOLLOW_LINKS; 64 | } 65 | 66 | /** Returns an immutable set of open options for opening a new file channel. */ 67 | public static ImmutableSet getOptionsForChannel(Set options) { 68 | if (options.isEmpty()) { 69 | return DEFAULT_READ; 70 | } 71 | 72 | boolean append = options.contains(APPEND); 73 | boolean write = append || options.contains(WRITE); 74 | boolean read = !write || options.contains(READ); 75 | 76 | if (read) { 77 | if (append) { 78 | throw new UnsupportedOperationException("'READ' + 'APPEND' not allowed"); 79 | } 80 | 81 | if (!write) { 82 | // ignore all write related options 83 | return options.contains(LinkOption.NOFOLLOW_LINKS) 84 | ? DEFAULT_READ_NOFOLLOW_LINKS 85 | : DEFAULT_READ; 86 | } 87 | } 88 | 89 | // options contains write or append and may also contain read 90 | // it does not contain both read and append 91 | return addWrite(options); 92 | } 93 | 94 | /** Returns an immutable set of open options for opening a new input stream. */ 95 | @SuppressWarnings("unchecked") // safe covariant cast 96 | public static ImmutableSet getOptionsForInputStream(OpenOption... options) { 97 | boolean nofollowLinks = false; 98 | for (OpenOption option : options) { 99 | if (checkNotNull(option) != READ) { 100 | if (option == LinkOption.NOFOLLOW_LINKS) { 101 | nofollowLinks = true; 102 | } else { 103 | throw new UnsupportedOperationException("'" + option + "' not allowed"); 104 | } 105 | } 106 | } 107 | 108 | // just return the link options for finding the file, nothing else is needed 109 | return (ImmutableSet) 110 | (ImmutableSet) (nofollowLinks ? NOFOLLOW_LINKS : FOLLOW_LINKS); 111 | } 112 | 113 | /** Returns an immutable set of open options for opening a new output stream. */ 114 | public static ImmutableSet getOptionsForOutputStream(OpenOption... options) { 115 | if (options.length == 0) { 116 | return DEFAULT_WRITE; 117 | } 118 | 119 | ImmutableSet result = addWrite(Arrays.asList(options)); 120 | if (result.contains(READ)) { 121 | throw new UnsupportedOperationException("'READ' not allowed"); 122 | } 123 | return result; 124 | } 125 | 126 | /** 127 | * Returns an {@link ImmutableSet} copy of the given {@code options}, adding {@link 128 | * StandardOpenOption#WRITE} if it isn't already present. 129 | */ 130 | private static ImmutableSet addWrite(Collection options) { 131 | return options.contains(WRITE) 132 | ? ImmutableSet.copyOf(options) 133 | : ImmutableSet.builder().add(WRITE).addAll(options).build(); 134 | } 135 | 136 | /** Returns an immutable set of the given options for a move. */ 137 | public static ImmutableSet getMoveOptions(CopyOption... options) { 138 | return ImmutableSet.copyOf(Lists.asList(LinkOption.NOFOLLOW_LINKS, options)); 139 | } 140 | 141 | /** Returns an immutable set of the given options for a copy. */ 142 | public static ImmutableSet getCopyOptions(CopyOption... options) { 143 | ImmutableSet result = ImmutableSet.copyOf(options); 144 | if (result.contains(ATOMIC_MOVE)) { 145 | throw new UnsupportedOperationException("'ATOMIC_MOVE' not allowed"); 146 | } 147 | return result; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/OwnerAttributeProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.jimfs.UserLookupService.createUserPrincipal; 21 | 22 | import com.google.common.collect.ImmutableMap; 23 | import com.google.common.collect.ImmutableSet; 24 | import java.io.IOException; 25 | import java.nio.file.attribute.FileAttributeView; 26 | import java.nio.file.attribute.FileOwnerAttributeView; 27 | import java.nio.file.attribute.UserPrincipal; 28 | import java.util.Map; 29 | import org.jspecify.annotations.Nullable; 30 | 31 | /** 32 | * Attribute provider that provides the {@link FileOwnerAttributeView} ("owner"). 33 | * 34 | * @author Colin Decker 35 | */ 36 | final class OwnerAttributeProvider extends AttributeProvider { 37 | 38 | private static final ImmutableSet ATTRIBUTES = ImmutableSet.of("owner"); 39 | 40 | private static final UserPrincipal DEFAULT_OWNER = createUserPrincipal("user"); 41 | 42 | @Override 43 | public String name() { 44 | return "owner"; 45 | } 46 | 47 | @Override 48 | public ImmutableSet fixedAttributes() { 49 | return ATTRIBUTES; 50 | } 51 | 52 | @Override 53 | public ImmutableMap defaultValues(Map userProvidedDefaults) { 54 | Object userProvidedOwner = userProvidedDefaults.get("owner:owner"); 55 | 56 | UserPrincipal owner = DEFAULT_OWNER; 57 | if (userProvidedOwner != null) { 58 | if (userProvidedOwner instanceof String) { 59 | owner = createUserPrincipal((String) userProvidedOwner); 60 | } else { 61 | throw invalidType("owner", "owner", userProvidedOwner, String.class, UserPrincipal.class); 62 | } 63 | } 64 | 65 | return ImmutableMap.of("owner:owner", owner); 66 | } 67 | 68 | @Override 69 | public @Nullable Object get(File file, String attribute) { 70 | if (attribute.equals("owner")) { 71 | return file.getAttribute("owner", "owner"); 72 | } 73 | return null; 74 | } 75 | 76 | @Override 77 | public void set(File file, String view, String attribute, Object value, boolean create) { 78 | if (attribute.equals("owner")) { 79 | checkNotCreate(view, attribute, create); 80 | UserPrincipal user = checkType(view, attribute, value, UserPrincipal.class); 81 | // TODO(cgdecker): Do we really need to do this? Any reason not to allow any UserPrincipal? 82 | if (!(user instanceof UserLookupService.JimfsUserPrincipal)) { 83 | user = createUserPrincipal(user.getName()); 84 | } 85 | file.setAttribute("owner", "owner", user); 86 | } 87 | } 88 | 89 | @Override 90 | public Class viewType() { 91 | return FileOwnerAttributeView.class; 92 | } 93 | 94 | @Override 95 | public FileOwnerAttributeView view( 96 | FileLookup lookup, ImmutableMap inheritedViews) { 97 | return new View(lookup); 98 | } 99 | 100 | /** Implementation of {@link FileOwnerAttributeView}. */ 101 | private static final class View extends AbstractAttributeView implements FileOwnerAttributeView { 102 | 103 | public View(FileLookup lookup) { 104 | super(lookup); 105 | } 106 | 107 | @Override 108 | public String name() { 109 | return "owner"; 110 | } 111 | 112 | @Override 113 | public UserPrincipal getOwner() throws IOException { 114 | return (UserPrincipal) lookupFile().getAttribute("owner", "owner"); 115 | } 116 | 117 | @Override 118 | public void setOwner(UserPrincipal owner) throws IOException { 119 | lookupFile().setAttribute("owner", "owner", checkNotNull(owner)); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/PathMatchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | import static com.google.common.base.Preconditions.checkNotNull; 21 | 22 | import com.google.common.annotations.VisibleForTesting; 23 | import com.google.common.base.Ascii; 24 | import com.google.common.base.MoreObjects; 25 | import com.google.common.collect.ImmutableSet; 26 | import java.nio.file.FileSystem; 27 | import java.nio.file.Path; 28 | import java.nio.file.PathMatcher; 29 | import java.util.regex.Pattern; 30 | 31 | /** 32 | * {@link PathMatcher} factory for any file system. 33 | * 34 | * @author Colin Decker 35 | */ 36 | final class PathMatchers { 37 | 38 | private PathMatchers() {} 39 | 40 | /** 41 | * Gets a {@link PathMatcher} for the given syntax and pattern as specified by {@link 42 | * FileSystem#getPathMatcher}. The {@code separators} string contains the path name element 43 | * separators (one character each) recognized by the file system. For a glob-syntax path matcher, 44 | * any of the given separators will be recognized as a separator in the pattern, and any of them 45 | * will be matched as a separator when checking a path. 46 | */ 47 | // TODO(cgdecker): Should I be just canonicalizing separators rather than matching any separator? 48 | // Perhaps so, assuming Path always canonicalizes its separators 49 | public static PathMatcher getPathMatcher( 50 | String syntaxAndPattern, String separators, ImmutableSet normalizations) { 51 | int syntaxSeparator = syntaxAndPattern.indexOf(':'); 52 | checkArgument( 53 | syntaxSeparator > 0, "Must be of the form 'syntax:pattern': %s", syntaxAndPattern); 54 | 55 | String syntax = Ascii.toLowerCase(syntaxAndPattern.substring(0, syntaxSeparator)); 56 | String pattern = syntaxAndPattern.substring(syntaxSeparator + 1); 57 | 58 | switch (syntax) { 59 | case "glob": 60 | pattern = GlobToRegex.toRegex(pattern, separators); 61 | // fall through 62 | case "regex": 63 | return fromRegex(pattern, normalizations); 64 | default: 65 | throw new UnsupportedOperationException("Invalid syntax: " + syntaxAndPattern); 66 | } 67 | } 68 | 69 | private static PathMatcher fromRegex(String regex, Iterable normalizations) { 70 | return new RegexPathMatcher(PathNormalization.compilePattern(regex, normalizations)); 71 | } 72 | 73 | /** 74 | * {@code PathMatcher} that matches the {@code toString()} form of a {@code Path} against a regex 75 | * {@code Pattern}. 76 | */ 77 | @VisibleForTesting 78 | static final class RegexPathMatcher implements PathMatcher { 79 | 80 | private final Pattern pattern; 81 | 82 | private RegexPathMatcher(Pattern pattern) { 83 | this.pattern = checkNotNull(pattern); 84 | } 85 | 86 | @Override 87 | public boolean matches(Path path) { 88 | return pattern.matcher(path.toString()).matches(); 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return MoreObjects.toStringHelper(this).addValue(pattern).toString(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/PathNormalization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import com.google.common.base.Ascii; 20 | import com.google.common.base.Function; 21 | import com.ibm.icu.lang.UCharacter; 22 | import java.text.Normalizer; 23 | import java.util.regex.Pattern; 24 | 25 | /** 26 | * Normalizations that can be applied to names in paths. Includes Unicode normalizations and 27 | * normalizations for case insensitive paths. These normalizations can be set in {@code 28 | * Configuration.Builder} when creating a Jimfs file system instance and are automatically applied 29 | * to paths in the file system. 30 | * 31 | * @author Colin Decker 32 | */ 33 | public enum PathNormalization implements Function { 34 | 35 | /** No normalization. */ 36 | NONE(0) { 37 | @Override 38 | public String apply(String string) { 39 | return string; 40 | } 41 | }, 42 | 43 | /** Unicode composed normalization (form {@linkplain java.text.Normalizer.Form#NFC NFC}). */ 44 | NFC(Pattern.CANON_EQ) { 45 | @Override 46 | public String apply(String string) { 47 | return Normalizer.normalize(string, Normalizer.Form.NFC); 48 | } 49 | }, 50 | 51 | /** Unicode decomposed normalization (form {@linkplain java.text.Normalizer.Form#NFD NFD}). */ 52 | NFD(Pattern.CANON_EQ) { 53 | @Override 54 | public String apply(String string) { 55 | return Normalizer.normalize(string, Normalizer.Form.NFD); 56 | } 57 | }, 58 | 59 | /* 60 | * Some notes on case folding/case insensitivity of file systems: 61 | * 62 | * In general (I don't have any counterexamples) case-insensitive file systems handle 63 | * their case insensitivity in a locale-independent way. NTFS, for example, writes a 64 | * special case mapping file ($UpCase) to the file system when it's first initialized, 65 | * and this is not affected by the locale of either the user or the copy of Windows 66 | * being used. This means that it will NOT handle i/I-variants in filenames as you'd 67 | * expect for Turkic languages, even for a Turkish user who has installed a Turkish 68 | * copy of Windows. 69 | */ 70 | 71 | /** Unicode case folding for case insensitive paths. Requires ICU4J on the classpath. */ 72 | CASE_FOLD_UNICODE(Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) { 73 | @Override 74 | public String apply(String string) { 75 | try { 76 | return UCharacter.foldCase(string, true); 77 | } catch (NoClassDefFoundError e) { 78 | NoClassDefFoundError error = 79 | new NoClassDefFoundError( 80 | "PathNormalization.CASE_FOLD_UNICODE requires ICU4J. " 81 | + "Did you forget to include it on your classpath?"); 82 | error.initCause(e); 83 | throw error; 84 | } 85 | } 86 | }, 87 | 88 | /** ASCII case folding for simple case insensitive paths. */ 89 | CASE_FOLD_ASCII(Pattern.CASE_INSENSITIVE) { 90 | @Override 91 | public String apply(String string) { 92 | return Ascii.toLowerCase(string); 93 | } 94 | }; 95 | 96 | private final int patternFlags; 97 | 98 | private PathNormalization(int patternFlags) { 99 | this.patternFlags = patternFlags; 100 | } 101 | 102 | /** Applies this normalization to the given string, returning the normalized result. */ 103 | @Override 104 | public abstract String apply(String string); 105 | 106 | /** 107 | * Returns the flags that should be used when creating a regex {@link Pattern} in order to 108 | * approximate this normalization. 109 | */ 110 | public int patternFlags() { 111 | return patternFlags; 112 | } 113 | 114 | /** 115 | * Applies the given normalizations to the given string in order, returning the normalized result. 116 | */ 117 | public static String normalize(String string, Iterable normalizations) { 118 | String result = string; 119 | for (PathNormalization normalization : normalizations) { 120 | result = normalization.apply(result); 121 | } 122 | return result; 123 | } 124 | 125 | /** Compiles a regex pattern using flags based on the given normalizations. */ 126 | public static Pattern compilePattern(String regex, Iterable normalizations) { 127 | int flags = 0; 128 | for (PathNormalization normalization : normalizations) { 129 | flags |= normalization.patternFlags(); 130 | } 131 | return Pattern.compile(regex, flags); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/PathURLConnection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static java.nio.charset.StandardCharsets.UTF_8; 21 | 22 | import com.google.common.base.Ascii; 23 | import com.google.common.base.MoreObjects; 24 | import com.google.common.collect.ImmutableListMultimap; 25 | import com.google.common.collect.ImmutableMap; 26 | import com.google.common.collect.Iterables; 27 | import java.io.ByteArrayInputStream; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.net.URI; 31 | import java.net.URISyntaxException; 32 | import java.net.URL; 33 | import java.net.URLConnection; 34 | import java.nio.file.DirectoryStream; 35 | import java.nio.file.Files; 36 | import java.nio.file.Path; 37 | import java.nio.file.Paths; 38 | import java.nio.file.attribute.FileTime; 39 | import java.text.DateFormat; 40 | import java.text.SimpleDateFormat; 41 | import java.util.Date; 42 | import java.util.List; 43 | import java.util.Locale; 44 | import java.util.Map; 45 | import java.util.TimeZone; 46 | import org.jspecify.annotations.Nullable; 47 | 48 | /** 49 | * {@code URLConnection} implementation. 50 | * 51 | * @author Colin Decker 52 | */ 53 | final class PathURLConnection extends URLConnection { 54 | 55 | /* 56 | * This implementation should be able to work for any proper file system implementation... it 57 | * might be useful to release it and make it usable by other file systems. 58 | */ 59 | 60 | private static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss \'GMT\'"; 61 | private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; 62 | 63 | private InputStream stream; 64 | private ImmutableListMultimap headers = ImmutableListMultimap.of(); 65 | 66 | PathURLConnection(URL url) { 67 | super(checkNotNull(url)); 68 | } 69 | 70 | @Override 71 | public void connect() throws IOException { 72 | if (stream != null) { 73 | return; 74 | } 75 | 76 | Path path = Paths.get(toUri(url)); 77 | 78 | long length; 79 | if (Files.isDirectory(path)) { 80 | // Match File URL behavior for directories by having the stream contain the filenames in 81 | // the directory separated by newlines. 82 | StringBuilder builder = new StringBuilder(); 83 | try (DirectoryStream files = Files.newDirectoryStream(path)) { 84 | for (Path file : files) { 85 | builder.append(file.getFileName()).append('\n'); 86 | } 87 | } 88 | byte[] bytes = builder.toString().getBytes(UTF_8); 89 | stream = new ByteArrayInputStream(bytes); 90 | length = bytes.length; 91 | } else { 92 | stream = Files.newInputStream(path); 93 | length = Files.size(path); 94 | } 95 | 96 | FileTime lastModified = Files.getLastModifiedTime(path); 97 | String contentType = 98 | MoreObjects.firstNonNull(Files.probeContentType(path), DEFAULT_CONTENT_TYPE); 99 | 100 | ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); 101 | builder.put("content-length", "" + length); 102 | builder.put("content-type", contentType); 103 | if (lastModified != null) { 104 | DateFormat format = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); 105 | format.setTimeZone(TimeZone.getTimeZone("GMT")); 106 | builder.put("last-modified", format.format(new Date(lastModified.toMillis()))); 107 | } 108 | 109 | headers = builder.build(); 110 | } 111 | 112 | private static URI toUri(URL url) throws IOException { 113 | try { 114 | return url.toURI(); 115 | } catch (URISyntaxException e) { 116 | throw new IOException("URL " + url + " cannot be converted to a URI", e); 117 | } 118 | } 119 | 120 | @Override 121 | public InputStream getInputStream() throws IOException { 122 | connect(); 123 | return stream; 124 | } 125 | 126 | @SuppressWarnings("unchecked") // safe by specification of ListMultimap.asMap() 127 | @Override 128 | public Map> getHeaderFields() { 129 | try { 130 | connect(); 131 | } catch (IOException e) { 132 | return ImmutableMap.of(); 133 | } 134 | return (ImmutableMap>) (ImmutableMap) headers.asMap(); 135 | } 136 | 137 | @Override 138 | public @Nullable String getHeaderField(String name) { 139 | try { 140 | connect(); 141 | } catch (IOException e) { 142 | return null; 143 | } 144 | 145 | // no header should have more than one value 146 | return Iterables.getFirst(headers.get(Ascii.toLowerCase(name)), null); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/StandardAttributeProviders.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import com.google.common.collect.ImmutableMap; 20 | import org.jspecify.annotations.Nullable; 21 | 22 | /** 23 | * Static registry of {@link AttributeProvider} implementations for the standard set of file 24 | * attribute views Jimfs supports. 25 | * 26 | * @author Colin Decker 27 | */ 28 | final class StandardAttributeProviders { 29 | 30 | private StandardAttributeProviders() {} 31 | 32 | private static final ImmutableMap PROVIDERS = 33 | new ImmutableMap.Builder() 34 | .put("basic", new BasicAttributeProvider()) 35 | .put("owner", new OwnerAttributeProvider()) 36 | .put("posix", new PosixAttributeProvider()) 37 | .put("dos", new DosAttributeProvider()) 38 | .put("acl", new AclAttributeProvider()) 39 | .put("user", new UserDefinedAttributeProvider()) 40 | .build(); 41 | 42 | /** 43 | * Returns the attribute provider for the given view, or {@code null} if the given view is not one 44 | * of the attribute views this supports. 45 | */ 46 | public static @Nullable AttributeProvider get(String view) { 47 | AttributeProvider provider = PROVIDERS.get(view); 48 | 49 | if (provider == null && view.equals("unix")) { 50 | // create a new UnixAttributeProvider per file system, as it does some caching that should be 51 | // cleaned up when the file system is garbage collected 52 | return new UnixAttributeProvider(); 53 | } 54 | 55 | return provider; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/SymbolicLink.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import java.nio.file.attribute.FileTime; 22 | 23 | /** 24 | * A symbolic link file, containing a {@linkplain JimfsPath path}. 25 | * 26 | * @author Colin Decker 27 | */ 28 | final class SymbolicLink extends File { 29 | 30 | private final JimfsPath target; 31 | 32 | /** Creates a new symbolic link with the given ID and target. */ 33 | public static SymbolicLink create(int id, FileTime creationTime, JimfsPath target) { 34 | return new SymbolicLink(id, creationTime, target); 35 | } 36 | 37 | private SymbolicLink(int id, FileTime creationTime, JimfsPath target) { 38 | super(id, creationTime); 39 | this.target = checkNotNull(target); 40 | } 41 | 42 | /** Returns the target path of this symbolic link. */ 43 | JimfsPath target() { 44 | return target; 45 | } 46 | 47 | @Override 48 | File copyWithoutContent(int id, FileTime creationTime) { 49 | return SymbolicLink.create(id, creationTime, target); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/SystemFileTimeSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.nio.file.attribute.FileTime; 20 | import java.time.Instant; 21 | 22 | /** Implementation of of {@link FileTimeSource} that gets the current time from the system. */ 23 | enum SystemFileTimeSource implements FileTimeSource { 24 | INSTANCE; 25 | 26 | @Override 27 | public FileTime now() { 28 | return FileTime.from(Instant.now()); 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "SystemFileTimeSource"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/UnixFileAttributeView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.nio.file.attribute.FileAttributeView; 20 | 21 | /** 22 | * Dummy view interface for the "unix" view, which doesn't have a public view interface. 23 | * 24 | * @author Colin Decker 25 | */ 26 | interface UnixFileAttributeView extends FileAttributeView {} 27 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/UnixPathType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | 21 | import java.nio.file.InvalidPathException; 22 | import org.jspecify.annotations.Nullable; 23 | 24 | /** 25 | * Unix-style path type. 26 | * 27 | * @author Colin Decker 28 | */ 29 | final class UnixPathType extends PathType { 30 | 31 | /** Unix path type. */ 32 | static final PathType INSTANCE = new UnixPathType(); 33 | 34 | private UnixPathType() { 35 | super(false, '/'); 36 | } 37 | 38 | @Override 39 | public ParseResult parsePath(String path) { 40 | if (path.isEmpty()) { 41 | return emptyPath(); 42 | } 43 | 44 | checkValid(path); 45 | 46 | String root = path.startsWith("/") ? "/" : null; 47 | return new ParseResult(root, splitter().split(path)); 48 | } 49 | 50 | private static void checkValid(String path) { 51 | int nulIndex = path.indexOf('\0'); 52 | if (nulIndex != -1) { 53 | throw new InvalidPathException(path, "nul character not allowed", nulIndex); 54 | } 55 | } 56 | 57 | @Override 58 | public String toString(@Nullable String root, Iterable names) { 59 | StringBuilder builder = new StringBuilder(); 60 | if (root != null) { 61 | builder.append(root); 62 | } 63 | joiner().appendTo(builder, names); 64 | return builder.toString(); 65 | } 66 | 67 | @Override 68 | public String toUriPath(String root, Iterable names, boolean directory) { 69 | StringBuilder builder = new StringBuilder(); 70 | for (String name : names) { 71 | builder.append('/').append(name); 72 | } 73 | 74 | if (directory || builder.length() == 0) { 75 | builder.append('/'); 76 | } 77 | return builder.toString(); 78 | } 79 | 80 | @Override 81 | public ParseResult parseUriPath(String uriPath) { 82 | checkArgument(uriPath.startsWith("/"), "uriPath (%s) must start with /", uriPath); 83 | return parsePath(uriPath); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/UserDefinedAttributeProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import com.google.common.collect.ImmutableMap; 22 | import com.google.common.collect.ImmutableSet; 23 | import java.io.IOException; 24 | import java.nio.ByteBuffer; 25 | import java.nio.file.attribute.FileAttributeView; 26 | import java.nio.file.attribute.UserDefinedFileAttributeView; 27 | import java.util.List; 28 | import org.jspecify.annotations.Nullable; 29 | 30 | /** 31 | * Attribute provider that provides the {@link UserDefinedFileAttributeView} ("user"). Unlike most 32 | * other attribute providers, this one has no pre-defined set of attributes. Rather, it allows 33 | * arbitrary user defined attributes to be set (as {@code ByteBuffer} or {@code byte[]}) and read 34 | * (as {@code byte[]}). 35 | * 36 | * @author Colin Decker 37 | */ 38 | final class UserDefinedAttributeProvider extends AttributeProvider { 39 | 40 | UserDefinedAttributeProvider() {} 41 | 42 | @Override 43 | public String name() { 44 | return "user"; 45 | } 46 | 47 | @Override 48 | public ImmutableSet fixedAttributes() { 49 | // no fixed set of attributes for this view 50 | return ImmutableSet.of(); 51 | } 52 | 53 | @Override 54 | public boolean supports(String attribute) { 55 | // any attribute name is supported 56 | return true; 57 | } 58 | 59 | @Override 60 | public ImmutableSet attributes(File file) { 61 | return userDefinedAttributes(file); 62 | } 63 | 64 | private static ImmutableSet userDefinedAttributes(File file) { 65 | ImmutableSet.Builder builder = ImmutableSet.builder(); 66 | for (String attribute : file.getAttributeNames("user")) { 67 | builder.add(attribute); 68 | } 69 | return builder.build(); 70 | } 71 | 72 | @Override 73 | public @Nullable Object get(File file, String attribute) { 74 | Object value = file.getAttribute("user", attribute); 75 | if (value instanceof byte[]) { 76 | byte[] bytes = (byte[]) value; 77 | return bytes.clone(); 78 | } 79 | return null; 80 | } 81 | 82 | @Override 83 | public void set(File file, String view, String attribute, Object value, boolean create) { 84 | checkNotNull(value); 85 | checkNotCreate(view, attribute, create); 86 | 87 | byte[] bytes; 88 | if (value instanceof byte[]) { 89 | bytes = ((byte[]) value).clone(); 90 | } else if (value instanceof ByteBuffer) { 91 | // value instanceof ByteBuffer 92 | ByteBuffer buffer = (ByteBuffer) value; 93 | bytes = new byte[buffer.remaining()]; 94 | buffer.get(bytes); 95 | } else { 96 | throw invalidType(view, attribute, value, byte[].class, ByteBuffer.class); 97 | } 98 | 99 | file.setAttribute("user", attribute, bytes); 100 | } 101 | 102 | @Override 103 | public Class viewType() { 104 | return UserDefinedFileAttributeView.class; 105 | } 106 | 107 | @Override 108 | public UserDefinedFileAttributeView view( 109 | FileLookup lookup, ImmutableMap inheritedViews) { 110 | return new View(lookup); 111 | } 112 | 113 | /** Implementation of {@link UserDefinedFileAttributeView}. */ 114 | private static class View extends AbstractAttributeView implements UserDefinedFileAttributeView { 115 | 116 | public View(FileLookup lookup) { 117 | super(lookup); 118 | } 119 | 120 | @Override 121 | public String name() { 122 | return "user"; 123 | } 124 | 125 | @Override 126 | public List list() throws IOException { 127 | return userDefinedAttributes(lookupFile()).asList(); 128 | } 129 | 130 | private byte[] getStoredBytes(String name) throws IOException { 131 | byte[] bytes = (byte[]) lookupFile().getAttribute(name(), name); 132 | if (bytes == null) { 133 | throw new IllegalArgumentException("attribute '" + name() + ":" + name + "' is not set"); 134 | } 135 | return bytes; 136 | } 137 | 138 | @Override 139 | public int size(String name) throws IOException { 140 | return getStoredBytes(name).length; 141 | } 142 | 143 | @Override 144 | public int read(String name, ByteBuffer dst) throws IOException { 145 | byte[] bytes = getStoredBytes(name); 146 | dst.put(bytes); 147 | return bytes.length; 148 | } 149 | 150 | @Override 151 | public int write(String name, ByteBuffer src) throws IOException { 152 | byte[] bytes = new byte[src.remaining()]; 153 | src.get(bytes); 154 | lookupFile().setAttribute(name(), name, bytes); 155 | return bytes.length; 156 | } 157 | 158 | @Override 159 | public void delete(String name) throws IOException { 160 | lookupFile().deleteAttribute(name(), name); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/UserLookupService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import java.io.IOException; 22 | import java.nio.file.attribute.GroupPrincipal; 23 | import java.nio.file.attribute.UserPrincipal; 24 | import java.nio.file.attribute.UserPrincipalLookupService; 25 | import java.nio.file.attribute.UserPrincipalNotFoundException; 26 | 27 | /** 28 | * {@link UserPrincipalLookupService} implementation. 29 | * 30 | * @author Colin Decker 31 | */ 32 | final class UserLookupService extends UserPrincipalLookupService { 33 | 34 | private final boolean supportsGroups; 35 | 36 | public UserLookupService(boolean supportsGroups) { 37 | this.supportsGroups = supportsGroups; 38 | } 39 | 40 | @Override 41 | public UserPrincipal lookupPrincipalByName(String name) { 42 | return createUserPrincipal(name); 43 | } 44 | 45 | @Override 46 | public GroupPrincipal lookupPrincipalByGroupName(String group) throws IOException { 47 | if (!supportsGroups) { 48 | throw new UserPrincipalNotFoundException(group); // required by spec 49 | } 50 | return createGroupPrincipal(group); 51 | } 52 | 53 | /** Creates a {@link UserPrincipal} for the given user name. */ 54 | static UserPrincipal createUserPrincipal(String name) { 55 | return new JimfsUserPrincipal(name); 56 | } 57 | 58 | /** Creates a {@link GroupPrincipal} for the given group name. */ 59 | static GroupPrincipal createGroupPrincipal(String name) { 60 | return new JimfsGroupPrincipal(name); 61 | } 62 | 63 | /** Base class for {@link UserPrincipal} and {@link GroupPrincipal} implementations. */ 64 | private abstract static class NamedPrincipal implements UserPrincipal { 65 | 66 | protected final String name; 67 | 68 | private NamedPrincipal(String name) { 69 | this.name = checkNotNull(name); 70 | } 71 | 72 | @Override 73 | public final String getName() { 74 | return name; 75 | } 76 | 77 | @Override 78 | public final int hashCode() { 79 | return name.hashCode(); 80 | } 81 | 82 | @Override 83 | public final String toString() { 84 | return name; 85 | } 86 | } 87 | 88 | /** {@link UserPrincipal} implementation. */ 89 | static final class JimfsUserPrincipal extends NamedPrincipal { 90 | 91 | private JimfsUserPrincipal(String name) { 92 | super(name); 93 | } 94 | 95 | @Override 96 | public boolean equals(Object obj) { 97 | return obj instanceof JimfsUserPrincipal 98 | && getName().equals(((JimfsUserPrincipal) obj).getName()); 99 | } 100 | } 101 | 102 | /** {@link GroupPrincipal} implementation. */ 103 | static final class JimfsGroupPrincipal extends NamedPrincipal implements GroupPrincipal { 104 | 105 | private JimfsGroupPrincipal(String name) { 106 | super(name); 107 | } 108 | 109 | @Override 110 | public boolean equals(Object obj) { 111 | return obj instanceof JimfsGroupPrincipal && ((JimfsGroupPrincipal) obj).name.equals(name); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | import static com.google.common.base.Preconditions.checkNotNull; 21 | 22 | import com.google.common.collect.ImmutableCollection; 23 | 24 | /** 25 | * Miscellaneous static utility methods. 26 | * 27 | * @author Colin Decker 28 | * @author Austin Appleby 29 | */ 30 | final class Util { 31 | 32 | private Util() {} 33 | 34 | /** Returns the next power of 2 >= n. */ 35 | public static int nextPowerOf2(int n) { 36 | if (n == 0) { 37 | return 1; 38 | } 39 | int b = Integer.highestOneBit(n); 40 | return b == n ? n : b << 1; 41 | } 42 | 43 | /** 44 | * Checks that the given number is not negative, throwing IAE if it is. The given description 45 | * describes the number in the exception message. 46 | */ 47 | static void checkNotNegative(long n, String description) { 48 | checkArgument(n >= 0, "%s must not be negative: %s", description, n); 49 | } 50 | 51 | /** Checks that no element in the given iterable is null, throwing NPE if any is. */ 52 | static void checkNoneNull(Iterable objects) { 53 | if (!(objects instanceof ImmutableCollection)) { 54 | for (Object o : objects) { 55 | checkNotNull(o); 56 | } 57 | } 58 | } 59 | 60 | private static final int C1 = 0xcc9e2d51; 61 | private static final int C2 = 0x1b873593; 62 | 63 | /* 64 | * This method was rewritten in Java from an intermediate step of the Murmur hash function in 65 | * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the 66 | * following header: 67 | * 68 | * MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author 69 | * hereby disclaims copyright to this source code. 70 | */ 71 | static int smearHash(int hashCode) { 72 | return C2 * Integer.rotateLeft(hashCode * C1, 15); 73 | } 74 | 75 | private static final int ARRAY_LEN = 8192; 76 | private static final byte[] ZERO_ARRAY = new byte[ARRAY_LEN]; 77 | private static final byte[][] NULL_ARRAY = new byte[ARRAY_LEN][]; 78 | 79 | /** Zeroes all bytes between off (inclusive) and off + len (exclusive) in the given array. */ 80 | static void zero(byte[] bytes, int off, int len) { 81 | // this is significantly faster than looping or Arrays.fill (which loops), particularly when 82 | // the length of the slice to be zeroed is <= to ARRAY_LEN (in that case, it's faster by a 83 | // factor of 2) 84 | int remaining = len; 85 | while (remaining > ARRAY_LEN) { 86 | System.arraycopy(ZERO_ARRAY, 0, bytes, off, ARRAY_LEN); 87 | off += ARRAY_LEN; 88 | remaining -= ARRAY_LEN; 89 | } 90 | 91 | System.arraycopy(ZERO_ARRAY, 0, bytes, off, remaining); 92 | } 93 | 94 | /** 95 | * Clears (sets to null) all blocks between off (inclusive) and off + len (exclusive) in the given 96 | * array. 97 | */ 98 | static void clear(byte[][] blocks, int off, int len) { 99 | // this is significantly faster than looping or Arrays.fill (which loops), particularly when 100 | // the length of the slice to be cleared is <= to ARRAY_LEN (in that case, it's faster by a 101 | // factor of 2) 102 | int remaining = len; 103 | while (remaining > ARRAY_LEN) { 104 | System.arraycopy(NULL_ARRAY, 0, blocks, off, ARRAY_LEN); 105 | off += ARRAY_LEN; 106 | remaining -= ARRAY_LEN; 107 | } 108 | 109 | System.arraycopy(NULL_ARRAY, 0, blocks, off, remaining); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/WatchServiceConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | import static com.google.common.base.Preconditions.checkNotNull; 21 | import static java.util.concurrent.TimeUnit.SECONDS; 22 | 23 | import java.nio.file.WatchService; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * Configuration for the {@link WatchService} implementation used by a file system. 28 | * 29 | * @author Colin Decker 30 | * @since 1.1 31 | */ 32 | public abstract class WatchServiceConfiguration { 33 | 34 | /** The default configuration that's used if the user doesn't provide anything more specific. */ 35 | static final WatchServiceConfiguration DEFAULT = polling(5, SECONDS); 36 | 37 | /** 38 | * Returns a configuration for a {@link WatchService} that polls watched directories for changes 39 | * every {@code interval} of the given {@code timeUnit} (e.g. every 5 {@link TimeUnit#SECONDS 40 | * seconds}). 41 | */ 42 | @SuppressWarnings("GoodTime") // should accept a java.time.Duration 43 | public static WatchServiceConfiguration polling(long interval, TimeUnit timeUnit) { 44 | return new PollingConfig(interval, timeUnit); 45 | } 46 | 47 | WatchServiceConfiguration() {} 48 | 49 | /** Creates a new {@link AbstractWatchService} implementation. */ 50 | // return type and parameters of this method subject to change if needed for any future 51 | // implementations 52 | abstract AbstractWatchService newWatchService(FileSystemView view, PathService pathService); 53 | 54 | /** Implementation for {@link #polling}. */ 55 | private static final class PollingConfig extends WatchServiceConfiguration { 56 | 57 | private final long interval; 58 | private final TimeUnit timeUnit; 59 | 60 | private PollingConfig(long interval, TimeUnit timeUnit) { 61 | checkArgument(interval > 0, "interval (%s) must be positive", interval); 62 | this.interval = interval; 63 | this.timeUnit = checkNotNull(timeUnit); 64 | } 65 | 66 | @Override 67 | AbstractWatchService newWatchService(FileSystemView view, PathService pathService) { 68 | return new PollingWatchService(view, pathService, view.state(), interval, timeUnit); 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return "WatchServiceConfiguration.polling(" + interval + ", " + timeUnit + ")"; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /jimfs/src/main/java/com/google/common/jimfs/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Package containing the Jimfs file system API and implementation. Most users should only need to 19 | * use the {@link com.google.common.jimfs.Jimfs Jimfs} and {@link 20 | * com.google.common.jimfs.Configuration Configuration} classes. 21 | */ 22 | @CheckReturnValue 23 | @ParametersAreNonnullByDefault 24 | package com.google.common.jimfs; 25 | 26 | import com.google.errorprone.annotations.CheckReturnValue; 27 | import javax.annotation.ParametersAreNonnullByDefault; 28 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/AbstractAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.fail; 21 | 22 | import com.google.common.collect.ImmutableMap; 23 | import java.io.IOException; 24 | import java.nio.file.attribute.FileAttributeView; 25 | import java.util.Map; 26 | import java.util.Set; 27 | import org.junit.Before; 28 | 29 | /** 30 | * Abstract base class for tests of individual {@link AttributeProvider} implementations. 31 | * 32 | * @author Colin Decker 33 | */ 34 | public abstract class AbstractAttributeProviderTest

{ 35 | 36 | protected static final ImmutableMap NO_INHERITED_VIEWS = 37 | ImmutableMap.of(); 38 | 39 | protected final FakeFileTimeSource fileTimeSource = new FakeFileTimeSource(); 40 | 41 | protected P provider; 42 | protected File file; 43 | 44 | /** Create the provider being tested. */ 45 | protected abstract P createProvider(); 46 | 47 | /** Creates the set of providers the provider being tested depends on. */ 48 | protected abstract Set createInheritedProviders(); 49 | 50 | protected FileLookup fileLookup() { 51 | return new FileLookup() { 52 | @Override 53 | public File lookup() throws IOException { 54 | return file; 55 | } 56 | }; 57 | } 58 | 59 | @Before 60 | public void setUp() { 61 | this.provider = createProvider(); 62 | this.file = Directory.create(0, fileTimeSource.now()); 63 | 64 | Map defaultValues = createDefaultValues(); 65 | setDefaultValues(file, provider, defaultValues); 66 | 67 | Set inheritedProviders = createInheritedProviders(); 68 | for (AttributeProvider inherited : inheritedProviders) { 69 | setDefaultValues(file, inherited, defaultValues); 70 | } 71 | } 72 | 73 | private static void setDefaultValues( 74 | File file, AttributeProvider provider, Map defaultValues) { 75 | Map defaults = provider.defaultValues(defaultValues); 76 | for (Map.Entry entry : defaults.entrySet()) { 77 | int separatorIndex = entry.getKey().indexOf(':'); 78 | String view = entry.getKey().substring(0, separatorIndex); 79 | String attr = entry.getKey().substring(separatorIndex + 1); 80 | file.setAttribute(view, attr, entry.getValue()); 81 | } 82 | } 83 | 84 | protected Map createDefaultValues() { 85 | return ImmutableMap.of(); 86 | } 87 | 88 | // assertions 89 | 90 | protected void assertSupportsAll(String... attributes) { 91 | for (String attribute : attributes) { 92 | assertThat(provider.supports(attribute)).isTrue(); 93 | } 94 | } 95 | 96 | protected void assertContainsAll(File file, ImmutableMap expectedAttributes) { 97 | for (Map.Entry entry : expectedAttributes.entrySet()) { 98 | String attribute = entry.getKey(); 99 | Object value = entry.getValue(); 100 | 101 | assertThat(provider.get(file, attribute)).isEqualTo(value); 102 | } 103 | } 104 | 105 | protected void assertSetAndGetSucceeds(String attribute, Object value) { 106 | assertSetAndGetSucceeds(attribute, value, false); 107 | } 108 | 109 | protected void assertSetAndGetSucceeds(String attribute, Object value, boolean create) { 110 | provider.set(file, provider.name(), attribute, value, create); 111 | assertThat(provider.get(file, attribute)).isEqualTo(value); 112 | } 113 | 114 | protected void assertSetAndGetSucceedsOnCreate(String attribute, Object value) { 115 | assertSetAndGetSucceeds(attribute, value, true); 116 | } 117 | 118 | @SuppressWarnings("EmptyCatchBlock") 119 | protected void assertSetFails(String attribute, Object value) { 120 | try { 121 | provider.set(file, provider.name(), attribute, value, false); 122 | fail(); 123 | } catch (IllegalArgumentException expected) { 124 | } 125 | } 126 | 127 | @SuppressWarnings("EmptyCatchBlock") 128 | protected void assertSetFailsOnCreate(String attribute, Object value) { 129 | try { 130 | provider.set(file, provider.name(), attribute, value, true); 131 | fail(); 132 | } catch (UnsupportedOperationException expected) { 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/AbstractJimfsIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.PathSubject.paths; 20 | import static com.google.common.truth.Truth.assertThat; 21 | import static com.google.common.truth.Truth.assert_; 22 | 23 | import java.io.IOException; 24 | import java.nio.file.FileSystem; 25 | import java.nio.file.Files; 26 | import java.nio.file.LinkOption; 27 | import java.nio.file.Path; 28 | import java.nio.file.attribute.BasicFileAttributes; 29 | import java.nio.file.attribute.FileTime; 30 | import org.junit.After; 31 | import org.junit.Before; 32 | 33 | /** @author Colin Decker */ 34 | public abstract class AbstractJimfsIntegrationTest { 35 | 36 | protected FileSystem fs; 37 | 38 | @Before 39 | public void setUp() throws IOException { 40 | fs = createFileSystem(); 41 | } 42 | 43 | @After 44 | public void tearDown() throws IOException { 45 | fs.close(); 46 | } 47 | 48 | /** Creates the file system to use in the tests. */ 49 | protected abstract FileSystem createFileSystem(); 50 | 51 | // helpers 52 | 53 | protected Path path(String first, String... more) { 54 | return fs.getPath(first, more); 55 | } 56 | 57 | protected Object getFileKey(String path, LinkOption... options) throws IOException { 58 | return Files.getAttribute(path(path), "fileKey", options); 59 | } 60 | 61 | protected PathSubject assertThatPath(String path, LinkOption... options) { 62 | return assertThatPath(path(path), options); 63 | } 64 | 65 | protected static PathSubject assertThatPath(Path path, LinkOption... options) { 66 | PathSubject subject = assert_().about(paths()).that(path); 67 | if (options.length != 0) { 68 | subject = subject.noFollowLinks(); 69 | } 70 | return subject; 71 | } 72 | 73 | /** Tester for testing changes in file times. */ 74 | protected static final class FileTimeTester { 75 | 76 | private final Path path; 77 | 78 | private FileTime accessTime; 79 | private FileTime modifiedTime; 80 | 81 | FileTimeTester(Path path) throws IOException { 82 | this.path = path; 83 | 84 | BasicFileAttributes attrs = attrs(); 85 | accessTime = attrs.lastAccessTime(); 86 | modifiedTime = attrs.lastModifiedTime(); 87 | } 88 | 89 | private BasicFileAttributes attrs() throws IOException { 90 | return Files.readAttributes(path, BasicFileAttributes.class); 91 | } 92 | 93 | public void assertAccessTimeChanged() throws IOException { 94 | FileTime t = attrs().lastAccessTime(); 95 | assertThat(t).isNotEqualTo(accessTime); 96 | accessTime = t; 97 | } 98 | 99 | public void assertAccessTimeDidNotChange() throws IOException { 100 | FileTime t = attrs().lastAccessTime(); 101 | assertThat(t).isEqualTo(accessTime); 102 | } 103 | 104 | public void assertModifiedTimeChanged() throws IOException { 105 | FileTime t = attrs().lastModifiedTime(); 106 | assertThat(t).isNotEqualTo(modifiedTime); 107 | modifiedTime = t; 108 | } 109 | 110 | public void assertModifiedTimeDidNotChange() throws IOException { 111 | FileTime t = attrs().lastModifiedTime(); 112 | assertThat(t).isEqualTo(modifiedTime); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/AclAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.UserLookupService.createUserPrincipal; 20 | import static com.google.common.truth.Truth.assertThat; 21 | import static java.nio.file.attribute.AclEntryFlag.DIRECTORY_INHERIT; 22 | import static java.nio.file.attribute.AclEntryPermission.APPEND_DATA; 23 | import static java.nio.file.attribute.AclEntryPermission.DELETE; 24 | import static java.nio.file.attribute.AclEntryType.ALLOW; 25 | import static org.junit.Assert.assertNotNull; 26 | 27 | import com.google.common.collect.ImmutableList; 28 | import com.google.common.collect.ImmutableMap; 29 | import com.google.common.collect.ImmutableSet; 30 | import java.io.IOException; 31 | import java.nio.file.attribute.AclEntry; 32 | import java.nio.file.attribute.AclFileAttributeView; 33 | import java.nio.file.attribute.FileAttributeView; 34 | import java.nio.file.attribute.UserPrincipal; 35 | import java.util.Map; 36 | import java.util.Set; 37 | import org.junit.Test; 38 | import org.junit.runner.RunWith; 39 | import org.junit.runners.JUnit4; 40 | 41 | /** 42 | * Tests for {@link AclAttributeProvider}. 43 | * 44 | * @author Colin Decker 45 | */ 46 | @RunWith(JUnit4.class) 47 | public class AclAttributeProviderTest extends AbstractAttributeProviderTest { 48 | 49 | private static final UserPrincipal USER = createUserPrincipal("user"); 50 | private static final UserPrincipal FOO = createUserPrincipal("foo"); 51 | 52 | private static final ImmutableList defaultAcl = 53 | new ImmutableList.Builder() 54 | .add( 55 | AclEntry.newBuilder() 56 | .setType(ALLOW) 57 | .setFlags(DIRECTORY_INHERIT) 58 | .setPermissions(DELETE, APPEND_DATA) 59 | .setPrincipal(USER) 60 | .build()) 61 | .add( 62 | AclEntry.newBuilder() 63 | .setType(ALLOW) 64 | .setFlags(DIRECTORY_INHERIT) 65 | .setPermissions(DELETE, APPEND_DATA) 66 | .setPrincipal(FOO) 67 | .build()) 68 | .build(); 69 | 70 | @Override 71 | protected AclAttributeProvider createProvider() { 72 | return new AclAttributeProvider(); 73 | } 74 | 75 | @Override 76 | protected Set createInheritedProviders() { 77 | return ImmutableSet.of(new BasicAttributeProvider(), new OwnerAttributeProvider()); 78 | } 79 | 80 | @Override 81 | protected Map createDefaultValues() { 82 | return ImmutableMap.of("acl:acl", defaultAcl); 83 | } 84 | 85 | @Test 86 | public void testInitialAttributes() { 87 | assertThat(provider.get(file, "acl")).isEqualTo(defaultAcl); 88 | } 89 | 90 | @Test 91 | public void testSet() { 92 | assertSetAndGetSucceeds("acl", ImmutableList.of()); 93 | assertSetFailsOnCreate("acl", ImmutableList.of()); 94 | assertSetFails("acl", ImmutableSet.of()); 95 | assertSetFails("acl", ImmutableList.of("hello")); 96 | } 97 | 98 | @Test 99 | public void testView() throws IOException { 100 | AclFileAttributeView view = 101 | provider.view( 102 | fileLookup(), 103 | ImmutableMap.of( 104 | "owner", new OwnerAttributeProvider().view(fileLookup(), NO_INHERITED_VIEWS))); 105 | assertNotNull(view); 106 | 107 | assertThat(view.name()).isEqualTo("acl"); 108 | 109 | assertThat(view.getAcl()).isEqualTo(defaultAcl); 110 | 111 | view.setAcl(ImmutableList.of()); 112 | view.setOwner(FOO); 113 | 114 | assertThat(view.getAcl()).isEqualTo(ImmutableList.of()); 115 | assertThat(view.getOwner()).isEqualTo(FOO); 116 | 117 | assertThat(file.getAttribute("acl", "acl")).isEqualTo(ImmutableList.of()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/BasicAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import com.google.common.collect.ImmutableMap; 22 | import com.google.common.collect.ImmutableSet; 23 | import java.io.IOException; 24 | import java.nio.file.attribute.BasicFileAttributeView; 25 | import java.nio.file.attribute.BasicFileAttributes; 26 | import java.nio.file.attribute.FileTime; 27 | import java.util.Set; 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | import org.junit.runners.JUnit4; 31 | 32 | /** 33 | * Tests for {@link BasicAttributeProvider}. 34 | * 35 | * @author Colin Decker 36 | */ 37 | @RunWith(JUnit4.class) 38 | public class BasicAttributeProviderTest 39 | extends AbstractAttributeProviderTest { 40 | 41 | @Override 42 | protected BasicAttributeProvider createProvider() { 43 | return new BasicAttributeProvider(); 44 | } 45 | 46 | @Override 47 | protected Set createInheritedProviders() { 48 | return ImmutableSet.of(); 49 | } 50 | 51 | @Test 52 | public void testSupportedAttributes() { 53 | assertSupportsAll( 54 | "fileKey", 55 | "size", 56 | "isDirectory", 57 | "isRegularFile", 58 | "isSymbolicLink", 59 | "isOther", 60 | "creationTime", 61 | "lastModifiedTime", 62 | "lastAccessTime"); 63 | } 64 | 65 | @Test 66 | public void testInitialAttributes() { 67 | FileTime expected = fileTimeSource.now(); 68 | assertThat(file.getCreationTime()).isEqualTo(expected); 69 | assertThat(file.getLastAccessTime()).isEqualTo(expected); 70 | assertThat(file.getLastModifiedTime()).isEqualTo(expected); 71 | 72 | assertContainsAll( 73 | file, 74 | ImmutableMap.builder() 75 | .put("fileKey", 0) 76 | .put("size", 0L) 77 | .put("isDirectory", true) 78 | .put("isRegularFile", false) 79 | .put("isSymbolicLink", false) 80 | .put("isOther", false) 81 | .build()); 82 | } 83 | 84 | @Test 85 | public void testSet() { 86 | FileTime time = FileTime.fromMillis(0L); 87 | 88 | // settable 89 | assertSetAndGetSucceeds("creationTime", time); 90 | assertSetAndGetSucceeds("lastModifiedTime", time); 91 | assertSetAndGetSucceeds("lastAccessTime", time); 92 | 93 | // unsettable 94 | assertSetFails("fileKey", 3L); 95 | assertSetFails("size", 1L); 96 | assertSetFails("isRegularFile", true); 97 | assertSetFails("isDirectory", true); 98 | assertSetFails("isSymbolicLink", true); 99 | assertSetFails("isOther", true); 100 | 101 | // invalid type 102 | assertSetFails("creationTime", "foo"); 103 | } 104 | 105 | @Test 106 | public void testSetOnCreate() { 107 | FileTime time = FileTime.fromMillis(0L); 108 | 109 | assertSetFailsOnCreate("creationTime", time); 110 | assertSetFailsOnCreate("lastModifiedTime", time); 111 | assertSetFailsOnCreate("lastAccessTime", time); 112 | } 113 | 114 | @Test 115 | public void testView() throws IOException { 116 | BasicFileAttributeView view = provider.view(fileLookup(), NO_INHERITED_VIEWS); 117 | 118 | assertThat(view).isNotNull(); 119 | assertThat(view.name()).isEqualTo("basic"); 120 | 121 | BasicFileAttributes attrs = view.readAttributes(); 122 | assertThat(attrs.fileKey()).isEqualTo(0); 123 | 124 | FileTime initial = fileTimeSource.now(); 125 | assertThat(attrs.creationTime()).isEqualTo(initial); 126 | assertThat(attrs.lastAccessTime()).isEqualTo(initial); 127 | assertThat(attrs.lastModifiedTime()).isEqualTo(initial); 128 | 129 | view.setTimes(null, null, null); 130 | 131 | assertThat(attrs.creationTime()).isEqualTo(initial); 132 | assertThat(attrs.lastAccessTime()).isEqualTo(initial); 133 | assertThat(attrs.lastModifiedTime()).isEqualTo(initial); 134 | 135 | view.setTimes(FileTime.fromMillis(0L), null, null); 136 | 137 | attrs = view.readAttributes(); 138 | assertThat(attrs.creationTime()).isEqualTo(initial); 139 | assertThat(attrs.lastAccessTime()).isEqualTo(initial); 140 | assertThat(attrs.lastModifiedTime()).isEqualTo(FileTime.fromMillis(0L)); 141 | } 142 | 143 | @Test 144 | public void testAttributes() { 145 | BasicFileAttributes attrs = provider.readAttributes(file); 146 | assertThat(attrs.fileKey()).isEqualTo(0); 147 | assertThat(attrs.isDirectory()).isTrue(); 148 | assertThat(attrs.isRegularFile()).isFalse(); 149 | assertThat(attrs.creationTime()).isNotNull(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/BasicFileAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import java.nio.file.attribute.FileAttribute; 22 | 23 | /** @author Colin Decker */ 24 | public class BasicFileAttribute implements FileAttribute { 25 | 26 | private final String name; 27 | private final T value; 28 | 29 | public BasicFileAttribute(String name, T value) { 30 | this.name = checkNotNull(name); 31 | this.value = checkNotNull(value); 32 | } 33 | 34 | @Override 35 | public String name() { 36 | return name; 37 | } 38 | 39 | @Override 40 | public T value() { 41 | return value; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/ByteBufferChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import com.google.errorprone.annotations.CanIgnoreReturnValue; 20 | import java.io.IOException; 21 | import java.nio.ByteBuffer; 22 | import java.nio.channels.SeekableByteChannel; 23 | 24 | /** @author Colin Decker */ 25 | public class ByteBufferChannel implements SeekableByteChannel { 26 | 27 | private final ByteBuffer buffer; 28 | 29 | public ByteBufferChannel(byte[] bytes) { 30 | this.buffer = ByteBuffer.wrap(bytes); 31 | } 32 | 33 | public ByteBufferChannel(byte[] bytes, int offset, int length) { 34 | this.buffer = ByteBuffer.wrap(bytes, offset, length); 35 | } 36 | 37 | public ByteBufferChannel(int capacity) { 38 | this.buffer = ByteBuffer.allocate(capacity); 39 | } 40 | 41 | public ByteBufferChannel(ByteBuffer buffer) { 42 | this.buffer = buffer; 43 | } 44 | 45 | public ByteBuffer buffer() { 46 | return buffer; 47 | } 48 | 49 | @Override 50 | public int read(ByteBuffer dst) throws IOException { 51 | if (buffer.remaining() == 0) { 52 | return -1; 53 | } 54 | int length = Math.min(dst.remaining(), buffer.remaining()); 55 | for (int i = 0; i < length; i++) { 56 | dst.put(buffer.get()); 57 | } 58 | return length; 59 | } 60 | 61 | @Override 62 | public int write(ByteBuffer src) throws IOException { 63 | int length = Math.min(src.remaining(), buffer.remaining()); 64 | for (int i = 0; i < length; i++) { 65 | buffer.put(src.get()); 66 | } 67 | return length; 68 | } 69 | 70 | @Override 71 | public long position() throws IOException { 72 | return buffer.position(); 73 | } 74 | 75 | @Override 76 | @CanIgnoreReturnValue 77 | public SeekableByteChannel position(long newPosition) throws IOException { 78 | buffer.position((int) newPosition); 79 | return this; 80 | } 81 | 82 | @Override 83 | public long size() throws IOException { 84 | return buffer.limit(); 85 | } 86 | 87 | @Override 88 | @CanIgnoreReturnValue 89 | public SeekableByteChannel truncate(long size) throws IOException { 90 | buffer.limit((int) size); 91 | return this; 92 | } 93 | 94 | @Override 95 | public boolean isOpen() { 96 | return true; 97 | } 98 | 99 | @Override 100 | public void close() throws IOException {} 101 | } 102 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/ClassLoaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static java.nio.charset.StandardCharsets.UTF_8; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertFalse; 22 | import static org.junit.Assert.assertTrue; 23 | 24 | import com.google.common.base.MoreObjects; 25 | import com.google.common.collect.ImmutableList; 26 | import java.io.IOException; 27 | import java.lang.reflect.Method; 28 | import java.net.URLClassLoader; 29 | import java.nio.file.FileSystem; 30 | import java.nio.file.Files; 31 | import java.nio.file.Path; 32 | import java.nio.file.spi.FileSystemProvider; 33 | import java.util.List; 34 | import org.junit.Test; 35 | import org.junit.runner.RunWith; 36 | import org.junit.runners.JUnit4; 37 | 38 | /** 39 | * Tests behavior when user code loads Jimfs in a separate class loader from the system class loader 40 | * (which is what {@link FileSystemProvider#installedProviders()} uses to load {@link 41 | * FileSystemProvider}s as services from the classpath). 42 | * 43 | * @author Colin Decker 44 | */ 45 | @RunWith(JUnit4.class) 46 | public class ClassLoaderTest { 47 | 48 | @Test 49 | public void separateClassLoader() throws Exception { 50 | ClassLoader contextLoader = Thread.currentThread().getContextClassLoader(); 51 | ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); 52 | 53 | ClassLoader loader = MoreObjects.firstNonNull(contextLoader, systemLoader); 54 | 55 | if (loader instanceof URLClassLoader) { 56 | // Anything we can do if it isn't a URLClassLoader? 57 | URLClassLoader urlLoader = (URLClassLoader) loader; 58 | 59 | ClassLoader separateLoader = 60 | new URLClassLoader( 61 | urlLoader.getURLs(), systemLoader.getParent()); // either null or the boostrap loader 62 | 63 | Thread.currentThread().setContextClassLoader(separateLoader); 64 | try { 65 | Class thisClass = separateLoader.loadClass(getClass().getName()); 66 | Method createFileSystem = thisClass.getDeclaredMethod("createFileSystem"); 67 | 68 | // First, the call to Jimfs.newFileSystem in createFileSystem needs to succeed 69 | Object fs = createFileSystem.invoke(null); 70 | 71 | // Next, some sanity checks: 72 | 73 | // The file system is a JimfsFileSystem 74 | assertEquals("com.google.common.jimfs.JimfsFileSystem", fs.getClass().getName()); 75 | 76 | // But it is not seen as an instance of JimfsFileSystem here because it was loaded by a 77 | // different ClassLoader 78 | assertFalse(fs instanceof JimfsFileSystem); 79 | 80 | // But it should be an instance of FileSystem regardless, which is the important thing. 81 | assertTrue(fs instanceof FileSystem); 82 | 83 | // And normal file operations should work on it despite its provenance from a different 84 | // ClassLoader 85 | writeAndRead((FileSystem) fs, "bar.txt", "blah blah"); 86 | 87 | // And for the heck of it, test the contents of the file that was created in 88 | // createFileSystem too 89 | assertEquals( 90 | "blah", Files.readAllLines(((FileSystem) fs).getPath("foo.txt"), UTF_8).get(0)); 91 | } finally { 92 | Thread.currentThread().setContextClassLoader(contextLoader); 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * This method is really just testing that {@code Jimfs.newFileSystem()} succeeds. Without special 99 | * handling, when the system class loader loads our {@code FileSystemProvider} implementation as a 100 | * service and this code (the user code) is loaded in a separate class loader, the system-loaded 101 | * provider won't see the instance of {@code Configuration} we give it as being an instance of the 102 | * {@code Configuration} it's expecting (they're completely separate classes) and creation of the 103 | * file system will fail. 104 | */ 105 | public static FileSystem createFileSystem() throws IOException { 106 | FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); 107 | 108 | // Just some random operations to verify that basic things work on the created file system. 109 | writeAndRead(fs, "foo.txt", "blah"); 110 | 111 | return fs; 112 | } 113 | 114 | private static void writeAndRead(FileSystem fs, String path, String text) throws IOException { 115 | Path p = fs.getPath(path); 116 | Files.write(p, ImmutableList.of(text), UTF_8); 117 | List lines = Files.readAllLines(p, UTF_8); 118 | assertEquals(text, lines.get(0)); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/DosAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.assertNotNull; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import com.google.common.collect.ImmutableMap; 24 | import com.google.common.collect.ImmutableSet; 25 | import java.io.IOException; 26 | import java.nio.file.attribute.DosFileAttributeView; 27 | import java.nio.file.attribute.DosFileAttributes; 28 | import java.nio.file.attribute.FileAttributeView; 29 | import java.nio.file.attribute.FileTime; 30 | import java.util.Set; 31 | import org.junit.Test; 32 | import org.junit.runner.RunWith; 33 | import org.junit.runners.JUnit4; 34 | 35 | /** 36 | * Tests for {@link DosAttributeProvider}. 37 | * 38 | * @author Colin Decker 39 | */ 40 | @RunWith(JUnit4.class) 41 | public class DosAttributeProviderTest extends AbstractAttributeProviderTest { 42 | 43 | private static final ImmutableList DOS_ATTRIBUTES = 44 | ImmutableList.of("hidden", "archive", "readonly", "system"); 45 | 46 | @Override 47 | protected DosAttributeProvider createProvider() { 48 | return new DosAttributeProvider(); 49 | } 50 | 51 | @Override 52 | protected Set createInheritedProviders() { 53 | return ImmutableSet.of(new BasicAttributeProvider(), new OwnerAttributeProvider()); 54 | } 55 | 56 | @Test 57 | public void testInitialAttributes() { 58 | for (String attribute : DOS_ATTRIBUTES) { 59 | assertThat(provider.get(file, attribute)).isEqualTo(false); 60 | } 61 | } 62 | 63 | @Test 64 | public void testSet() { 65 | for (String attribute : DOS_ATTRIBUTES) { 66 | assertSetAndGetSucceeds(attribute, true); 67 | assertSetFailsOnCreate(attribute, true); 68 | } 69 | } 70 | 71 | @Test 72 | public void testView() throws IOException { 73 | DosFileAttributeView view = 74 | provider.view( 75 | fileLookup(), 76 | ImmutableMap.of( 77 | "basic", new BasicAttributeProvider().view(fileLookup(), NO_INHERITED_VIEWS))); 78 | assertNotNull(view); 79 | 80 | assertThat(view.name()).isEqualTo("dos"); 81 | 82 | DosFileAttributes attrs = view.readAttributes(); 83 | assertThat(attrs.isHidden()).isFalse(); 84 | assertThat(attrs.isArchive()).isFalse(); 85 | assertThat(attrs.isReadOnly()).isFalse(); 86 | assertThat(attrs.isSystem()).isFalse(); 87 | 88 | view.setArchive(true); 89 | view.setReadOnly(true); 90 | view.setHidden(true); 91 | view.setSystem(false); 92 | 93 | assertThat(attrs.isHidden()).isFalse(); 94 | assertThat(attrs.isArchive()).isFalse(); 95 | assertThat(attrs.isReadOnly()).isFalse(); 96 | 97 | attrs = view.readAttributes(); 98 | assertThat(attrs.isHidden()).isTrue(); 99 | assertThat(attrs.isArchive()).isTrue(); 100 | assertThat(attrs.isReadOnly()).isTrue(); 101 | assertThat(attrs.isSystem()).isFalse(); 102 | 103 | view.setTimes(FileTime.fromMillis(0L), null, null); 104 | assertThat(view.readAttributes().lastModifiedTime()).isEqualTo(FileTime.fromMillis(0L)); 105 | } 106 | 107 | @Test 108 | public void testAttributes() { 109 | DosFileAttributes attrs = provider.readAttributes(file); 110 | assertThat(attrs.isHidden()).isFalse(); 111 | assertThat(attrs.isArchive()).isFalse(); 112 | assertThat(attrs.isReadOnly()).isFalse(); 113 | assertThat(attrs.isSystem()).isFalse(); 114 | 115 | file.setAttribute("dos", "hidden", true); 116 | 117 | attrs = provider.readAttributes(file); 118 | assertThat(attrs.isHidden()).isTrue(); 119 | assertThat(attrs.isArchive()).isFalse(); 120 | assertThat(attrs.isReadOnly()).isFalse(); 121 | assertThat(attrs.isSystem()).isFalse(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/FakeFileTimeSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import com.google.errorprone.annotations.CanIgnoreReturnValue; 20 | import java.nio.file.attribute.FileTime; 21 | import java.time.Duration; 22 | import java.time.Instant; 23 | import java.util.Random; 24 | 25 | /** Fake implementation of {@link FileTimeSource}. */ 26 | final class FakeFileTimeSource implements FileTimeSource { 27 | 28 | private final Random random = new Random(System.currentTimeMillis()); 29 | private Instant now; 30 | 31 | FakeFileTimeSource() { 32 | randomize(); 33 | } 34 | 35 | @CanIgnoreReturnValue 36 | FakeFileTimeSource randomize() { 37 | now = 38 | Instant.ofEpochSecond( 39 | random 40 | .longs(Instant.MIN.getEpochSecond(), Instant.MAX.getEpochSecond()) 41 | .findAny() 42 | .getAsLong(), 43 | random.nextInt(1_000_000_000)); 44 | return this; 45 | } 46 | 47 | @CanIgnoreReturnValue 48 | FakeFileTimeSource advance(Duration duration) { 49 | this.now = now.plus(duration); 50 | return this; 51 | } 52 | 53 | @Override 54 | public FileTime now() { 55 | return FileTime.from(now); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/FileFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.junit.runners.JUnit4; 25 | 26 | /** 27 | * Tests for {@link FileFactory}. 28 | * 29 | * @author Colin Decker 30 | */ 31 | @RunWith(JUnit4.class) 32 | public class FileFactoryTest { 33 | 34 | private final FakeFileTimeSource fileTimeSource = new FakeFileTimeSource(); 35 | 36 | private FileFactory factory; 37 | 38 | @Before 39 | public void setUp() { 40 | factory = new FileFactory(new HeapDisk(2, 2, 0), fileTimeSource); 41 | } 42 | 43 | @Test 44 | public void testCreateFiles_basic() { 45 | File file = factory.createDirectory(); 46 | assertThat(file.id()).isEqualTo(0L); 47 | assertThat(file.isDirectory()).isTrue(); 48 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 49 | 50 | fileTimeSource.randomize(); 51 | file = factory.createRegularFile(); 52 | assertThat(file.id()).isEqualTo(1L); 53 | assertThat(file.isRegularFile()).isTrue(); 54 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 55 | 56 | fileTimeSource.randomize(); 57 | file = factory.createSymbolicLink(fakePath()); 58 | assertThat(file.id()).isEqualTo(2L); 59 | assertThat(file.isSymbolicLink()).isTrue(); 60 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 61 | } 62 | 63 | @Test 64 | public void testCreateFiles_withSupplier() { 65 | File file = factory.directoryCreator().get(); 66 | assertThat(file.id()).isEqualTo(0L); 67 | assertThat(file.isDirectory()).isTrue(); 68 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 69 | 70 | fileTimeSource.randomize(); 71 | file = factory.regularFileCreator().get(); 72 | assertThat(file.id()).isEqualTo(1L); 73 | assertThat(file.isRegularFile()).isTrue(); 74 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 75 | 76 | fileTimeSource.randomize(); 77 | file = factory.symbolicLinkCreator(fakePath()).get(); 78 | assertThat(file.id()).isEqualTo(2L); 79 | assertThat(file.isSymbolicLink()).isTrue(); 80 | assertThat(file.getCreationTime()).isEqualTo(fileTimeSource.now()); 81 | } 82 | 83 | static JimfsPath fakePath() { 84 | return PathServiceTest.fakeUnixPathService().emptyPath(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/FileSystemStateTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertFalse; 22 | import static org.junit.Assert.assertTrue; 23 | import static org.junit.Assert.fail; 24 | 25 | import com.google.common.collect.ImmutableList; 26 | import com.google.common.collect.ImmutableSet; 27 | import java.io.Closeable; 28 | import java.io.IOException; 29 | import java.nio.file.ClosedFileSystemException; 30 | import java.time.Duration; 31 | import java.util.List; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | import org.junit.runners.JUnit4; 35 | 36 | /** 37 | * Tests for {@link FileSystemState}. 38 | * 39 | * @author Colin Decker 40 | */ 41 | @RunWith(JUnit4.class) 42 | public class FileSystemStateTest { 43 | 44 | private final TestRunnable onClose = new TestRunnable(); 45 | private final FakeFileTimeSource fileTimeSource = new FakeFileTimeSource(); 46 | private final FileSystemState state = new FileSystemState(fileTimeSource, onClose); 47 | 48 | @Test 49 | public void testIsOpen() throws IOException { 50 | assertTrue(state.isOpen()); 51 | state.close(); 52 | assertFalse(state.isOpen()); 53 | } 54 | 55 | @Test 56 | public void testCheckOpen() throws IOException { 57 | state.checkOpen(); // does not throw 58 | state.close(); 59 | try { 60 | state.checkOpen(); 61 | fail(); 62 | } catch (ClosedFileSystemException expected) { 63 | } 64 | } 65 | 66 | @Test 67 | public void testNow() { 68 | assertThat(state.now()).isEqualTo(fileTimeSource.now()); 69 | fileTimeSource.advance(Duration.ofSeconds(1)); 70 | assertThat(state.now()).isEqualTo(fileTimeSource.now()); 71 | } 72 | 73 | @Test 74 | public void testClose_callsOnCloseRunnable() throws IOException { 75 | assertEquals(0, onClose.runCount); 76 | state.close(); 77 | assertEquals(1, onClose.runCount); 78 | } 79 | 80 | @Test 81 | public void testClose_multipleTimesDoNothing() throws IOException { 82 | state.close(); 83 | assertEquals(1, onClose.runCount); 84 | state.close(); 85 | state.close(); 86 | assertEquals(1, onClose.runCount); 87 | } 88 | 89 | @Test 90 | public void testClose_registeredResourceIsClosed() throws IOException { 91 | TestCloseable resource = new TestCloseable(); 92 | state.register(resource); 93 | assertFalse(resource.closed); 94 | state.close(); 95 | assertTrue(resource.closed); 96 | } 97 | 98 | @Test 99 | public void testClose_unregisteredResourceIsNotClosed() throws IOException { 100 | TestCloseable resource = new TestCloseable(); 101 | state.register(resource); 102 | assertFalse(resource.closed); 103 | state.unregister(resource); 104 | state.close(); 105 | assertFalse(resource.closed); 106 | } 107 | 108 | @Test 109 | public void testClose_multipleRegisteredResourcesAreClosed() throws IOException { 110 | List resources = 111 | ImmutableList.of(new TestCloseable(), new TestCloseable(), new TestCloseable()); 112 | for (TestCloseable resource : resources) { 113 | state.register(resource); 114 | assertFalse(resource.closed); 115 | } 116 | state.close(); 117 | for (TestCloseable resource : resources) { 118 | assertTrue(resource.closed); 119 | } 120 | } 121 | 122 | @Test 123 | public void testClose_resourcesThatThrowOnClose() { 124 | List resources = 125 | ImmutableList.of( 126 | new TestCloseable(), 127 | new ThrowsOnClose("a"), 128 | new TestCloseable(), 129 | new ThrowsOnClose("b"), 130 | new ThrowsOnClose("c"), 131 | new TestCloseable(), 132 | new TestCloseable()); 133 | for (TestCloseable resource : resources) { 134 | state.register(resource); 135 | assertFalse(resource.closed); 136 | } 137 | 138 | try { 139 | state.close(); 140 | fail(); 141 | } catch (IOException expected) { 142 | Throwable[] suppressed = expected.getSuppressed(); 143 | assertEquals(2, suppressed.length); 144 | ImmutableSet messages = 145 | ImmutableSet.of( 146 | expected.getMessage(), suppressed[0].getMessage(), suppressed[1].getMessage()); 147 | assertEquals(ImmutableSet.of("a", "b", "c"), messages); 148 | } 149 | 150 | for (TestCloseable resource : resources) { 151 | assertTrue(resource.closed); 152 | } 153 | } 154 | 155 | private static class TestCloseable implements Closeable { 156 | 157 | boolean closed = false; 158 | 159 | @Override 160 | public void close() throws IOException { 161 | closed = true; 162 | } 163 | } 164 | 165 | private static final class TestRunnable implements Runnable { 166 | int runCount = 0; 167 | 168 | @Override 169 | public void run() { 170 | runCount++; 171 | } 172 | } 173 | 174 | private static class ThrowsOnClose extends TestCloseable { 175 | 176 | private final String string; 177 | 178 | private ThrowsOnClose(String string) { 179 | this.string = string; 180 | } 181 | 182 | @Override 183 | public void close() throws IOException { 184 | super.close(); 185 | throw new IOException(string); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/FileTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.FileFactoryTest.fakePath; 20 | import static com.google.common.jimfs.TestUtils.regularFile; 21 | import static com.google.common.truth.Truth.assertThat; 22 | 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.junit.runners.JUnit4; 26 | 27 | /** 28 | * Tests for {@link File}. 29 | * 30 | * @author Colin Decker 31 | */ 32 | @RunWith(JUnit4.class) 33 | public class FileTest { 34 | 35 | private final FakeFileTimeSource fileTimeSource = new FakeFileTimeSource(); 36 | 37 | @Test 38 | public void testAttributes() { 39 | // these methods are basically just thin wrappers around a map, so no need to test too 40 | // thoroughly 41 | 42 | File file = RegularFile.create(0, fileTimeSource.now(), new HeapDisk(10, 10, 10)); 43 | 44 | assertThat(file.getAttributeKeys()).isEmpty(); 45 | assertThat(file.getAttribute("foo", "foo")).isNull(); 46 | 47 | file.deleteAttribute("foo", "foo"); // doesn't throw 48 | 49 | file.setAttribute("foo", "foo", "foo"); 50 | 51 | assertThat(file.getAttributeKeys()).containsExactly("foo:foo"); 52 | assertThat(file.getAttribute("foo", "foo")).isEqualTo("foo"); 53 | 54 | file.deleteAttribute("foo", "foo"); 55 | 56 | assertThat(file.getAttributeKeys()).isEmpty(); 57 | assertThat(file.getAttribute("foo", "foo")).isNull(); 58 | } 59 | 60 | @Test 61 | public void testFileBasics() { 62 | File file = regularFile(0); 63 | 64 | assertThat(file.id()).isEqualTo(0); 65 | assertThat(file.links()).isEqualTo(0); 66 | } 67 | 68 | @Test 69 | public void testDirectory() { 70 | File file = Directory.create(0, fileTimeSource.now()); 71 | assertThat(file.isDirectory()).isTrue(); 72 | assertThat(file.isRegularFile()).isFalse(); 73 | assertThat(file.isSymbolicLink()).isFalse(); 74 | } 75 | 76 | @Test 77 | public void testRegularFile() { 78 | File file = regularFile(10); 79 | assertThat(file.isDirectory()).isFalse(); 80 | assertThat(file.isRegularFile()).isTrue(); 81 | assertThat(file.isSymbolicLink()).isFalse(); 82 | } 83 | 84 | @Test 85 | public void testSymbolicLink() { 86 | File file = SymbolicLink.create(0, fileTimeSource.now(), fakePath()); 87 | assertThat(file.isDirectory()).isFalse(); 88 | assertThat(file.isRegularFile()).isFalse(); 89 | assertThat(file.isSymbolicLink()).isTrue(); 90 | } 91 | 92 | @Test 93 | public void testRootDirectory() { 94 | Directory file = Directory.createRoot(0, fileTimeSource.now(), Name.simple("/")); 95 | assertThat(file.isRootDirectory()).isTrue(); 96 | 97 | Directory otherFile = Directory.createRoot(1, fileTimeSource.now(), Name.simple("$")); 98 | assertThat(otherFile.isRootDirectory()).isTrue(); 99 | } 100 | 101 | @Test 102 | public void testLinkAndUnlink() { 103 | File file = regularFile(0); 104 | assertThat(file.links()).isEqualTo(0); 105 | 106 | file.incrementLinkCount(); 107 | assertThat(file.links()).isEqualTo(1); 108 | 109 | file.incrementLinkCount(); 110 | assertThat(file.links()).isEqualTo(2); 111 | 112 | file.decrementLinkCount(); 113 | assertThat(file.links()).isEqualTo(1); 114 | 115 | file.decrementLinkCount(); 116 | assertThat(file.links()).isEqualTo(0); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/NameTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.junit.runners.JUnit4; 24 | 25 | /** 26 | * Tests for {@link Name}. 27 | * 28 | * @author Colin Decker 29 | */ 30 | @RunWith(JUnit4.class) 31 | public class NameTest { 32 | 33 | @Test 34 | public void testNames() { 35 | assertThat(Name.create("foo", "foo")).isEqualTo(Name.create("foo", "foo")); 36 | assertThat(Name.create("FOO", "foo")).isEqualTo(Name.create("foo", "foo")); 37 | assertThat(Name.create("FOO", "foo")).isNotEqualTo(Name.create("FOO", "FOO")); 38 | 39 | assertThat(Name.create("a", "b").toString()).isEqualTo("a"); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/OwnerAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.UserLookupService.createUserPrincipal; 20 | import static com.google.common.truth.Truth.assertThat; 21 | 22 | import com.google.common.collect.ImmutableSet; 23 | import java.io.IOException; 24 | import java.nio.file.attribute.FileOwnerAttributeView; 25 | import java.util.Set; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.junit.runners.JUnit4; 29 | 30 | /** 31 | * Tests for {@link OwnerAttributeProvider}. 32 | * 33 | * @author Colin Decker 34 | */ 35 | @RunWith(JUnit4.class) 36 | public class OwnerAttributeProviderTest 37 | extends AbstractAttributeProviderTest { 38 | 39 | @Override 40 | protected OwnerAttributeProvider createProvider() { 41 | return new OwnerAttributeProvider(); 42 | } 43 | 44 | @Override 45 | protected Set createInheritedProviders() { 46 | return ImmutableSet.of(); 47 | } 48 | 49 | @Test 50 | public void testInitialAttributes() { 51 | assertThat(provider.get(file, "owner")).isEqualTo(createUserPrincipal("user")); 52 | } 53 | 54 | @Test 55 | public void testSet() { 56 | assertSetAndGetSucceeds("owner", createUserPrincipal("user")); 57 | assertSetFailsOnCreate("owner", createUserPrincipal("user")); 58 | 59 | // invalid type 60 | assertSetFails("owner", "root"); 61 | } 62 | 63 | @Test 64 | public void testView() throws IOException { 65 | FileOwnerAttributeView view = provider.view(fileLookup(), NO_INHERITED_VIEWS); 66 | assertThat(view).isNotNull(); 67 | 68 | assertThat(view.name()).isEqualTo("owner"); 69 | assertThat(view.getOwner()).isEqualTo(createUserPrincipal("user")); 70 | 71 | view.setOwner(createUserPrincipal("root")); 72 | assertThat(view.getOwner()).isEqualTo(createUserPrincipal("root")); 73 | assertThat(file.getAttribute("owner", "owner")).isEqualTo(createUserPrincipal("root")); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/PathTypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.Preconditions.checkArgument; 20 | import static com.google.common.truth.Truth.assertThat; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import com.google.common.jimfs.PathType.ParseResult; 24 | import java.net.URI; 25 | import org.jspecify.annotations.Nullable; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.junit.runners.JUnit4; 29 | 30 | /** 31 | * Tests for {@link PathType}. 32 | * 33 | * @author Colin Decker 34 | */ 35 | @RunWith(JUnit4.class) 36 | public class PathTypeTest { 37 | 38 | private static final FakePathType type = new FakePathType(); 39 | static final URI fileSystemUri = URI.create("jimfs://foo"); 40 | 41 | @Test 42 | public void testBasicProperties() { 43 | assertThat(type.getSeparator()).isEqualTo("/"); 44 | assertThat(type.getOtherSeparators()).isEqualTo("\\"); 45 | } 46 | 47 | @Test 48 | public void testParsePath() { 49 | ParseResult path = type.parsePath("foo/bar/baz/one\\two"); 50 | assertParseResult(path, null, "foo", "bar", "baz", "one", "two"); 51 | 52 | ParseResult path2 = type.parsePath("$one//\\two"); 53 | assertParseResult(path2, "$", "one", "two"); 54 | } 55 | 56 | @Test 57 | public void testToString() { 58 | ParseResult path = type.parsePath("foo/bar\\baz"); 59 | assertThat(type.toString(path.root(), path.names())).isEqualTo("foo/bar/baz"); 60 | 61 | ParseResult path2 = type.parsePath("$/foo/bar"); 62 | assertThat(type.toString(path2.root(), path2.names())).isEqualTo("$foo/bar"); 63 | } 64 | 65 | @Test 66 | public void testToUri() { 67 | URI fileUri = type.toUri(fileSystemUri, "$", ImmutableList.of("foo", "bar"), false); 68 | assertThat(fileUri.toString()).isEqualTo("jimfs://foo/$/foo/bar"); 69 | assertThat(fileUri.getPath()).isEqualTo("/$/foo/bar"); 70 | 71 | URI directoryUri = type.toUri(fileSystemUri, "$", ImmutableList.of("foo", "bar"), true); 72 | assertThat(directoryUri.toString()).isEqualTo("jimfs://foo/$/foo/bar/"); 73 | assertThat(directoryUri.getPath()).isEqualTo("/$/foo/bar/"); 74 | 75 | URI rootUri = type.toUri(fileSystemUri, "$", ImmutableList.of(), true); 76 | assertThat(rootUri.toString()).isEqualTo("jimfs://foo/$/"); 77 | assertThat(rootUri.getPath()).isEqualTo("/$/"); 78 | } 79 | 80 | @Test 81 | public void testToUri_escaping() { 82 | URI fileUri = type.toUri(fileSystemUri, "$", ImmutableList.of("foo", "bar baz"), false); 83 | assertThat(fileUri.toString()).isEqualTo("jimfs://foo/$/foo/bar%20baz"); 84 | assertThat(fileUri.getRawPath()).isEqualTo("/$/foo/bar%20baz"); 85 | assertThat(fileUri.getPath()).isEqualTo("/$/foo/bar baz"); 86 | } 87 | 88 | @Test 89 | public void testUriRoundTrips() { 90 | assertUriRoundTripsCorrectly(type, "$"); 91 | assertUriRoundTripsCorrectly(type, "$foo"); 92 | assertUriRoundTripsCorrectly(type, "$foo/bar/baz"); 93 | assertUriRoundTripsCorrectly(type, "$foo bar"); 94 | assertUriRoundTripsCorrectly(type, "$foo/bar baz"); 95 | } 96 | 97 | static void assertParseResult(ParseResult result, @Nullable String root, String... names) { 98 | assertThat(result.root()).isEqualTo(root); 99 | assertThat(result.names()).containsExactly((Object[]) names).inOrder(); 100 | } 101 | 102 | static void assertUriRoundTripsCorrectly(PathType type, String path) { 103 | ParseResult result = type.parsePath(path); 104 | URI uri = type.toUri(fileSystemUri, result.root(), result.names(), false); 105 | ParseResult parsedUri = type.fromUri(uri); 106 | assertThat(parsedUri.root()).isEqualTo(result.root()); 107 | assertThat(parsedUri.names()).containsExactlyElementsIn(result.names()).inOrder(); 108 | } 109 | 110 | /** Arbitrary path type with $ as the root, / as the separator and \ as an alternate separator. */ 111 | private static final class FakePathType extends PathType { 112 | 113 | protected FakePathType() { 114 | super(false, '/', '\\'); 115 | } 116 | 117 | @Override 118 | public ParseResult parsePath(String path) { 119 | String root = null; 120 | if (path.startsWith("$")) { 121 | root = "$"; 122 | path = path.substring(1); 123 | } 124 | 125 | return new ParseResult(root, splitter().split(path)); 126 | } 127 | 128 | @Override 129 | public String toString(@Nullable String root, Iterable names) { 130 | StringBuilder builder = new StringBuilder(); 131 | if (root != null) { 132 | builder.append(root); 133 | } 134 | joiner().appendTo(builder, names); 135 | return builder.toString(); 136 | } 137 | 138 | @Override 139 | public String toUriPath(String root, Iterable names, boolean directory) { 140 | StringBuilder builder = new StringBuilder(); 141 | builder.append('/').append(root); 142 | for (String name : names) { 143 | builder.append('/').append(name); 144 | } 145 | if (directory) { 146 | builder.append('/'); 147 | } 148 | return builder.toString(); 149 | } 150 | 151 | @Override 152 | public ParseResult parseUriPath(String uriPath) { 153 | checkArgument(uriPath.startsWith("/$"), "uriPath (%s) must start with /$", uriPath); 154 | return parsePath(uriPath.substring(1)); 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/PosixAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.UserLookupService.createGroupPrincipal; 20 | import static com.google.common.jimfs.UserLookupService.createUserPrincipal; 21 | import static com.google.common.truth.Truth.assertThat; 22 | import static org.junit.Assert.assertNotNull; 23 | 24 | import com.google.common.collect.ImmutableList; 25 | import com.google.common.collect.ImmutableMap; 26 | import com.google.common.collect.ImmutableSet; 27 | import java.io.IOException; 28 | import java.nio.file.attribute.PosixFileAttributeView; 29 | import java.nio.file.attribute.PosixFileAttributes; 30 | import java.nio.file.attribute.PosixFilePermission; 31 | import java.nio.file.attribute.PosixFilePermissions; 32 | import java.util.Set; 33 | import org.junit.Test; 34 | import org.junit.runner.RunWith; 35 | import org.junit.runners.JUnit4; 36 | 37 | /** 38 | * Tests for {@link PosixAttributeProvider}. 39 | * 40 | * @author Colin Decker 41 | */ 42 | @RunWith(JUnit4.class) 43 | public class PosixAttributeProviderTest 44 | extends AbstractAttributeProviderTest { 45 | 46 | @Override 47 | protected PosixAttributeProvider createProvider() { 48 | return new PosixAttributeProvider(); 49 | } 50 | 51 | @Override 52 | protected Set createInheritedProviders() { 53 | return ImmutableSet.of(new BasicAttributeProvider(), new OwnerAttributeProvider()); 54 | } 55 | 56 | @Test 57 | public void testInitialAttributes() { 58 | assertContainsAll( 59 | file, 60 | ImmutableMap.of( 61 | "group", createGroupPrincipal("group"), 62 | "permissions", PosixFilePermissions.fromString("rw-r--r--"))); 63 | } 64 | 65 | @Test 66 | public void testSet() { 67 | assertSetAndGetSucceeds("group", createGroupPrincipal("foo")); 68 | assertSetAndGetSucceeds("permissions", PosixFilePermissions.fromString("rwxrwxrwx")); 69 | 70 | // invalid types 71 | assertSetFails("permissions", ImmutableList.of(PosixFilePermission.GROUP_EXECUTE)); 72 | assertSetFails("permissions", ImmutableSet.of("foo")); 73 | } 74 | 75 | @Test 76 | public void testSetOnCreate() { 77 | assertSetAndGetSucceedsOnCreate("permissions", PosixFilePermissions.fromString("rwxrwxrwx")); 78 | assertSetFailsOnCreate("group", createGroupPrincipal("foo")); 79 | } 80 | 81 | @Test 82 | public void testView() throws IOException { 83 | file.setAttribute("owner", "owner", createUserPrincipal("user")); 84 | 85 | PosixFileAttributeView view = 86 | provider.view( 87 | fileLookup(), 88 | ImmutableMap.of( 89 | "basic", new BasicAttributeProvider().view(fileLookup(), NO_INHERITED_VIEWS), 90 | "owner", new OwnerAttributeProvider().view(fileLookup(), NO_INHERITED_VIEWS))); 91 | assertNotNull(view); 92 | 93 | assertThat(view.name()).isEqualTo("posix"); 94 | assertThat(view.getOwner()).isEqualTo(createUserPrincipal("user")); 95 | 96 | PosixFileAttributes attrs = view.readAttributes(); 97 | assertThat(attrs.fileKey()).isEqualTo(0); 98 | assertThat(attrs.owner()).isEqualTo(createUserPrincipal("user")); 99 | assertThat(attrs.group()).isEqualTo(createGroupPrincipal("group")); 100 | assertThat(attrs.permissions()).isEqualTo(PosixFilePermissions.fromString("rw-r--r--")); 101 | 102 | view.setOwner(createUserPrincipal("root")); 103 | assertThat(view.getOwner()).isEqualTo(createUserPrincipal("root")); 104 | assertThat(file.getAttribute("owner", "owner")).isEqualTo(createUserPrincipal("root")); 105 | 106 | view.setGroup(createGroupPrincipal("root")); 107 | assertThat(view.readAttributes().group()).isEqualTo(createGroupPrincipal("root")); 108 | assertThat(file.getAttribute("posix", "group")).isEqualTo(createGroupPrincipal("root")); 109 | 110 | view.setPermissions(PosixFilePermissions.fromString("rwx------")); 111 | assertThat(view.readAttributes().permissions()) 112 | .isEqualTo(PosixFilePermissions.fromString("rwx------")); 113 | assertThat(file.getAttribute("posix", "permissions")) 114 | .isEqualTo(PosixFilePermissions.fromString("rwx------")); 115 | } 116 | 117 | @Test 118 | public void testAttributes() { 119 | PosixFileAttributes attrs = provider.readAttributes(file); 120 | assertThat(attrs.permissions()).isEqualTo(PosixFilePermissions.fromString("rw-r--r--")); 121 | assertThat(attrs.group()).isEqualTo(createGroupPrincipal("group")); 122 | assertThat(attrs.fileKey()).isEqualTo(0); 123 | } 124 | 125 | @Test 126 | public void testAttributes_permissionsAreModifiable() { 127 | Set permissions = provider.readAttributes(file).permissions(); 128 | permissions.add(PosixFilePermission.OWNER_EXECUTE); 129 | assertThat(permissions).isEqualTo(PosixFilePermissions.fromString("rwxr--r--")); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/RegexGlobMatcherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import com.google.common.collect.ImmutableSet; 22 | import java.nio.file.FileSystem; 23 | import java.nio.file.FileSystems; 24 | import java.nio.file.PathMatcher; 25 | import java.util.regex.Pattern; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.junit.runners.JUnit4; 29 | 30 | /** 31 | * Tests for {@link PathMatcher} instances created by {@link GlobToRegex}. 32 | * 33 | * @author Colin Decker 34 | */ 35 | @RunWith(JUnit4.class) 36 | public class RegexGlobMatcherTest extends AbstractGlobMatcherTest { 37 | 38 | @Override 39 | protected PathMatcher matcher(String pattern) { 40 | return PathMatchers.getPathMatcher( 41 | "glob:" + pattern, "/", ImmutableSet.of()); 42 | } 43 | 44 | @Override 45 | protected PathMatcher realMatcher(String pattern) { 46 | FileSystem defaultFileSystem = FileSystems.getDefault(); 47 | if ("/".equals(defaultFileSystem.getSeparator())) { 48 | return defaultFileSystem.getPathMatcher("glob:" + pattern); 49 | } 50 | return null; 51 | } 52 | 53 | @Test 54 | public void testRegexTranslation() { 55 | assertGlobRegexIs("foo", "foo"); 56 | assertGlobRegexIs("/", "/"); 57 | assertGlobRegexIs("?", "[^/]"); 58 | assertGlobRegexIs("*", "[^/]*"); 59 | assertGlobRegexIs("**", ".*"); 60 | assertGlobRegexIs("/foo", "/foo"); 61 | assertGlobRegexIs("?oo", "[^/]oo"); 62 | assertGlobRegexIs("*oo", "[^/]*oo"); 63 | assertGlobRegexIs("**/*.java", ".*/[^/]*\\.java"); 64 | assertGlobRegexIs("[a-z]", "[[^/]&&[a-z]]"); 65 | assertGlobRegexIs("[!a-z]", "[[^/]&&[^a-z]]"); 66 | assertGlobRegexIs("[-a-z]", "[[^/]&&[-a-z]]"); 67 | assertGlobRegexIs("[!-a-z]", "[[^/]&&[^-a-z]]"); 68 | assertGlobRegexIs("{a,b,c}", "(a|b|c)"); 69 | assertGlobRegexIs("{?oo,[A-Z]*,foo/**}", "([^/]oo|[[^/]&&[A-Z]][^/]*|foo/.*)"); 70 | } 71 | 72 | @Test 73 | public void testRegexEscaping() { 74 | assertGlobRegexIs("(", "\\("); 75 | assertGlobRegexIs(".", "\\."); 76 | assertGlobRegexIs("^", "\\^"); 77 | assertGlobRegexIs("$", "\\$"); 78 | assertGlobRegexIs("+", "\\+"); 79 | assertGlobRegexIs("\\\\", "\\\\"); 80 | assertGlobRegexIs("]", "\\]"); 81 | assertGlobRegexIs(")", "\\)"); 82 | assertGlobRegexIs("}", "\\}"); 83 | } 84 | 85 | @Test 86 | public void testRegexTranslationWithMultipleSeparators() { 87 | assertGlobRegexIs("?", "[^\\\\/]", "\\/"); 88 | assertGlobRegexIs("*", "[^\\\\/]*", "\\/"); 89 | assertGlobRegexIs("/", "[\\\\/]", "\\/"); 90 | assertGlobRegexIs("\\\\", "[\\\\/]", "\\/"); 91 | } 92 | 93 | private static void assertGlobRegexIs(String glob, String regex) { 94 | assertGlobRegexIs(glob, regex, "/"); 95 | } 96 | 97 | private static void assertGlobRegexIs(String glob, String regex, String separators) { 98 | assertEquals(regex, GlobToRegex.toRegex(glob, separators)); 99 | Pattern.compile(regex); // ensure the regex syntax is valid 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/TestAttributeView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.io.IOException; 20 | import java.nio.file.attribute.BasicFileAttributeView; 21 | 22 | /** @author Colin Decker */ 23 | public interface TestAttributeView extends BasicFileAttributeView { 24 | 25 | TestAttributes readAttributes() throws IOException; 26 | 27 | void setBar(long bar) throws IOException; 28 | 29 | void setBaz(int baz) throws IOException; 30 | } 31 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/TestAttributes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import java.nio.file.attribute.BasicFileAttributes; 20 | 21 | /** @author Colin Decker */ 22 | public interface TestAttributes extends BasicFileAttributes { 23 | 24 | String foo(); 25 | 26 | long bar(); 27 | 28 | int baz(); 29 | } 30 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static java.nio.file.LinkOption.NOFOLLOW_LINKS; 20 | import static org.junit.Assert.assertFalse; 21 | 22 | import com.google.common.collect.ImmutableList; 23 | import java.io.IOException; 24 | import java.nio.ByteBuffer; 25 | import java.nio.file.DirectoryStream; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.util.ArrayList; 29 | import java.util.Arrays; 30 | import java.util.HashSet; 31 | import java.util.List; 32 | import java.util.Objects; 33 | import java.util.Set; 34 | 35 | /** @author Colin Decker */ 36 | public final class TestUtils { 37 | 38 | private TestUtils() {} 39 | 40 | public static byte[] bytes(int... bytes) { 41 | byte[] result = new byte[bytes.length]; 42 | for (int i = 0; i < bytes.length; i++) { 43 | result[i] = (byte) bytes[i]; 44 | } 45 | return result; 46 | } 47 | 48 | public static byte[] bytes(String bytes) { 49 | byte[] result = new byte[bytes.length()]; 50 | for (int i = 0; i < bytes.length(); i++) { 51 | String digit = bytes.substring(i, i + 1); 52 | result[i] = Byte.parseByte(digit); 53 | } 54 | return result; 55 | } 56 | 57 | public static byte[] preFilledBytes(int length, int fillValue) { 58 | byte[] result = new byte[length]; 59 | Arrays.fill(result, (byte) fillValue); 60 | return result; 61 | } 62 | 63 | public static byte[] preFilledBytes(int length) { 64 | byte[] bytes = new byte[length]; 65 | for (int i = 0; i < length; i++) { 66 | bytes[i] = (byte) i; 67 | } 68 | return bytes; 69 | } 70 | 71 | public static ByteBuffer buffer(String bytes) { 72 | return ByteBuffer.wrap(bytes(bytes)); 73 | } 74 | 75 | public static Iterable buffers(String... bytes) { 76 | List result = new ArrayList<>(); 77 | for (String b : bytes) { 78 | result.add(buffer(b)); 79 | } 80 | return result; 81 | } 82 | 83 | /** Returns a number of permutations of the given path that should all locate the same file. */ 84 | public static Iterable permutations(Path path) throws IOException { 85 | Path workingDir = path.getFileSystem().getPath("").toRealPath(); 86 | boolean directory = Files.isDirectory(path); 87 | 88 | Set results = new HashSet<>(); 89 | results.add(path); 90 | if (path.isAbsolute()) { 91 | results.add(workingDir.relativize(path)); 92 | } else { 93 | results.add(workingDir.resolve(path)); 94 | } 95 | if (directory) { 96 | for (Path p : ImmutableList.copyOf(results)) { 97 | results.add(p.resolve(".")); 98 | results.add(p.resolve(".").resolve(".")); 99 | Path fileName = p.getFileName(); 100 | if (fileName != null 101 | && !fileName.toString().equals(".") 102 | && !fileName.toString().equals("..")) { 103 | results.add(p.resolve("..").resolve(fileName)); 104 | results.add(p.resolve("..").resolve(".").resolve(fileName)); 105 | results.add(p.resolve("..").resolve(".").resolve(fileName).resolve(".")); 106 | results.add(p.resolve(".").resolve("..").resolve(".").resolve(fileName)); 107 | } 108 | } 109 | 110 | try (DirectoryStream stream = Files.newDirectoryStream(path)) { 111 | for (Path child : stream) { 112 | if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 113 | Path childName = child.getFileName(); 114 | for (Path p : ImmutableList.copyOf(results)) { 115 | results.add(p.resolve(childName).resolve("..")); 116 | results.add(p.resolve(childName).resolve(".").resolve(".").resolve("..")); 117 | results.add(p.resolve(childName).resolve("..").resolve(".")); 118 | results.add( 119 | p.resolve(childName).resolve("..").resolve(childName).resolve(".").resolve("..")); 120 | } 121 | break; // no need to add more than one child 122 | } 123 | } 124 | } 125 | } 126 | return results; 127 | } 128 | 129 | // equivalent to the Junit 4.11 method. 130 | public static void assertNotEquals(Object unexpected, Object actual) { 131 | assertFalse( 132 | "Values should be different. Actual: " + actual, Objects.equals(unexpected, actual)); 133 | } 134 | 135 | static RegularFile regularFile(int size) { 136 | RegularFile file = 137 | RegularFile.create(0, new FakeFileTimeSource().now(), new HeapDisk(8096, 1000, 1000)); 138 | try { 139 | file.write(0, new byte[size], 0, size); 140 | return file; 141 | } catch (IOException e) { 142 | throw new AssertionError(e); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/UnixAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.UserLookupService.createGroupPrincipal; 20 | import static com.google.common.jimfs.UserLookupService.createUserPrincipal; 21 | import static com.google.common.truth.Truth.assertThat; 22 | 23 | import com.google.common.collect.ImmutableSet; 24 | import java.nio.file.attribute.PosixFilePermissions; 25 | import java.util.Set; 26 | import org.junit.Test; 27 | import org.junit.runner.RunWith; 28 | import org.junit.runners.JUnit4; 29 | 30 | /** 31 | * Tests for {@link UnixAttributeProvider}. 32 | * 33 | * @author Colin Decker 34 | */ 35 | @RunWith(JUnit4.class) 36 | @SuppressWarnings("OctalInteger") 37 | public class UnixAttributeProviderTest 38 | extends AbstractAttributeProviderTest { 39 | 40 | @Override 41 | protected UnixAttributeProvider createProvider() { 42 | return new UnixAttributeProvider(); 43 | } 44 | 45 | @Override 46 | protected Set createInheritedProviders() { 47 | return ImmutableSet.of( 48 | new BasicAttributeProvider(), new OwnerAttributeProvider(), new PosixAttributeProvider()); 49 | } 50 | 51 | @Test 52 | public void testInitialAttributes() { 53 | // unix provider relies on other providers to set their initial attributes 54 | file.setAttribute("owner", "owner", createUserPrincipal("foo")); 55 | file.setAttribute("posix", "group", createGroupPrincipal("bar")); 56 | file.setAttribute( 57 | "posix", "permissions", ImmutableSet.copyOf(PosixFilePermissions.fromString("rw-r--r--"))); 58 | 59 | // these are pretty much meaningless here since they aren't properties this 60 | // file system actually has, so don't really care about the exact value of these 61 | assertThat(provider.get(file, "uid")).isInstanceOf(Integer.class); 62 | assertThat(provider.get(file, "gid")).isInstanceOf(Integer.class); 63 | assertThat(provider.get(file, "rdev")).isEqualTo(0L); 64 | assertThat(provider.get(file, "dev")).isEqualTo(1L); 65 | assertThat(provider.get(file, "ino")).isInstanceOf(Integer.class); 66 | 67 | // these have logical origins in attributes from other views 68 | assertThat(provider.get(file, "mode")).isEqualTo(0644); // rw-r--r-- 69 | assertThat(provider.get(file, "ctime")).isEqualTo(file.getCreationTime()); 70 | 71 | // this is based on a property this file system does actually have 72 | assertThat(provider.get(file, "nlink")).isEqualTo(1); 73 | 74 | file.incrementLinkCount(); 75 | assertThat(provider.get(file, "nlink")).isEqualTo(2); 76 | file.decrementLinkCount(); 77 | assertThat(provider.get(file, "nlink")).isEqualTo(1); 78 | } 79 | 80 | @Test 81 | public void testSet() { 82 | assertSetFails("unix:uid", 1); 83 | assertSetFails("unix:gid", 1); 84 | assertSetFails("unix:rdev", 1L); 85 | assertSetFails("unix:dev", 1L); 86 | assertSetFails("unix:ino", 1); 87 | assertSetFails("unix:mode", 1); 88 | assertSetFails("unix:ctime", 1L); 89 | assertSetFails("unix:nlink", 1); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/UnixPathTypeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.jimfs.PathTypeTest.assertParseResult; 20 | import static com.google.common.jimfs.PathTypeTest.assertUriRoundTripsCorrectly; 21 | import static com.google.common.jimfs.PathTypeTest.fileSystemUri; 22 | import static com.google.common.truth.Truth.assertThat; 23 | import static org.junit.Assert.assertEquals; 24 | import static org.junit.Assert.fail; 25 | 26 | import com.google.common.collect.ImmutableList; 27 | import java.net.URI; 28 | import java.nio.file.InvalidPathException; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.junit.runners.JUnit4; 32 | 33 | /** 34 | * Tests for {@link UnixPathType}. 35 | * 36 | * @author Colin Decker 37 | */ 38 | @RunWith(JUnit4.class) 39 | public class UnixPathTypeTest { 40 | 41 | @Test 42 | public void testUnix() { 43 | PathType unix = PathType.unix(); 44 | assertThat(unix.getSeparator()).isEqualTo("/"); 45 | assertThat(unix.getOtherSeparators()).isEqualTo(""); 46 | 47 | // "//foo/bar" is what will be passed to parsePath if "/", "foo", "bar" is passed to getPath 48 | PathType.ParseResult path = unix.parsePath("//foo/bar"); 49 | assertParseResult(path, "/", "foo", "bar"); 50 | assertThat(unix.toString(path.root(), path.names())).isEqualTo("/foo/bar"); 51 | 52 | PathType.ParseResult path2 = unix.parsePath("foo/bar/"); 53 | assertParseResult(path2, null, "foo", "bar"); 54 | assertThat(unix.toString(path2.root(), path2.names())).isEqualTo("foo/bar"); 55 | } 56 | 57 | @Test 58 | public void testUnix_toUri() { 59 | URI fileUri = PathType.unix().toUri(fileSystemUri, "/", ImmutableList.of("foo", "bar"), false); 60 | assertThat(fileUri.toString()).isEqualTo("jimfs://foo/foo/bar"); 61 | assertThat(fileUri.getPath()).isEqualTo("/foo/bar"); 62 | 63 | URI directoryUri = 64 | PathType.unix().toUri(fileSystemUri, "/", ImmutableList.of("foo", "bar"), true); 65 | assertThat(directoryUri.toString()).isEqualTo("jimfs://foo/foo/bar/"); 66 | assertThat(directoryUri.getPath()).isEqualTo("/foo/bar/"); 67 | 68 | URI rootUri = PathType.unix().toUri(fileSystemUri, "/", ImmutableList.of(), true); 69 | assertThat(rootUri.toString()).isEqualTo("jimfs://foo/"); 70 | assertThat(rootUri.getPath()).isEqualTo("/"); 71 | } 72 | 73 | @Test 74 | public void testUnix_toUri_escaping() { 75 | URI uri = PathType.unix().toUri(fileSystemUri, "/", ImmutableList.of("foo bar"), false); 76 | assertThat(uri.toString()).isEqualTo("jimfs://foo/foo%20bar"); 77 | assertThat(uri.getRawPath()).isEqualTo("/foo%20bar"); 78 | assertThat(uri.getPath()).isEqualTo("/foo bar"); 79 | } 80 | 81 | @Test 82 | public void testUnix_uriRoundTrips() { 83 | assertUriRoundTripsCorrectly(PathType.unix(), "/"); 84 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo"); 85 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo/bar/baz"); 86 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo/bar baz/one/two"); 87 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo bar"); 88 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo bar/"); 89 | assertUriRoundTripsCorrectly(PathType.unix(), "/foo bar/baz/one"); 90 | } 91 | 92 | @Test 93 | public void testUnix_illegalCharacters() { 94 | try { 95 | PathType.unix().parsePath("/foo/bar\0"); 96 | fail(); 97 | } catch (InvalidPathException expected) { 98 | assertEquals(8, expected.getIndex()); 99 | } 100 | 101 | try { 102 | PathType.unix().parsePath("/\u00001/foo"); 103 | fail(); 104 | } catch (InvalidPathException expected) { 105 | assertEquals(1, expected.getIndex()); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/UrlTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.base.StandardSystemProperty.LINE_SEPARATOR; 20 | import static com.google.common.truth.Truth.assertThat; 21 | import static java.nio.charset.StandardCharsets.UTF_8; 22 | 23 | import com.google.common.collect.ImmutableList; 24 | import com.google.common.collect.Range; 25 | import com.google.common.io.Resources; 26 | import java.io.IOException; 27 | import java.net.MalformedURLException; 28 | import java.net.URL; 29 | import java.net.URLConnection; 30 | import java.nio.file.FileSystem; 31 | import java.nio.file.Files; 32 | import java.nio.file.Path; 33 | import java.nio.file.attribute.FileTime; 34 | import org.junit.Test; 35 | import org.junit.runner.RunWith; 36 | import org.junit.runners.JUnit4; 37 | 38 | /** 39 | * Tests that {@link URL} instances can be created and used from jimfs URIs. 40 | * 41 | * @author Colin Decker 42 | */ 43 | @RunWith(JUnit4.class) 44 | public class UrlTest { 45 | 46 | private final FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); 47 | private Path path = fs.getPath("foo"); 48 | 49 | @Test 50 | public void creatUrl() throws MalformedURLException { 51 | URL url = path.toUri().toURL(); 52 | assertThat(url).isNotNull(); 53 | } 54 | 55 | @Test 56 | public void readFromUrl() throws IOException { 57 | Files.write(path, ImmutableList.of("Hello World"), UTF_8); 58 | 59 | URL url = path.toUri().toURL(); 60 | assertThat(Resources.asCharSource(url, UTF_8).read()) 61 | .isEqualTo("Hello World" + LINE_SEPARATOR.value()); 62 | } 63 | 64 | @Test 65 | public void readDirectoryContents() throws IOException { 66 | Files.createDirectory(path); 67 | Files.createFile(path.resolve("a.txt")); 68 | Files.createFile(path.resolve("b.txt")); 69 | Files.createDirectory(path.resolve("c")); 70 | 71 | URL url = path.toUri().toURL(); 72 | assertThat(Resources.asCharSource(url, UTF_8).read()).isEqualTo("a.txt\nb.txt\nc\n"); 73 | } 74 | 75 | @Test 76 | public void headers() throws IOException { 77 | byte[] bytes = {1, 2, 3}; 78 | Files.write(path, bytes); 79 | FileTime lastModified = Files.getLastModifiedTime(path); 80 | 81 | URL url = path.toUri().toURL(); 82 | URLConnection conn = url.openConnection(); 83 | 84 | // read header fields directly 85 | assertThat(conn.getHeaderFields()).containsEntry("content-length", ImmutableList.of("3")); 86 | assertThat(conn.getHeaderFields()) 87 | .containsEntry("content-type", ImmutableList.of("application/octet-stream")); 88 | 89 | if (lastModified != null) { 90 | assertThat(conn.getHeaderFields()).containsKey("last-modified"); 91 | assertThat(conn.getHeaderFields()).hasSize(3); 92 | } else { 93 | assertThat(conn.getHeaderFields()).hasSize(2); 94 | } 95 | 96 | // use the specific methods for reading the expected headers 97 | assertThat(conn.getContentLengthLong()).isEqualTo(Files.size(path)); 98 | assertThat(conn.getContentType()).isEqualTo("application/octet-stream"); 99 | 100 | if (lastModified != null) { 101 | // The HTTP date format does not include milliseconds, which means that the last modified time 102 | // returned from the connection may not be exactly the same as that of the file system itself. 103 | // The difference should less than 1000ms though, and should never be greater. 104 | long difference = lastModified.toMillis() - conn.getLastModified(); 105 | assertThat(difference).isIn(Range.closedOpen(0L, 1000L)); 106 | } else { 107 | assertThat(conn.getLastModified()).isEqualTo(0L); 108 | } 109 | } 110 | 111 | @Test 112 | public void contentType() throws IOException { 113 | path = fs.getPath("foo.txt"); 114 | Files.write(path, ImmutableList.of("Hello World"), UTF_8); 115 | 116 | URL url = path.toUri().toURL(); 117 | URLConnection conn = url.openConnection(); 118 | 119 | // Should be text/plain, but this is entirely dependent on the installed FileTypeDetectors 120 | String detectedContentType = Files.probeContentType(path); 121 | if (detectedContentType == null) { 122 | assertThat(conn.getContentType()).isEqualTo("application/octet-stream"); 123 | } else { 124 | assertThat(conn.getContentType()).isEqualTo(detectedContentType); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/UserDefinedAttributeProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.assertNotNull; 21 | import static org.junit.Assert.fail; 22 | 23 | import com.google.common.collect.ImmutableList; 24 | import com.google.common.collect.ImmutableSet; 25 | import java.io.IOException; 26 | import java.nio.ByteBuffer; 27 | import java.nio.file.attribute.UserDefinedFileAttributeView; 28 | import java.util.Arrays; 29 | import java.util.Set; 30 | import org.junit.Test; 31 | import org.junit.runner.RunWith; 32 | import org.junit.runners.JUnit4; 33 | 34 | /** 35 | * Tests for {@link UserDefinedAttributeProvider}. 36 | * 37 | * @author Colin Decker 38 | */ 39 | @RunWith(JUnit4.class) 40 | public class UserDefinedAttributeProviderTest 41 | extends AbstractAttributeProviderTest { 42 | 43 | @Override 44 | protected UserDefinedAttributeProvider createProvider() { 45 | return new UserDefinedAttributeProvider(); 46 | } 47 | 48 | @Override 49 | protected Set createInheritedProviders() { 50 | return ImmutableSet.of(); 51 | } 52 | 53 | @Test 54 | public void testInitialAttributes() { 55 | // no initial attributes 56 | assertThat(ImmutableList.copyOf(file.getAttributeKeys())).isEmpty(); 57 | assertThat(provider.attributes(file)).isEmpty(); 58 | } 59 | 60 | @Test 61 | public void testGettingAndSetting() { 62 | byte[] bytes = {0, 1, 2, 3}; 63 | provider.set(file, "user", "one", bytes, false); 64 | provider.set(file, "user", "two", ByteBuffer.wrap(bytes), false); 65 | 66 | byte[] one = (byte[]) provider.get(file, "one"); 67 | byte[] two = (byte[]) provider.get(file, "two"); 68 | assertThat(Arrays.equals(one, bytes)).isTrue(); 69 | assertThat(Arrays.equals(two, bytes)).isTrue(); 70 | 71 | assertSetFails("foo", "hello"); 72 | 73 | assertThat(provider.attributes(file)).containsExactly("one", "two"); 74 | } 75 | 76 | @Test 77 | public void testSetOnCreate() { 78 | assertSetFailsOnCreate("anything", new byte[0]); 79 | } 80 | 81 | @Test 82 | public void testView() throws IOException { 83 | UserDefinedFileAttributeView view = provider.view(fileLookup(), NO_INHERITED_VIEWS); 84 | assertNotNull(view); 85 | 86 | assertThat(view.name()).isEqualTo("user"); 87 | assertThat(view.list()).isEmpty(); 88 | 89 | byte[] b1 = {0, 1, 2}; 90 | byte[] b2 = {0, 1, 2, 3, 4}; 91 | 92 | view.write("b1", ByteBuffer.wrap(b1)); 93 | view.write("b2", ByteBuffer.wrap(b2)); 94 | 95 | assertThat(view.list()).containsAtLeast("b1", "b2"); 96 | assertThat(file.getAttributeKeys()).containsExactly("user:b1", "user:b2"); 97 | 98 | assertThat(view.size("b1")).isEqualTo(3); 99 | assertThat(view.size("b2")).isEqualTo(5); 100 | 101 | ByteBuffer buf1 = ByteBuffer.allocate(view.size("b1")); 102 | ByteBuffer buf2 = ByteBuffer.allocate(view.size("b2")); 103 | 104 | view.read("b1", buf1); 105 | view.read("b2", buf2); 106 | 107 | assertThat(Arrays.equals(b1, buf1.array())).isTrue(); 108 | assertThat(Arrays.equals(b2, buf2.array())).isTrue(); 109 | 110 | view.delete("b2"); 111 | 112 | assertThat(view.list()).containsExactly("b1"); 113 | assertThat(file.getAttributeKeys()).containsExactly("user:b1"); 114 | 115 | try { 116 | view.size("b2"); 117 | fail(); 118 | } catch (IllegalArgumentException expected) { 119 | assertThat(expected.getMessage()).contains("not set"); 120 | } 121 | 122 | try { 123 | view.read("b2", ByteBuffer.allocate(10)); 124 | fail(); 125 | } catch (IllegalArgumentException expected) { 126 | assertThat(expected.getMessage()).contains("not set"); 127 | } 128 | 129 | view.write("b1", ByteBuffer.wrap(b2)); 130 | assertThat(view.size("b1")).isEqualTo(5); 131 | 132 | view.delete("b2"); // succeeds 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/UserLookupServiceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static org.junit.Assert.fail; 21 | 22 | import java.io.IOException; 23 | import java.nio.file.attribute.GroupPrincipal; 24 | import java.nio.file.attribute.UserPrincipal; 25 | import java.nio.file.attribute.UserPrincipalLookupService; 26 | import java.nio.file.attribute.UserPrincipalNotFoundException; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.junit.runners.JUnit4; 30 | 31 | /** 32 | * Tests for {@link UserLookupService}. 33 | * 34 | * @author Colin Decker 35 | */ 36 | @RunWith(JUnit4.class) 37 | public class UserLookupServiceTest { 38 | 39 | @Test 40 | public void testUserLookupService() throws IOException { 41 | UserPrincipalLookupService service = new UserLookupService(true); 42 | UserPrincipal bob1 = service.lookupPrincipalByName("bob"); 43 | UserPrincipal bob2 = service.lookupPrincipalByName("bob"); 44 | UserPrincipal alice = service.lookupPrincipalByName("alice"); 45 | 46 | assertThat(bob1).isEqualTo(bob2); 47 | assertThat(bob1).isNotEqualTo(alice); 48 | 49 | GroupPrincipal group1 = service.lookupPrincipalByGroupName("group"); 50 | GroupPrincipal group2 = service.lookupPrincipalByGroupName("group"); 51 | GroupPrincipal foo = service.lookupPrincipalByGroupName("foo"); 52 | 53 | assertThat(group1).isEqualTo(group2); 54 | assertThat(group1).isNotEqualTo(foo); 55 | } 56 | 57 | @Test 58 | public void testServiceNotSupportingGroups() throws IOException { 59 | UserPrincipalLookupService service = new UserLookupService(false); 60 | 61 | try { 62 | service.lookupPrincipalByGroupName("group"); 63 | fail(); 64 | } catch (UserPrincipalNotFoundException expected) { 65 | assertThat(expected.getName()).isEqualTo("group"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /jimfs/src/test/java/com/google/common/jimfs/WatchServiceConfigurationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.common.jimfs; 18 | 19 | import static com.google.common.truth.Truth.assertThat; 20 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 21 | import static java.util.concurrent.TimeUnit.SECONDS; 22 | 23 | import java.io.IOException; 24 | import java.nio.file.WatchService; 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.junit.runners.JUnit4; 30 | 31 | /** 32 | * Tests for {@link WatchServiceConfiguration}. 33 | * 34 | * @author Colin Decker 35 | */ 36 | @RunWith(JUnit4.class) 37 | public class WatchServiceConfigurationTest { 38 | 39 | private JimfsFileSystem fs; 40 | 41 | @Before 42 | public void setUp() { 43 | // kind of putting the cart before the horse maybe, but it's the easiest way to get valid 44 | // instances of both a FileSystemView and a PathService 45 | fs = (JimfsFileSystem) Jimfs.newFileSystem(); 46 | } 47 | 48 | @After 49 | public void tearDown() throws IOException { 50 | fs.close(); 51 | fs = null; 52 | } 53 | 54 | @Test 55 | public void testPollingConfig() { 56 | WatchServiceConfiguration polling = WatchServiceConfiguration.polling(50, MILLISECONDS); 57 | WatchService watchService = polling.newWatchService(fs.getDefaultView(), fs.getPathService()); 58 | assertThat(watchService).isInstanceOf(PollingWatchService.class); 59 | 60 | PollingWatchService pollingWatchService = (PollingWatchService) watchService; 61 | assertThat(pollingWatchService.interval).isEqualTo(50); 62 | assertThat(pollingWatchService.timeUnit).isEqualTo(MILLISECONDS); 63 | } 64 | 65 | @Test 66 | public void testDefaultConfig() { 67 | WatchService watchService = 68 | WatchServiceConfiguration.DEFAULT.newWatchService(fs.getDefaultView(), fs.getPathService()); 69 | assertThat(watchService).isInstanceOf(PollingWatchService.class); 70 | 71 | PollingWatchService pollingWatchService = (PollingWatchService) watchService; 72 | assertThat(pollingWatchService.interval).isEqualTo(5); 73 | assertThat(pollingWatchService.timeUnit).isEqualTo(SECONDS); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /util/update_snapshot_docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | echo -e "Publishing docs...\n" 6 | 7 | GH_PAGES_DIR="$HOME/gh-pages" 8 | 9 | git clone --quiet --branch=gh-pages https://x-access-token:${GITHUB_TOKEN}@github.com/google/jimfs.git $GH_PAGES_DIR > /dev/null 10 | 11 | cd $GH_PAGES_DIR 12 | 13 | git config --global user.name "$GITHUB_ACTOR" 14 | git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" 15 | 16 | ./updaterelease.sh snapshot 17 | 18 | git push -fq origin gh-pages > /dev/null 19 | 20 | echo -e "Published docs to gh-pages.\n" 21 | --------------------------------------------------------------------------------