IJent: fix bugs related to moving files and replace_existing flag

* By default, NIO filesystem must not replace existing files, but it used to do so, and it wasn't possible to disable replacing.
* After adding the ability to not replace existing files on the client side, a bug was found on the server side: IJent used to delete the file during `ensure_existence_preconditions` and then tried to call `resolve_link` on the deleted file.

GitOrigin-RevId: 3f5d2c919d02ad689e502983aae9200645f6c33a
This commit is contained in:
Vladimir Lagunov
2024-10-07 18:00:25 +02:00
committed by intellij-monorepo-bot
parent 9b0a64d2b4
commit 1e3ca1555f
3 changed files with 26 additions and 3 deletions

View File

@@ -261,12 +261,22 @@ interface EelFileSystemApi {
class Other(where: EelPath.Absolute, additionalMessage: String) : CopyException(where, additionalMessage), EelFsError.Other
}
enum class ReplaceExistingDuringMove {
REPLACE_EVERYTHING,
/** For compatibility with Java NIO. */
DO_NOT_REPLACE_DIRECTORIES,
DO_NOT_REPLACE,
}
@Throws(MoveException::class)
suspend fun move(source: EelPath.Absolute, target: EelPath.Absolute, replaceExisting: Boolean, followLinks: Boolean)
suspend fun move(source: EelPath.Absolute, target: EelPath.Absolute, replaceExisting: ReplaceExistingDuringMove, followLinks: Boolean)
sealed class MoveException(where: EelPath.Absolute, additionalMessage: String) : EelFsIOException(where, additionalMessage) {
class SourceDoesNotExist(where: EelPath.Absolute) : MoveException(where, "Source does not exist"), EelFsError.DoesNotExist
class TargetAlreadyExists(where: EelPath.Absolute) : MoveException(where, "Target already exists"), EelFsError.AlreadyExists
class TargetIsDirectory(where: EelPath.Absolute) : MoveException(where, "Target already exists and it is a directory"), EelFsError.AlreadyExists
class PermissionDenied(where: EelPath.Absolute) : MoveException(where, "Permission denied"), EelFsError.PermissionDenied
class NameTooLong(where: EelPath.Absolute) : MoveException(where, "Name too long"), EelFsError.NameTooLong
class ReadOnlyFileSystem(where: EelPath.Absolute) : MoveException(where, "File system is read-only"), EelFsError.ReadOnlyFileSystem

View File

@@ -187,7 +187,12 @@ private class IjentFailSafeFileSystemPosixApiImpl(
}
}
override suspend fun move(source: EelPath.Absolute, target: EelPath.Absolute, replaceExisting: Boolean, followLinks: Boolean) {
override suspend fun move(
source: EelPath.Absolute,
target: EelPath.Absolute,
replaceExisting: EelFileSystemApi.ReplaceExistingDuringMove,
followLinks: Boolean,
) {
holder.withDelegateRetrying {
move(source, target, replaceExisting, followLinks)
}

View File

@@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter
import com.intellij.platform.eel.fs.*
import com.intellij.platform.eel.fs.EelFileInfo.Type.*
import com.intellij.platform.eel.fs.EelFileSystemApi.ReplaceExistingDuringMove.*
import com.intellij.platform.eel.fs.EelFileSystemPosixApi.CreateDirectoryException
import com.intellij.platform.eel.fs.EelFileSystemPosixApi.CreateSymbolicLinkException
import com.intellij.platform.eel.fs.EelPosixFileInfo.Type.Symlink
@@ -328,7 +329,14 @@ class IjentNioFileSystemProvider : FileSystemProvider() {
source.nioFs.ijentFs.move(
sourcePath,
targetPath,
replaceExisting = true,
replaceExisting = run {
// This code may change when implementing Windows support.
when {
StandardCopyOption.ATOMIC_MOVE in options -> DO_NOT_REPLACE_DIRECTORIES
StandardCopyOption.REPLACE_EXISTING in options -> REPLACE_EVERYTHING
else -> DO_NOT_REPLACE
}
},
// In NIO, `move` does not follow links. This behavior is not influenced by the presense of NOFOLLOW_LINKS in CopyOptions
// See java.nio.file.CopyMoveHelper.convertMoveToCopyOptions
followLinks = false)