summaryrefslogtreecommitdiff
path: root/src/jsMain/kotlin/io/files.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsMain/kotlin/io/files.kt')
-rw-r--r--src/jsMain/kotlin/io/files.kt90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/jsMain/kotlin/io/files.kt b/src/jsMain/kotlin/io/files.kt
new file mode 100644
index 0000000..d37035d
--- /dev/null
+++ b/src/jsMain/kotlin/io/files.kt
@@ -0,0 +1,90 @@
+package io
+
+import User
+
+class IOHandler {
+ val mounts = mutableListOf<Mount>()
+ fun mount(absolutePath: Path.Absolute, fileSystem: FileSystem) {
+ if (mounts.any { it.mountPoint == absolutePath })
+ return // TODO sensible error message handling
+ mounts += Mount(absolutePath, fileSystem)
+ }
+
+ fun unmount(mountPoint: Path.Absolute) {
+ mounts.removeAll { it.mountPoint == mountPoint }
+ }
+
+ fun <T> findMountFor(
+ workingDirectory: Path.Absolute,
+ path: Path,
+ operation: FileSystem.(relativePath: Path) -> T
+ ): T {
+ val absolutPath = path.toAbsolutePath(workingDirectory)
+ val mount = mounts.filter {
+ it.mountPoint.parts.zip(absolutPath.parts).all { (a, b) -> a == b }
+ }.maxByOrNull { it.mountPoint.parts.size } ?: throw IllegalStateException("No mount present")
+ return mount.fileSystem.operation(
+ Path.Absolute(
+ absolutPath.parts.subList(
+ mount.mountPoint.parts.size,
+ absolutPath.parts.size
+ )
+ ) // TODO: unangenehm
+ )
+ }
+
+ fun findINode(absolutePath: Path.Absolute): INode {
+ val mount = mounts.filter {
+ it.mountPoint.parts.zip(absolutePath.parts).all { (a, b) -> a == b }
+ }.maxByOrNull { it.mountPoint.parts.size } ?: throw IllegalStateException("No mount present")
+ val iNode = mount.fileSystem.getINode(absolutePath.relativize(mount.mountPoint))
+ return when (iNode) {
+ is INodeResult.File -> iNode.op
+ is INodeResult.ResolveAgain -> findINode(absolutePath.resolve(iNode.relativeToOriginal))
+ }
+ }
+
+ fun read(workingDirectory: Path.Absolute, path: Path): ReadResult =
+ findMountFor(workingDirectory, path) { read(it) }
+
+ fun write(workingDirectory: Path.Absolute, path: Path, data: ByteArray): Unit =
+ findMountFor(workingDirectory, path) { write(it, data) }
+
+ fun stat(workingDirectory: Path.Absolute, path: Path): Unit =
+ findMountFor(workingDirectory, path) { stat(it) }
+}
+
+interface INode {
+ val fs: FileSystem
+}
+
+sealed interface INodeResult {
+ class File(val op: INode) : INodeResult
+ class ResolveAgain(val relativeToOriginal: Path): INodeResult
+}
+
+interface FileSystem {
+ fun getINode(relativePath: Path.Relative): INodeResult
+ fun read(relativePath: Path): ReadResult
+ fun write(path: Path, data: ByteArray): Unit // Write result
+ fun stat(path: Path): Unit // TODO io.Stat result
+}
+
+sealed class ReadResult {
+ class Success(val text: String) : ReadResult()
+ object NotFound : ReadResult()
+ object NoAccess : ReadResult()
+}
+
+data class Mount(
+ val mountPoint: Path.Absolute,
+ val fileSystem: FileSystem
+)
+
+data class Stat(
+ val exists: Boolean,
+ var owner: User,
+ val created: Long,
+ val edited: Long,
+ val size: Long
+)