Skip to content

Commit

Permalink
Support symlink for NioFSWrappingFS
Browse files Browse the repository at this point in the history
  • Loading branch information
oldergod committed Jun 21, 2023
1 parent 06317a3 commit 0d6a49e
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ abstract class AbstractFileSystemTest(
) {
val base: Path = temporaryDirectory / "${this::class.simpleName}-${randomToken(16)}"
private val isNodeJsFileSystem = fileSystem::class.simpleName?.startsWith("NodeJs") ?: false
private val isWrappingJimFileSystem = this::class.simpleName?.contains("JimFileSystem") ?: false

@BeforeTest
fun setUp() {
Expand All @@ -72,13 +73,17 @@ abstract class AbstractFileSystemTest(
val cwdString = cwd.toString()
val slash = Path.DIRECTORY_SEPARATOR
assertTrue(cwdString) {
cwdString.endsWith("okio${slash}okio") ||
cwdString.endsWith("${slash}okio-parent-okio-js-legacy-test") ||
cwdString.endsWith("${slash}okio-parent-okio-js-ir-test") ||
cwdString.endsWith("${slash}okio-parent-okio-nodefilesystem-js-ir-test") ||
cwdString.endsWith("${slash}okio-parent-okio-nodefilesystem-js-legacy-test") ||
cwdString.contains("/CoreSimulator/Devices/") || // iOS simulator.
cwdString == "/" // Android emulator.
if (isWrappingJimFileSystem) {
cwdString.endsWith("work")
} else {
cwdString.endsWith("okio${slash}okio") ||
cwdString.endsWith("${slash}okio-parent-okio-js-legacy-test") ||
cwdString.endsWith("${slash}okio-parent-okio-js-ir-test") ||
cwdString.endsWith("${slash}okio-parent-okio-nodefilesystem-js-ir-test") ||
cwdString.endsWith("${slash}okio-parent-okio-nodefilesystem-js-legacy-test") ||
cwdString.contains("/CoreSimulator/Devices/") || // iOS simulator.
cwdString == "/" // Android emulator.
}
}
}

Expand All @@ -90,12 +95,19 @@ abstract class AbstractFileSystemTest(
}

@Test
fun canonicalizeNoSuchFile() {
fun canonicalizeAbsolutePathNoSuchFile() {
assertFailsWith<FileNotFoundException> {
fileSystem.canonicalize(base / "no-such-file")
}
}

@Test
fun canonicalizeRelativePathNoSuchFile() {
assertFailsWith<FileNotFoundException> {
fileSystem.canonicalize("no-such-file".toPath())
}
}

@Test
fun canonicalizeFollowsSymlinkDirectories() {
if (!supportsSymlink()) return
Expand Down Expand Up @@ -260,6 +272,10 @@ abstract class AbstractFileSystemTest(
fileSystem.write("a.txt".toPath()) {
writeUtf8("hello, world!")
}
} else if (isWrappingJimFileSystem) {
fileSystem.write("a.txt".toPath()) {
writeUtf8("hello, world!")
}
}

val entries = fileSystem.list(".".toPath())
Expand Down Expand Up @@ -319,6 +335,10 @@ abstract class AbstractFileSystemTest(
fileSystem.write("a.txt".toPath()) {
writeUtf8("hello, world!")
}
} else if (isWrappingJimFileSystem) {
fileSystem.write("a.txt".toPath()) {
writeUtf8("hello, world!")
}
}

val entries = fileSystem.listOrNull(".".toPath())
Expand Down Expand Up @@ -2404,7 +2424,6 @@ abstract class AbstractFileSystemTest(
if (windowsLimitations) return false
return when (fileSystem::class.simpleName) {
"JvmSystemFileSystem",
"NioFileSystemWrappingFileSystem",
-> false
else -> true
}
Expand Down
38 changes: 20 additions & 18 deletions okio/src/jvmMain/kotlin/okio/NioFileSystemWrappingFileSystem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ package okio

import java.io.InterruptedIOException
import java.nio.channels.FileChannel
import java.nio.file.FileSystem as JavaNioFileSystem
import java.nio.file.FileSystem as NioFileSystem
import java.nio.file.Files
import java.nio.file.NoSuchFileException
import java.nio.file.Path as NioPath
Expand All @@ -36,24 +36,29 @@ import okio.Path.Companion.toOkioPath
* A file system that wraps a `java.nio.file.FileSystem` and executes all operations in the context of the wrapped file
* system.
*/
internal class NioFileSystemWrappingFileSystem(javaNioFileSystem: JavaNioFileSystem) : NioSystemFileSystem() {
// TODO(Benoit) How do deal with multiple directories? Test with Windows someday.
private val delegateRoot = javaNioFileSystem.rootDirectories.first()

internal class NioFileSystemWrappingFileSystem(private val nioFileSystem: NioFileSystem) : NioSystemFileSystem() {
/**
* On a `java.nio.file.FileSystem`, `java.nio.file.Path` are stateful and hold a reference to the file system they
* got provided from. We need to [resolve][java.nio.file.Path.resolve] all okio paths before doing operations on the
* nio file system in order for things to work properly.
*/
private fun Path.resolve(readSymlink: Boolean = false): NioPath {
val resolved = delegateRoot.resolve(toString())
val resolved = nioFileSystem.getPath(toString())
return if (readSymlink && resolved.isSymbolicLink()) {
resolved.readSymbolicLink()
} else {
resolved
}
}

override fun canonicalize(path: Path): Path {
try {
return path.resolve(readSymlink = true).toRealPath().toOkioPath()
} catch (e: NoSuchFileException) {
throw FileNotFoundException("no such file: $this")
}
}

override fun metadataOrNull(path: Path): FileMetadata? {
return metadataOrNull(path.resolve())
}
Expand All @@ -74,17 +79,7 @@ internal class NioFileSystemWrappingFileSystem(javaNioFileSystem: JavaNioFileSys
return null
}
}
val result = entries.mapTo(mutableListOf()) { entry ->
// TODO(Benoit) This whole block can surely be improved.
val path = dir / entry.toOkioPath()
if (dir.isRelative) {
// All `entries` are absolute and resolving them against `dir` won't have any effect. We need to manually
// relativize them back.
nioDir.relativize(path.resolve()).toOkioPath()
} else {
path
}
}
val result = entries.mapTo(mutableListOf()) { entry -> dir / entry.toString() }
result.sort()
return result
}
Expand Down Expand Up @@ -195,7 +190,14 @@ internal class NioFileSystemWrappingFileSystem(javaNioFileSystem: JavaNioFileSys
}

override fun createSymlink(source: Path, target: Path) {
Files.createSymbolicLink(source.resolve(), target.resolve())
val sourceNioPath = source.resolve()
val targetNioPath =
if (source.isAbsolute && target.isRelative) {
sourceNioPath.parent.resolve(target.toString())
} else {
target.resolve()
}
Files.createSymbolicLink(sourceNioPath, targetNioPath)
}

override fun toString(): String = "NioFileSystemWrappingFileSystem"
Expand Down
2 changes: 1 addition & 1 deletion okio/src/jvmTest/kotlin/okio/FileHandleFileSystemTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class FileHandleFileSystemTest : AbstractFileSystemTest(
}
}

class FileHandleNioFileSystemWrapperFileSystemTest : AbstractFileSystemTest(
class FileHandleNioJimFileSystemWrapperFileSystemTest : AbstractFileSystemTest(
clock = Clock.System,
fileSystem = Jimfs
.newFileSystem(
Expand Down
13 changes: 12 additions & 1 deletion okio/src/jvmTest/kotlin/okio/JvmSystemFileSystemTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package okio
import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import java.io.InterruptedIOException
import java.nio.file.FileSystems
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.fail
Expand Down Expand Up @@ -59,7 +60,7 @@ class JvmSystemFileSystemTest : AbstractFileSystemTest(
}
}

class NioFileSystemWrappingFileSystemTest : AbstractFileSystemTest(
class NioJimFileSystemWrappingFileSystemTest : AbstractFileSystemTest(
clock = Clock.System,
fileSystem = Jimfs
.newFileSystem(
Expand All @@ -73,3 +74,13 @@ class NioFileSystemWrappingFileSystemTest : AbstractFileSystemTest(
allowAtomicMoveFromFileToDirectory = true,
temporaryDirectory = FileSystem.SYSTEM_TEMPORARY_DIRECTORY,
)

class NioDefaultFileSystemWrappingFileSystemTest : AbstractFileSystemTest(
clock = Clock.System,
fileSystem = FileSystems.getDefault().asOkioFileSystem(),
windowsLimitations = false,
allowClobberingEmptyDirectories = Path.DIRECTORY_SEPARATOR == "\\",
allowAtomicMoveFromFileToDirectory = false,
allowRenameWhenTargetIsOpen = Path.DIRECTORY_SEPARATOR != "\\",
temporaryDirectory = FileSystem.SYSTEM_TEMPORARY_DIRECTORY,
)

0 comments on commit 0d6a49e

Please sign in to comment.