From f0a7a18efb5118a001e04c150a8c2913f32f28bb Mon Sep 17 00:00:00 2001 From: Vladimir Lagunov Date: Fri, 7 Feb 2025 18:40:51 +0100 Subject: [PATCH] IJPL-175521 Eel FS: MultiRoutingFileSystemProvider.newFileSystem throws UnsupportedOperationException There are backends for opening archives as NIO filesystems. `java.nio.file.FileSystems.newFileSystem` iterates over backends and returns the filesystem from the first backend that doesn't throw an `UnsupportedOperationException`. `FileSystems.newFileSystem` always tries the default file system provider the first. Before this commit, `FileSystems.newFileSystem` returned an instance of `MultiRoutingFileSystem` for ZIP files, while it was supposed to return `jdk.nio.zipfs.ZipFileSystem`. Now `MultiRoutingFileSystemProvider.newFileSystem` throws UOE, just like `WindowsFileSystemProvider` and `UnixFileSystemProvider`. GitOrigin-RevId: cb18db3d5d02060fc550a1b509b215b181ec6efc --- .../fs/MultiRoutingFileSystemProvider.java | 17 +++-- .../impl/nio/IjentNioFileSystemProvider.kt | 76 +++++++++---------- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/MultiRoutingFileSystemProvider.java b/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/MultiRoutingFileSystemProvider.java index 1b14cb118ae1..4c859d1eebd1 100644 --- a/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/MultiRoutingFileSystemProvider.java +++ b/platform/core-nio-fs/src/com/intellij/platform/core/nio/fs/MultiRoutingFileSystemProvider.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.core.nio.fs; import org.jetbrains.annotations.Contract; @@ -14,6 +14,7 @@ import java.nio.file.FileSystem; import java.nio.file.Path; import java.nio.file.spi.FileSystemProvider; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.BiFunction; /** @@ -77,6 +78,7 @@ public final class MultiRoutingFileSystemProvider ) { if (provider.getClass().getName().equals(MultiRoutingFileSystemProvider.class.getName())) { Map arguments = new HashMap<>(); + arguments.put(KEY_MRFS, Void.TYPE); arguments.put(KEY_ROOT, root); arguments.put(KEY_PREFIX, isPrefix); arguments.put(KEY_CASE_SENSITIVE, caseSensitive); @@ -106,14 +108,18 @@ public final class MultiRoutingFileSystemProvider } @Override - public @NotNull MultiRoutingFileSystem newFileSystem(Path path, Map env) { - return getFileSystem(path.toUri()); + public @Nullable MultiRoutingFileSystem newFileSystem(Path path, @Nullable Map env) { + throw new UnsupportedOperationException(MultiRoutingFileSystemProvider.class.getName() + " doesn't open other files as filesystems"); } @Override public @Nullable MultiRoutingFileSystem newFileSystem(URI uri, @Nullable Map env) { - if (env == null) { - return getFileSystem(uri); + if (env == null || !env.containsKey(KEY_MRFS)) { + throw new UnsupportedOperationException( + MultiRoutingFileSystem.class.getName() + " can be created only with `" + + MultiRoutingFileSystemProvider.class.getName() + ".computeBackend()`." + + " Otherwise, this file system provider behaves as a default file system provider and throws an error." + ); } String root = Objects.requireNonNull((String)env.get(KEY_ROOT)); @@ -128,6 +134,7 @@ public final class MultiRoutingFileSystemProvider return null; } + private static final String KEY_MRFS = "MRFS." + ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE); private static final String KEY_ROOT = "KEY_ROOT"; private static final String KEY_PREFIX = "KEY_PREFIX"; private static final String KEY_CASE_SENSITIVE = "KEY_CASE_SENSITIVE"; diff --git a/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt b/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt index ad1a76b29bed..283f36c10f4f 100644 --- a/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt +++ b/platform/ijent/impl/src/com/intellij/platform/ijent/community/impl/nio/IjentNioFileSystemProvider.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.ijent.community.impl.nio import com.intellij.openapi.diagnostic.thisLogger @@ -73,7 +73,13 @@ class IjentNioFileSystemProvider : FileSystemProvider() { override fun newFileSystem(uri: URI, env: MutableMap): IjentNioFileSystem { @Suppress("NAME_SHADOWING") val uri = uri.normalize() - typicalUriChecks(uri) + if (uri.authority.isNullOrEmpty() + || uri.scheme != this.scheme + || !uri.query.isNullOrEmpty() + || !uri.fragment.isNullOrEmpty()) { + throw UnsupportedOperationException(uri.toString() + " doesn't look like a proper URL for " + IjentNioFileSystemProvider::class.simpleName) + } + val ijentFs = try { env[KEY_IJENT_FS] as IjentFileSystemApi @@ -496,35 +502,35 @@ class IjentNioFileSystemProvider : FileSystemProvider() { val oldPermissions = (readAttributes(path, PosixFileAttributes::class.java, *options) as IjentNioPosixFileAttributes).fileInfo.permissions builder.permissions(when (requestedAttributes.singleOrNull()) { - "permissions" -> { - value as Set<*> // ClassCastException is expected - @Suppress("UNCHECKED_CAST") val mask = PosixFilePermissionsUtil.toUnixMode(value as Set) - EelPosixFileInfoImpl.Permissions(oldPermissions.owner, oldPermissions.group, mask) - } - "owner" -> { - if (value is EelPosixUserPrincipal) { - if (value.uid != oldPermissions.owner) { - TODO("Changing uid is not supported yet") - } - oldPermissions - } - else { - throw UnsupportedOperationException("Unsupported owner principal: $value") - } - } - "group" -> { - if (value is EelPosixGroupPrincipal) { - if (value.gid != oldPermissions.group) { - TODO("Changing gid is not supported yet") - } - oldPermissions - } - else { - throw java.lang.UnsupportedOperationException("Unsupported group principal: $value") - } - } - else -> throw IllegalArgumentException("Unrecognized attribute: $attribute") - }) + "permissions" -> { + value as Set<*> // ClassCastException is expected + @Suppress("UNCHECKED_CAST") val mask = PosixFilePermissionsUtil.toUnixMode(value as Set) + EelPosixFileInfoImpl.Permissions(oldPermissions.owner, oldPermissions.group, mask) + } + "owner" -> { + if (value is EelPosixUserPrincipal) { + if (value.uid != oldPermissions.owner) { + TODO("Changing uid is not supported yet") + } + oldPermissions + } + else { + throw UnsupportedOperationException("Unsupported owner principal: $value") + } + } + "group" -> { + if (value is EelPosixGroupPrincipal) { + if (value.gid != oldPermissions.group) { + TODO("Changing gid is not supported yet") + } + oldPermissions + } + else { + throw java.lang.UnsupportedOperationException("Unsupported group principal: $value") + } + } + else -> throw IllegalArgumentException("Unrecognized attribute: $attribute") + }) } else -> throw java.lang.IllegalArgumentException("Unrecognized attribute: $attribute") } @@ -625,14 +631,6 @@ class IjentNioFileSystemProvider : FileSystemProvider() { return path } - - private fun typicalUriChecks(uri: URI) { - require(uri.authority.isNotEmpty()) - - require(uri.scheme == scheme) { "${uri.scheme} != $scheme" } - require(uri.query.isNullOrEmpty()) { uri.query } - require(uri.fragment.isNullOrEmpty()) { uri.fragment } - } }