1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
)
|