From 104946b96231f9227c57fda943e04fc3a6a47a77 Mon Sep 17 00:00:00 2001 From: Vladimir Lagunov Date: Mon, 10 Nov 2025 15:12:35 +0100 Subject: [PATCH] IJPL-217737 IJent: Posix-to-DOS FileAttributeView adapter GitOrigin-RevId: de5c63d4a310ba3ef225f3dfba70e7758f5d2b71 --- .../nio/IjentWslNioFileSystemProvider.kt | 5 +- ...entNioPosixFileAttributesWithDosAdapter.kt | 84 ++++++++++++++++++- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/eel/src/com/intellij/platform/ide/impl/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt b/platform/platform-impl/eel/src/com/intellij/platform/ide/impl/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt index 96e95d61a443..59aa24b4a587 100644 --- a/platform/platform-impl/eel/src/com/intellij/platform/ide/impl/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt +++ b/platform/platform-impl/eel/src/com/intellij/platform/ide/impl/wsl/ijent/nio/IjentWslNioFileSystemProvider.kt @@ -2,6 +2,7 @@ package com.intellij.platform.ide.impl.wsl.ijent.nio import com.intellij.execution.ijent.nio.getCachedFileAttributesAndWrapToDosAttributesAdapter +import com.intellij.execution.ijent.nio.getFileAttributeViewUsingDosAttributesAdapter import com.intellij.execution.ijent.nio.readAttributesUsingDosAttributesAdapter import com.intellij.execution.wsl.WslDistributionManager import com.intellij.execution.wsl.WslPath @@ -302,8 +303,8 @@ class IjentWslNioFileSystemProvider( override fun getFileStore(path: Path): FileStore = ijentFsProvider.getFileStore(path.toIjentPath()) - override fun getFileAttributeView(path: Path, type: Class, vararg options: LinkOption): V = - ijentFsProvider.getFileAttributeView(path.toIjentPath(), type, *options) + override fun getFileAttributeView(path: Path, type: Class, vararg options: LinkOption): V = + ijentFsProvider.getFileAttributeViewUsingDosAttributesAdapter(path.toIjentPath(), type, *options) override fun readAttributes(path: Path, type: Class, vararg options: LinkOption): A { return ijentFsProvider.readAttributesUsingDosAttributesAdapter(path, path.toIjentPath(), type, *options) diff --git a/platform/platform-impl/src/com/intellij/execution/ijent/nio/IjentNioPosixFileAttributesWithDosAdapter.kt b/platform/platform-impl/src/com/intellij/execution/ijent/nio/IjentNioPosixFileAttributesWithDosAdapter.kt index e3501eaa28a4..ca8f06dad7c2 100644 --- a/platform/platform-impl/src/com/intellij/execution/ijent/nio/IjentNioPosixFileAttributesWithDosAdapter.kt +++ b/platform/platform-impl/src/com/intellij/execution/ijent/nio/IjentNioPosixFileAttributesWithDosAdapter.kt @@ -12,9 +12,7 @@ import com.intellij.platform.ijent.community.impl.nio.IjentNioPosixFileAttribute import org.jetbrains.annotations.ApiStatus import java.nio.file.LinkOption import java.nio.file.Path -import java.nio.file.attribute.BasicFileAttributes -import java.nio.file.attribute.DosFileAttributes -import java.nio.file.attribute.PosixFileAttributes +import java.nio.file.attribute.* import java.nio.file.attribute.PosixFilePermission.* import java.nio.file.spi.FileSystemProvider import kotlin.io.path.name @@ -111,4 +109,84 @@ class IjentNioPosixFileAttributesWithDosAdapter( override fun getCaseSensitivity(): FileAttributes.CaseSensitivity { if (fileInfo is CaseSensitivityAttribute) return fileInfo.caseSensitivity else return FileAttributes.CaseSensitivity.UNKNOWN } +} + +@ApiStatus.Internal +class IjentNioPosixFileAttributeViewWithDosAdapter( + private val userInfo: EelUserPosixInfo, + private val posixView: PosixFileAttributeView, + private val nameStartsWithDot: Boolean, +) : PosixFileAttributeView by posixView, DosFileAttributeView { + override fun readAttributes(): IjentNioPosixFileAttributesWithDosAdapter = + IjentNioPosixFileAttributesWithDosAdapter(userInfo, posixView.readAttributes(), nameStartsWithDot) + + override fun setReadOnly(readOnly: Boolean) { + val permissions: MutableSet = posixView.readAttributes().permissions() + + // "Read-only" implies "readable", "not read-only" implies "not only readable". In any case, the resource is supposed to be readable. + permissions += OWNER_READ + + if (readOnly) { + permissions -= OWNER_WRITE + permissions -= GROUP_WRITE + permissions -= OTHERS_WRITE + } + else { + // Windows has a complicated ACL for every file, but this option refers to the old DOS attribute. + // MS DOS was not a multi-user operating system, but Posix systems are. + // The dilemma is in how to treat the request to setting the read-only attribute as false: + // make the file readable for everyone or only for the owner. + // This code explicitly sets only for the user because in the worst but rare scenario it leads to non-functioning features, + // but too broad permissions can hypothetically lead to a security issue. + permissions += OWNER_WRITE + } + + posixView.setPermissions(permissions) + } + + override fun setHidden(value: Boolean) { + // There's no such conception as a hidden file in terms of the Posix filesystem, + // but there's a tradition to treat all files starting from `.` as hidden. + // + // File renaming is certainly something that the caller of `DosFileAttribute.setHidden` does not expect. + // Throwing an error might have been possible if this implementation was introduced for new code, + // but it is here to support unknown legacy code. + // + // Lastly, it might be worth using extended attributes like `sun.nio.fs.LinuxDosFileAttributeView` does, + // but it's usually unexpected, it's not supported on macOS, and also it requires efforts for implementing. + // Reference: https://github.com/JetBrains/JetBrainsRuntime/blob/922b12f30c4cfd6b504d66daf37fb30c7fb1bfe7/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java + // + // Thus, it's better to do nothing in this method. + } + + override fun setSystem(value: Boolean) { + // There's no such conception as a "system file" in Posix, though it might be implemented like in `sun.nio.fs.LinuxDosFileAttributeView` + } + + override fun setArchive(value: Boolean) { + // There's no such conception as a "system file" in Posix, though it might be implemented like in `sun.nio.fs.LinuxDosFileAttributeView` + } +} + +@ApiStatus.Internal +fun FileSystemProvider.getFileAttributeViewUsingDosAttributesAdapter( + ijentPath: IjentNioPath, + type: Class, + vararg options: LinkOption, +): V { + val actualType = when { + DosFileAttributeView::class.java.isAssignableFrom(type) -> PosixFileAttributeView::class.java + else -> type + } + + val resultAttrs = when (val actualView = getFileAttributeView(ijentPath, actualType, *options)) { + is PosixFileAttributeView -> IjentNioPosixFileAttributeViewWithDosAdapter( + userInfo = ijentPath.fileSystem.ijentFs.user as EelUserPosixInfo, + posixView = actualView, + nameStartsWithDot = ijentPath.name.startsWith("."), + ) + else -> actualView + } + + return type.cast(resultAttrs) } \ No newline at end of file