diff --git a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java index 47183181..8f923c50 100644 --- a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java +++ b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystem.java @@ -64,9 +64,11 @@ public final class CloudStorageFileSystem extends FileSystem { public static final String URI_SCHEME = "gs"; public static final String GCS_VIEW = "gcs"; public static final String BASIC_VIEW = "basic"; + public static final String POSIX_VIEW = "posix"; public static final int BLOCK_SIZE_DEFAULT = 2 * 1024 * 1024; public static final FileTime FILE_TIME_UNKNOWN = FileTime.fromMillis(0); - public static final Set SUPPORTED_VIEWS = ImmutableSet.of(BASIC_VIEW, GCS_VIEW); + public static final Set SUPPORTED_VIEWS = + ImmutableSet.of(BASIC_VIEW, GCS_VIEW, POSIX_VIEW); private final CloudStorageFileSystemProvider provider; private final String bucket; private final CloudStorageConfiguration config; diff --git a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java index 413f1172..bba5d875 100644 --- a/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java +++ b/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProvider.java @@ -19,6 +19,12 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.isNullOrEmpty; +import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE; +import static java.nio.file.attribute.PosixFilePermission.GROUP_READ; +import static java.nio.file.attribute.PosixFilePermission.GROUP_WRITE; +import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE; +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; import com.google.api.gax.paging.Page; import com.google.cloud.storage.Acl; @@ -62,10 +68,13 @@ import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.GroupPrincipal; +import java.nio.file.attribute.UserPrincipal; import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -852,7 +861,7 @@ public Map readAttributes(Path path, String attributes, LinkOpti // (eg. BasicFileAttributeView and PosixFileAttributeView), so rather than a partial // implementation we rely on the other overload for now. - // Partial implementation for a few commonly used ones: basic, gcs + // Partial implementation for a few commonly used ones: basic, gcs, posix String[] split = attributes.split(":", 2); if (split.length != 2) { throw new UnsupportedOperationException(); @@ -868,6 +877,9 @@ public Map readAttributes(Path path, String attributes, LinkOpti case "gcs": fileAttributes = readAttributes(path, CloudStorageFileAttributes.class, options); break; + case "posix": + // There is no real support for posix. + // Some systems expect Posix support for everything so these attributes are faked. case "basic": fileAttributes = readAttributes(path, BasicFileAttributes.class, options); break; @@ -905,6 +917,53 @@ public Map readAttributes(Path path, String attributes, LinkOpti results.put("size", fileAttributes.size()); } + // There is no real support for posix. + // Some systems fail if there is no posix support at all. + // To let these systems use this FileSystem these attributes are faked. + if (view.equals("posix")) { + if (allAttributes || attributeNames.contains("owner")) { + results.put( + "owner", + new UserPrincipal() { + @Override + public String getName() { + return "fakeowner"; + } + + @Override + public String toString() { + return "fakeowner"; + } + }); + } + if (allAttributes || attributeNames.contains("group")) { + results.put( + "group", + new GroupPrincipal() { + @Override + public String getName() { + return "fakegroup"; + } + + @Override + public String toString() { + return "fakegroup"; + } + }); + } + if (allAttributes || attributeNames.contains("permissions")) { + if (fileAttributes.isRegularFile()) { + results.put("permissions", EnumSet.of(OWNER_READ, OWNER_WRITE, GROUP_READ, GROUP_WRITE)); + } else { + // Directories, Symlinks and Other: + results.put( + "permissions", + EnumSet.of( + OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE)); + } + } + } + // CloudStorageFileAttributes if (fileAttributes instanceof CloudStorageFileAttributes) { CloudStorageFileAttributes cloudStorageFileAttributes = diff --git a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java index 4bc004e4..f44a932c 100644 --- a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java +++ b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemProviderTest.java @@ -59,6 +59,8 @@ import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.GroupPrincipal; +import java.nio.file.attribute.UserPrincipal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -906,7 +908,51 @@ public void testReadAttributes() throws IOException { assertEquals( expectedSpecific, fileSystemProvider.readAttributes( - path1, "basic:lastModifiedTime,isSymbolicLink,isOther,etag,cacheControl")); + path1, "basic:lastModifiedTime,isSymbolicLink,isOther,etag,cacheControl,owner,group")); + + // Add the attributes that are only known in posix view + // These are all fake values + expectedSpecific.put( + "owner", + new UserPrincipal() { + @Override + public String getName() { + return "fakeowner"; + } + + @Override + public String toString() { + return "fakeowner"; + } + }); + + expectedSpecific.put( + "group", + new GroupPrincipal() { + @Override + public String getName() { + return "fakegroup"; + } + + @Override + public String toString() { + return "fakegroup"; + } + }); + + // The equals between two anonymous classes (the UserPrincipal and GroupPrincipal) is always + // false + // so we compare the toString() instead. + assertEquals( + expectedSpecific.toString(), + fileSystemProvider + .readAttributes( + path1, + "posix:lastModifiedTime,isSymbolicLink,isOther,etag,cacheControl,owner,group") + .toString()); + + expectedSpecific.remove("owner"); + expectedSpecific.remove("group"); // Add the attributes that are only known in gcs view expectedSpecific.put("etag", Optional.of("TheEtag")); @@ -915,7 +961,7 @@ public void testReadAttributes() throws IOException { assertEquals( expectedSpecific, fileSystemProvider.readAttributes( - path1, "gcs:lastModifiedTime,isSymbolicLink,isOther,etag,cacheControl")); + path1, "gcs:lastModifiedTime,isSymbolicLink,isOther,etag,cacheControl,owner,group")); } private static CloudStorageConfiguration permitEmptyPathComponents(boolean value) { diff --git a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java index 57d698b9..4033e788 100644 --- a/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java +++ b/google-cloud-nio/src/test/java/com/google/cloud/storage/contrib/nio/CloudStorageFileSystemTest.java @@ -179,7 +179,7 @@ public void testGetters() throws IOException { assertThat(fs.getRootDirectories()).containsExactly(fs.getPath("/")); assertThat(fs.getFileStores()).isEmpty(); assertThat(fs.getSeparator()).isEqualTo("/"); - assertThat(fs.supportedFileAttributeViews()).containsExactly("basic", "gcs"); + assertThat(fs.supportedFileAttributeViews()).containsExactly("basic", "gcs", "posix"); } }