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.kt203
1 files changed, 0 insertions, 203 deletions
diff --git a/src/jsMain/kotlin/io/files.kt b/src/jsMain/kotlin/io/files.kt
deleted file mode 100644
index 4c53c4e..0000000
--- a/src/jsMain/kotlin/io/files.kt
+++ /dev/null
@@ -1,203 +0,0 @@
-package io
-
-import User
-
-sealed interface CreateFileResult {
- object Created : CreateFileResult
- sealed interface Failure : CreateFileResult {
- object NoPermission : Failure
- object NoParent : Failure
- object AlreadyExists : Failure
- }
-}
-
-sealed interface WriteFileResult {
- object Written : WriteFileResult
- sealed interface Failure : WriteFileResult {
- object NoPermission : Failure
- object NotAFile : Failure
- data class NotEnoughSpace(
- val dataSize: Long,
- val spaceLeft: Long
- ) : Failure
- }
-}
-
-sealed interface ReadFileResult {
- data class Read(val data: ByteArray) : ReadFileResult {
- override fun equals(other: Any?): Boolean = (other as? Read)?.let { it.data.contentEquals(this.data) } ?: false
-
- override fun hashCode(): Int {
- return data.contentHashCode()
- }
- }
-
- sealed interface Failure : ReadFileResult {
- object NoPermission : Failure
- object NotAFile : Failure
- }
-}
-
-sealed interface DeleteFileResult {
- sealed interface Failure : DeleteFileResult {
- object NoPermission : Failure
- object NotAFile : Failure
- }
-
- object Deleted : DeleteFileResult
-}
-
-interface FileService<INode> {
- fun getPath(iNode: INode): Path.Absolute
- fun getINode(path: Path.Absolute): INode
- fun createFile(iNode: INode, user: User): CreateFileResult
- fun createSymlink(iNode: INode, user: User, path: Path): CreateFileResult
- fun createDirectory(iNode: INode, user: User): CreateFileResult
- fun writeToFile(iNode: INode, user: User, data: ByteArray): WriteFileResult
- fun readFromFile(iNode: INode, user: User): ReadFileResult
- fun deleteFile(iNode: INode, user: User): DeleteFileResult
- fun exists(iNode: INode): Boolean
- fun isFile(iNode: INode): Boolean
- fun isDirectory(iNode: INode): Boolean
- fun isSymlink(iNode: INode): Boolean
- fun resolve(iNode: INode, fragment: String): INode
- fun resolve(iNode: INode, path: Path.Relative): INode
- fun changePermissions(iNode: INode, user: User, permissionUpdate: Map<User, Permission>)
-}
-
-data class Permission(
- val read: Boolean,
- val write: Boolean,
- val execute: Boolean
-) {
- companion object {
- val default get() = Permission(read = true, write = true, execute = false)
- }
-}
-
-sealed interface PrimitiveStorageBlob {
- val permissions: MutableMap<User, Permission>
-
- class File(var data: ByteArray, override val permissions: MutableMap<User, Permission>) : PrimitiveStorageBlob
- class Symlink(val path: Path, override val permissions: MutableMap<User, Permission>) : PrimitiveStorageBlob
- class Directory(override val permissions: MutableMap<User, Permission>) : PrimitiveStorageBlob
-}
-
-data class PrimitiveINode internal constructor(internal val internalPath: String)
-class PrimitiveFileService : FileService<PrimitiveINode> {
- private val storageBlobs = mutableMapOf<String, PrimitiveStorageBlob>(
- "/" to PrimitiveStorageBlob.Directory(mutableMapOf())
- )
-
- override fun getPath(iNode: PrimitiveINode): Path.Absolute = Path.of(iNode.internalPath) as Path.Absolute
-
- override fun getINode(path: Path.Absolute): PrimitiveINode {
- return resolve(PrimitiveINode("/"), Path.Relative(path.parts))
- }
-
- override fun resolve(iNode: PrimitiveINode, fragment: String): PrimitiveINode {
- if (fragment == "..") {
- val up = iNode.internalPath.substringBeforeLast('/')
- if (up.isEmpty()) return PrimitiveINode("/")
- return PrimitiveINode(up)
- }
- if (fragment.isEmpty() || fragment == ".")
- return iNode
- val blob = storageBlobs[iNode.internalPath]
- return when (blob) {
- is PrimitiveStorageBlob.Symlink -> {
- when (blob.path) {
- is Path.Absolute -> getINode(blob.path)
- is Path.Relative -> resolve(resolve(iNode, ".."), blob.path)
- }
- }
- else -> {
- PrimitiveINode(iNode.internalPath + "/" + fragment)
- }
- }
- }
-
- override fun resolve(iNode: PrimitiveINode, path: Path.Relative): PrimitiveINode =
- path.parts.fold(iNode) { node, fragment -> resolve(node, fragment) }
-
- private fun getStorageBlob(iNode: PrimitiveINode): PrimitiveStorageBlob? = storageBlobs[iNode.internalPath]
-
- override fun writeToFile(iNode: PrimitiveINode, user: User, data: ByteArray): WriteFileResult {
- val file = getStorageBlob(iNode) as? PrimitiveStorageBlob.File ?: return WriteFileResult.Failure.NotAFile
- if (!hasPermission(user, file) { read })
- return WriteFileResult.Failure.NoPermission
- file.data = data
- return WriteFileResult.Written
- }
-
- override fun readFromFile(iNode: PrimitiveINode, user: User): ReadFileResult {
- val file = getStorageBlob(iNode) as? PrimitiveStorageBlob.File ?: return ReadFileResult.Failure.NotAFile
- if (!hasPermission(user, file) { read })
- return ReadFileResult.Failure.NoPermission
- return ReadFileResult.Read(file.data)
- }
-
- override fun exists(iNode: PrimitiveINode): Boolean =
- getStorageBlob(iNode) != null
-
- override fun isFile(iNode: PrimitiveINode): Boolean =
- getStorageBlob(iNode) is PrimitiveStorageBlob.File
-
- override fun isDirectory(iNode: PrimitiveINode): Boolean =
- getStorageBlob(iNode) is PrimitiveStorageBlob.Directory
-
- override fun isSymlink(iNode: PrimitiveINode): Boolean =
- getStorageBlob(iNode) is PrimitiveStorageBlob.Symlink
-
- override fun changePermissions(iNode: PrimitiveINode, user: User, permissionUpdate: Map<User, Permission>) {
- val file = getStorageBlob(iNode) ?: return // TODO Results
- if (!hasPermission(user, file) { write })
- return // TODO Results
- file.permissions.putAll(permissionUpdate)
- return // TODO Results
- }
-
- override fun deleteFile(iNode: PrimitiveINode, user: User): DeleteFileResult {
- val file = getStorageBlob(iNode) ?: return DeleteFileResult.Failure.NotAFile
- if (!hasPermission(user, file) { write })
- return DeleteFileResult.Failure.NoPermission
- (storageBlobs.keys.filter { it.startsWith(iNode.internalPath + "/") } + listOf(iNode.internalPath)).forEach {
- storageBlobs.remove(it)
- }
- return DeleteFileResult.Deleted
- }
-
- private fun hasPermission(user: User, blob: PrimitiveStorageBlob, check: Permission.() -> Boolean): Boolean {
- return user.isRoot || blob.permissions[user]?.let(check) ?: false
- }
-
- private fun checkCreationPreconditions(iNode: PrimitiveINode, user: User): CreateFileResult? {
- if (storageBlobs.containsKey(iNode.internalPath)) return CreateFileResult.Failure.AlreadyExists
- val parent = getStorageBlob(resolve(iNode, ".."))
- if (parent !is PrimitiveStorageBlob.Directory) return CreateFileResult.Failure.NoParent
- if (!hasPermission(user, parent) { write }) return CreateFileResult.Failure.NoPermission
- return null
- }
-
- override fun createFile(iNode: PrimitiveINode, user: User): CreateFileResult {
- val preconditions = checkCreationPreconditions(iNode, user)
- if (preconditions != null) return preconditions
- storageBlobs[iNode.internalPath] = PrimitiveStorageBlob.File(byteArrayOf(), mutableMapOf(user to Permission.default))
- return CreateFileResult.Created
- }
-
- override fun createSymlink(iNode: PrimitiveINode, user: User, path: Path): CreateFileResult {
- val preconditions = checkCreationPreconditions(iNode, user)
- if (preconditions != null) return preconditions
- storageBlobs[iNode.internalPath] = PrimitiveStorageBlob.Symlink(path, mutableMapOf(user to Permission.default))
- return CreateFileResult.Created
- }
-
- override fun createDirectory(iNode: PrimitiveINode, user: User): CreateFileResult {
- val preconditions = checkCreationPreconditions(iNode, user)
- if (preconditions != null) return preconditions
- storageBlobs[iNode.internalPath] = PrimitiveStorageBlob.Directory(mutableMapOf(user to Permission.default))
- return CreateFileResult.Created
- }
-
-}