KorIO File System
KorIO has a Virtual File System functionality.
Table of contents:
File System
PathInfo
expect val File_separatorChar: Char
inline class PathInfo(val fullPath: String)
val String.pathInfo: PathInfo
interface Path { val pathInfo: PathInfo }
fun PathInfo.parts(): List<String>
fun PathInfo.normalize(): String
fun PathInfo.combine(access: PathInfo): PathInfo
fun PathInfo.lightCombine(access: PathInfo): PathInfo
fun PathInfo.isAbsolute(): Boolean
fun PathInfo.normalizeAbsolute(): PathInfo
// Direct PathInfo
val PathInfo.fullPathNormalized: String
val PathInfo.folder: String
val PathInfo.folderWithSlash: String
val PathInfo.baseName: String
val PathInfo.fullPathWithoutExtension: String
fun PathInfo.fullPathWithExtension(ext: String): String
val PathInfo.baseNameWithoutExtension: String
val PathInfo.baseNameWithoutCompoundExtension: String
val PathInfo.fullNameWithoutExtension: String
val PathInfo.fullNameWithoutCompoundExtension: String
fun PathInfo.baseNameWithExtension(ext: String): String
fun PathInfo.baseNameWithCompoundExtension(ext: String): String
val PathInfo.extension: String
val PathInfo.extensionLC: String
val PathInfo.compoundExtension: String
val PathInfo.compoundExtensionLC: String
val PathInfo.mimeTypeByExtension: MimeType
fun PathInfo.getPathComponents(): List<String>
fun PathInfo.getPathFullComponents(): List<String>
val PathInfo.fullName: String
// For instances including a pathInfo
val Path.fullPathNormalized: String
val Path.folder: String
val Path.folderWithSlash: String
val Path.baseName: String
val Path.fullPathWithoutExtension: String
fun Path.fullPathWithExtension(ext: String): String
val Path.fullNameWithoutExtension: String
val Path.baseNameWithoutExtension: String
val Path.fullNameWithoutCompoundExtension: String
val Path.baseNameWithoutCompoundExtension: String
fun Path.baseNameWithExtension(ext: String): String
fun Path.baseNameWithCompoundExtension(ext: String): String
val Path.extension: String
val Path.extensionLC: String
val Path.compoundExtension: String
val Path.compoundExtensionLC: String
val Path.mimeTypeByExtension: MimeType
fun Path.getPathComponents(): List<String>
fun Path.getPathFullComponents(): List<String>
val Path.fullName: String
VfsFile
data class VfsFile(
val vfs: Vfs,
val path: String
) : VfsNamed(path.pathInfo), AsyncInputOpenable, Extra by Extra.Mixin() {
val parent: VfsFile
val root: VfsFile
val absolutePath: String
operator fun get(path: String): VfsFile
// @TODO: Kotlin suspend operator not supported yet!
suspend fun set(path: String, content: String)
suspend fun set(path: String, content: ByteArray)
suspend fun set(path: String, content: AsyncStream)
suspend fun set(path: String, content: VfsFile)
suspend fun put(content: AsyncInputStream, attributes: List<Vfs.Attribute> = listOf()): Long
suspend fun put(content: AsyncInputStream, vararg attributes: Vfs.Attribute): Long
suspend fun write(data: ByteArray, vararg attributes: Vfs.Attribute): Long
suspend fun writeBytes(data: ByteArray, vararg attributes: Vfs.Attribute): Long
suspend fun writeStream(src: AsyncInputStream, vararg attributes: Vfs.Attribute, autoClose: Boolean = true): Long
suspend fun writeFile(file: VfsFile, vararg attributes: Vfs.Attribute): Long
suspend fun listNames(): List<String>
suspend fun copyTo(target: AsyncOutputStream)
suspend fun copyTo(target: VfsFile, vararg attributes: Vfs.Attribute): Long
fun withExtension(ext: String): VfsFile
fun withCompoundExtension(ext: String): VfsFile
fun appendExtension(ext: String): VfsFile
suspend fun open(mode: VfsOpenMode = VfsOpenMode.READ): AsyncStream
suspend fun openInputStream(): AsyncInputStream
override suspend fun openRead(): AsyncStream
suspend inline fun <T> openUse(mode: VfsOpenMode
suspend fun readRangeBytes(range: LongRange): ByteArray
suspend fun readRangeBytes(range: IntRange): ByteArray
suspend fun readAll(): ByteArray
suspend fun read(): ByteArray
suspend fun readBytes(): ByteArray
suspend fun readLines(charset: Charset = UTF8): List<String>
suspend fun writeLines(lines: List<String>, charset: Charset = UTF8)
suspend fun readString(charset: Charset = UTF8): String
suspend fun writeString(data: String, vararg attributes: Vfs.Attribute, charset: Charset = UTF8): Unit
suspend fun readChunk(offset: Long, size: Int): ByteArray
suspend fun writeChunk(data: ByteArray, offset: Long, resize: Boolean = false): Unit
suspend fun readAsSyncStream(): SyncStream
suspend fun stat(): VfsStat
suspend fun touch(time: DateTime, atime: DateTime = time): Unit
suspend fun size(): Long
suspend fun exists(): Boolean
suspend fun isDirectory(): Boolean
suspend fun setSize(size: Long): Unit
suspend fun delete(): Unit
suspend fun setAttributes(attributes: List<Vfs.Attribute>)
suspend fun setAttributes(vararg attributes: Vfs.Attribute)
suspend fun mkdir(attributes: List<Vfs.Attribute>)
suspend fun mkdir(vararg attributes: Vfs.Attribute)
suspend fun copyToTree(
target: VfsFile,
vararg attributes: Vfs.Attribute,
notify: suspend (Pair<VfsFile, VfsFile>) -> Unit = {}
): Unit
suspend fun ensureParents(): VfsFile
suspend fun renameTo(dstPath: String): Unit
suspend fun list(): ReceiveChannel<VfsFile>
suspend fun listRecursive(filter: (VfsFile) -> Boolean = { true }): ReceiveChannel<VfsFile>
suspend fun exec(
cmdAndArgs: List<String>,
env: Map<String, String> = LinkedHashMap(),
handler: VfsProcessHandler = VfsProcessHandler()
): Int
suspend fun execToString(
cmdAndArgs: List<String>,
env: Map<String, String> = LinkedHashMap(),
charset: Charset = UTF8,
captureError: Boolean = false,
throwOnError: Boolean = true
): String
suspend fun execToString(vararg cmdAndArgs: String, charset: Charset = UTF8): String
suspend fun passthru(
cmdAndArgs: List<String>,
env: Map<String, String> = LinkedHashMap(),
charset: Charset = UTF8
): Int
suspend fun passthru(
vararg cmdAndArgs: String,
env: Map<String, String> = LinkedHashMap(),
charset: Charset = UTF8
): Int
suspend fun watch(handler: suspend (Vfs.FileEvent) -> Unit): Closeable
suspend fun redirected(pathRedirector: suspend VfsFile.(String) -> String): VfsFile
fun jail(): VfsFile
suspend fun getUnderlyingUnscapedFile(): FinalVfsFile
}
fun VfsFile.toUnscaped(): FinalVfsFile
fun FinalVfsFile.toFile(): VfsFile
data class FinalVfsFile(val file: VfsFile) {
constructor(vfs: Vfs, path: String) : this(vfs[path])
val vfs: Vfs
val path: String
}
suspend inline fun <R> VfsFile.useVfs(callback: suspend (VfsFile) -> R): R
Vfs
open class VfsNamed(override val pathInfo: PathInfo) : Path
interface SimpleStorage {
suspend fun get(key: String): String?
suspend fun set(key: String, value: String)
suspend fun remove(key: String)
}
abstract class Vfs : AsyncCloseable {
open fun getAbsolutePath(path: String): String
val root: VfsFile
open val supportedAttributeTypes: List<KClass<out Attribute>>()
operator fun get(path: String): VfsFile
fun file(path: String) = root[path]
override suspend fun close(): Unit = Unit
fun createExistsStat(
path: String, isDirectory: Boolean, size: Long, device: Long = -1, inode: Long = -1, mode: Int = 511,
owner: String = "nobody", group: String = "nobody", createTime: DateTime = DateTime.EPOCH, modifiedTime: DateTime = DateTime.EPOCH,
lastAccessTime: DateTime = modifiedTime, extraInfo: Any? = null, id: String? = null
): VfsStat
fun createNonExistsStat(path: String, extraInfo: Any? = null): VfsStat
suspend fun exec(path: String, cmdAndArgs: List<String>, handler: VfsProcessHandler = VfsProcessHandler()): Int
open suspend fun exec(path: String, cmdAndArgs: List<String>, env: Map<String, String>, handler: VfsProcessHandler = VfsProcessHandler()): Int
open suspend fun open(path: String, mode: VfsOpenMode): AsyncStream
open suspend fun openInputStream(path: String): AsyncInputStream
open suspend fun readRange(path: String, range: LongRange): ByteArray
open suspend fun put(path: String, content: AsyncInputStream, attributes: List<Attribute> = listOf()): Long
suspend fun put(path: String, content: ByteArray, attributes: List<Attribute> = listOf()): Long
suspend fun readChunk(path: String, offset: Long, size: Int): ByteArray
suspend fun writeChunk(path: String, data: ByteArray, offset: Long, resize: Boolean)
open suspend fun setSize(path: String, size: Long)
open suspend fun setAttributes(path: String, attributes: List<Attribute>): Unit
open suspend fun stat(path: String): VfsStat
open suspend fun list(path: String): ReceiveChannel<VfsFile>
open suspend fun mkdir(path: String, attributes: List<Attribute>): Boolean
open suspend fun rmdir(path: String): Boolean
open suspend fun delete(path: String): Boolean
open suspend fun rename(src: String, dst: String): Boolean
open suspend fun watch(path: String, handler: (FileEvent) -> Unit): Closeable
open suspend fun touch(path: String, time: DateTime, atime: DateTime)
open suspend fun getUnderlyingUnscapedFile(path: String): FinalVfsFile
interface Attribute
inline fun <reified T> Iterable<Attribute>.get(): T?
abstract class Proxy : Vfs() {
protected abstract suspend fun access(path: String): VfsFile
protected open suspend fun VfsFile.transform(): VfsFile = file(this.path)
final override suspend fun getUnderlyingUnscapedFile(path: String): FinalVfsFile = initOnce().access(path).getUnderlyingUnscapedFile()
protected open suspend fun init() = Unit
var initialized = false
}
open class Decorator(val parent: VfsFile) : Proxy() {
val parentVfs = parent.vfs
override suspend fun access(path: String): VfsFile = parentVfs[path]
}
data class FileEvent(val kind: Kind, val file: VfsFile, val other: VfsFile? = null) {
enum class Kind { DELETED, MODIFIED, CREATED, RENAMED }
}
}
enum class VfsOpenMode(
val cmode: String,
val write: Boolean,
val createIfNotExists: Boolean = false,
val truncate: Boolean = false
) {
READ("rb", write = false),
WRITE("r+b", write = true, createIfNotExists = true),
APPEND("a+b", write = true, createIfNotExists = true),
CREATE_OR_TRUNCATE("w+b", write = true, createIfNotExists = true, truncate = true),
CREATE("w+b", write = true, createIfNotExists = true),
CREATE_NEW("w+b", write = true);
}
open class VfsProcessHandler {
open suspend fun onOut(data: ByteArray): Unit = Unit
open suspend fun onErr(data: ByteArray): Unit = Unit
}
class VfsProcessException(message: String) : IOException(message)
data class VfsStat(
val file: VfsFile,
val exists: Boolean,
val isDirectory: Boolean,
val size: Long,
val device: Long = -1L,
val inode: Long = -1L,
val mode: Int = 511,
val owner: String = "nobody",
val group: String = "nobody",
val createTime: DateTime = DateTime.EPOCH,
val modifiedTime: DateTime = createTime,
val lastAccessTime: DateTime = modifiedTime,
val extraInfo: Any? = null,
val id: String? = null
) : Path by file
val VfsStat.createDate: DateTime get() = createTime
val VfsStat.modifiedDate: DateTime get() = modifiedTime
val VfsStat.lastAccessDate: DateTime get() = lastAccessTime
suspend fun ByteArray.writeToFile(path: String) = localVfs(path).write(this)
suspend fun ByteArray.writeToFile(file: VfsFile) = file.write(this)
Standard File Systems
var resourcesVfsDebug = false
val resourcesVfs: VfsFile
val rootLocalVfs: VfsFile
val applicationVfs: VfsFile
val applicationDataVfs: VfsFile
val cacheVfs: VfsFile
val externalStorageVfs: VfsFile
val userHomeVfs: VfsFile
val tempVfs: VfsFile
val localCurrentDirVfs: VfsFile
fun localVfs(path: String): VfsFile
fun jailedLocalVfs(base: String): VfsFile
IsoVfs
suspend fun IsoVfs(file: VfsFile): VfsFile
suspend fun IsoVfs(s: AsyncStream): VfsFile
suspend fun AsyncStream.openAsIso(): IsoVfs
suspend fun VfsFile.openAsIso(): IsoVfs
suspend fun <R> AsyncStream.openAsIso(callback: suspend (VfsFile) -> R): R
suspend fun <R> VfsFile.openAsIso(callback: suspend (VfsFile) -> R): R
JailVfs
fun VfsFile.jail(): VfsFile
fun JailVfs(jailRoot: VfsFile): VfsFile
LocalVfs
abstract class LocalVfs : Vfs() {
companion object { operator fun get(base: String): VfsFile = localVfs(base) }
override fun toString(): String = "LocalVfs"
}
LogVfs
fun VfsFile.log(): VfsFile = LogVfs(this).root
class LogVfs(val parent: VfsFile) : Vfs.Proxy() {
val log: List<String>
val logstr: Strin
val modifiedFiles: Set<String>()
}
MapLikeStorageVfs
fun SimpleStorage.toVfs(): VfsFile = MapLikeStorageVfs(this).root
class MapLikeStorageVfs(val storage: SimpleStorage) : Vfs()
MemoryVfs
fun MemoryVfs(items: Map<String, AsyncStream> = LinkedHashMap(), caseSensitive: Boolean = true): VfsFile
fun MemoryVfsMix(
items: Map<String, Any> = LinkedHashMap(),
caseSensitive: Boolean = true,
charset: Charset = UTF8
): VfsFile
fun MemoryVfsMix(vararg items: Pair<String, Any>, caseSensitive: Boolean = true, charset: Charset = UTF8): VfsFile
MergedVfs
open class MergedVfs(vfsList: List<VfsFile> = listOf()) : Vfs.Proxy() {
operator fun plusAssign(other: VfsFile)
operator fun minusAssign(other: VfsFile)
}
MountableVfs
interface Mountable {
fun mount(folder: String, file: VfsFile): Mountable
fun unmount(folder: String): Mountable
}
// VfsFile.vfs is Mountable
suspend fun MountableVfs(closeMounts: Boolean = false, callback: suspend Mountable.() -> Unit): VfsFile
NodeVfs
open class NodeVfs(val caseSensitive: Boolean = true) : Vfs() {
val events = Signal<FileEvent>()
val rootNode = Node("", isDirectory = true)
open inner class Node() : Iterable<Node> {
val name: String
val isDirectory: Boolean
parent: Node? = null
val nameLC: String
var parent: Node?
var data: Any?
val children: Map<String, Node>()
val childrenLC: Map<String, Node>()
val root: Node
var stream: AsyncStream? = null
fun child(name: String): Node?
fun createChild(name: String, isDirectory: Boolean = false): Node
operator fun get(path: String): Node
fun getOrNull(path: String): Node?
fun access(path: String, createFolders: Boolean = false): Node
fun mkdir(name: String): Boolean
}
}
UniversalVfs
val String.uniVfs: UniversalVfs
fun String.uniVfs(providers: UniSchemaProviders, base: VfsFile? = null): VfsFile
object UniversalVfs {
operator fun invoke(uri: String, providers: UniSchemaProviders, base: VfsFile? = null): VfsFile
}
class UniSchema(val name: String, val provider: (URL) -> VfsFile)
class UniSchemaProviders(val providers: Map<String, UniSchema>) {
constructor(providers: Iterable<UniSchema>)
constructor(vararg providers: UniSchema)
}
var defaultUniSchema = UniSchemaProviders(
UniSchema("http") { UrlVfs(it) },
UniSchema("https") { UrlVfs(it) },
UniSchema("file") { rootLocalVfs[it.path] }
)
fun registerUniSchema(schema: UniSchema)
inline fun <T> registerUniSchemaTemporarily(schema: UniSchema, callback: () -> T): T
operator fun UniSchemaProviders.plus(other: UniSchemaProviders)
operator fun UniSchemaProviders.plus(other: UniSchema)
operator fun UniSchemaProviders.minus(other: UniSchemaProviders): UniSchemaProviders
operator fun UniSchemaProviders.minus(other: UniSchema)
UrlVfs
fun UrlVfs(url: String, client: HttpClient = createHttpClient()): VfsFile
fun UrlVfs(url: URL, client: HttpClient = createHttpClient()): VfsFile
fun UrlVfsJailed(url: String, client: HttpClient = createHttpClient()): VfsFile
fun UrlVfsJailed(url: URL, client: HttpClient = createHttpClient()): VfsFile
class UrlVfs(val url: String, val dummy: Unit, val client: HttpClient = createHttpClient()) : Vfs() {
class HttpHeaders(val headers: Http.Headers) : Attribute
fun getFullUrl(path: String): String {
val result = url.trim('/') + '/' + path.trim('/')
//println("UrlVfs.getFullUrl: url=$url, path=$path, result=$result")
return result
}
}
ZipVfs
// Create Zip File
suspend fun VfsFile.createZipFromTree(): ByteArray
suspend fun VfsFile.createZipFromTreeTo(s: AsyncStream)
// Opening Zip File
suspend fun VfsFile.openAsZip(caseSensitive: Boolean = true): VfsFile
suspend fun AsyncStream.openAsZip(caseSensitive: Boolean = true)suspend fun <R> VfsFile.openAsZip(caseSensitive: Boolean = true, callback: suspend (VfsFile) -> R): R
suspend fun <R> AsyncStream.openAsZip(caseSensitive: Boolean = true, callback: suspend (VfsFile) -> R): R
suspend fun ZipVfs(s: AsyncStream, zipFile: VfsFile? = null, caseSensitive: Boolean = true, closeStream: Boolean = false): VfsFile