From 8de9c0f46b62ec2d1e1626f2fb1ad6eb2dd4cfe5 Mon Sep 17 00:00:00 2001 From: Alexey Illarionov Date: Sun, 25 Aug 2024 15:41:29 +0300 Subject: [PATCH] Merge linux amr64 and x64 (#204) --- ...PlatformFileSystemOperations.linuxArm64.kt | 58 ------ .../kotlin/posix/LinuxArm64StatFd.kt | 60 ------ .../kotlin/posix/LinuxStat.linuxArm64.kt | 55 ++++++ .../kotlin/posix/LinuxStatFd.linuxArm64.kt | 31 +++ .../kotlin/posix/SyscallOpenat2.linuxArm64.kt | 20 -- .../src/linuxMain/kotlin/Dummy.kt | 10 - .../src/linuxMain/kotlin/LinuxFileSystem.kt | 77 +++++++- .../kotlin/posix/LinuxCheckAccess.kt} | 2 +- .../kotlin/posix/LinuxChmod.kt} | 2 +- .../kotlin/posix/LinuxChown.kt} | 2 +- .../kotlin/posix/LinuxMkdir.kt} | 2 +- .../src/linuxMain/kotlin/posix/LinuxOpen.kt | 179 +++++++++++------- .../kotlin/posix/LinuxReadLink.kt} | 2 +- .../kotlin/posix/LinuxSetTimestamp.kt} | 2 +- .../src/linuxMain/kotlin/posix/LinuxStat.kt | 67 +++++++ .../src/linuxMain/kotlin/posix/LinuxStatFd.kt | 37 ++++ .../kotlin/posix/LinuxUnlinkDirectory.kt} | 2 +- .../kotlin/posix/LinuxUnlinkFile.kt} | 2 +- .../linuxMain/kotlin/posix/PosixStatExt.kt | 38 ---- .../kotlin/posix/ext/BaseDirectoryExt.kt | 0 .../kotlin/posix/ext/StructTimespecExt.kt | 15 ++ .../linuxTest/kotlin/posix/LinuxOpenTest.kt | 77 +++++--- .../kotlin/posix/LinuxOpenTestToFlagsMask.kt | 40 ++++ .../PlatformFileSystemOperations.linuxX64.kt | 85 --------- .../kotlin/posix/LinuxStat.linuxX64.kt | 55 ++++++ .../kotlin/posix/LinuxStatFd.linuxX64.kt | 31 +++ .../linuxX64Main/kotlin/posix/LinuxX64Stat.kt | 70 ------- .../kotlin/posix/LinuxX64StatFd.kt | 37 ---- .../kotlin/posix/SyscallOpenat2.linuxX64.kt | 77 -------- .../src/linuxX64Test/kotlin/Dummy.kt | 10 - .../kotlin/posix/LinuxOpenTestCommon.kt | 72 ------- 31 files changed, 573 insertions(+), 644 deletions(-) delete mode 100644 wasi-emscripten-fs/src/linuxArm64Main/kotlin/PlatformFileSystemOperations.linuxArm64.kt delete mode 100644 wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxArm64StatFd.kt create mode 100644 wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStat.linuxArm64.kt create mode 100644 wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStatFd.linuxArm64.kt delete mode 100644 wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/SyscallOpenat2.linuxArm64.kt delete mode 100644 wasi-emscripten-fs/src/linuxMain/kotlin/Dummy.kt rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64CheckAccess.kt => linuxMain/kotlin/posix/LinuxCheckAccess.kt} (98%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64Chmod.kt => linuxMain/kotlin/posix/LinuxChmod.kt} (97%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64Chown.kt => linuxMain/kotlin/posix/LinuxChown.kt} (97%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64Mkdir.kt => linuxMain/kotlin/posix/LinuxMkdir.kt} (97%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64ReadLink.kt => linuxMain/kotlin/posix/LinuxReadLink.kt} (98%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64SetTimestamp.kt => linuxMain/kotlin/posix/LinuxSetTimestamp.kt} (97%) create mode 100644 wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStat.kt create mode 100644 wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStatFd.kt rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64UnlinkDirectory.kt => linuxMain/kotlin/posix/LinuxUnlinkDirectory.kt} (97%) rename wasi-emscripten-fs/src/{linuxX64Main/kotlin/posix/LinuxX64UnlinkFile.kt => linuxMain/kotlin/posix/LinuxUnlinkFile.kt} (97%) rename wasi-emscripten-fs/src/{linuxX64Main => linuxMain}/kotlin/posix/ext/BaseDirectoryExt.kt (100%) create mode 100644 wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/StructTimespecExt.kt create mode 100644 wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTestToFlagsMask.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/PlatformFileSystemOperations.linuxX64.kt create mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStat.linuxX64.kt create mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStatFd.linuxX64.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Stat.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64StatFd.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/SyscallOpenat2.linuxX64.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Test/kotlin/Dummy.kt delete mode 100644 wasi-emscripten-fs/src/linuxX64Test/kotlin/posix/LinuxOpenTestCommon.kt diff --git a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/PlatformFileSystemOperations.linuxArm64.kt b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/PlatformFileSystemOperations.linuxArm64.kt deleted file mode 100644 index 373f6579..00000000 --- a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/PlatformFileSystemOperations.linuxArm64.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem - -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.FileSystemOperation -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chmod.ChmodFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chown.ChownFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.close.CloseFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.cwd.GetCurrentWorkingDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.AddAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.RemoveAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.ReadFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.WriteFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.seek.SeekFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.settimestamp.SetTimestampFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.sync.SyncFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.truncate.TruncateFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxAddAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxArm64StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChmodFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChownFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxGetCurrentWorkingDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxOpen -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxReadFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxRemoveAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSeekFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSetTimestampFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSync -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxTruncateFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxWriteFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.PosixCloseFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler - -internal actual fun createPlatformFileSystemOperations( - fsState: PosixFileSystemState, -): Map, PosixOperationHandler<*, *, *>> = mapOf( - Open to LinuxOpen(fsState), - CloseFd to PosixCloseFd(fsState), - AddAdvisoryLockFd to LinuxAddAdvisoryLockFd, - RemoveAdvisoryLockFd to LinuxRemoveAdvisoryLockFd, - ChmodFd to LinuxChmodFd, - ChownFd to LinuxChownFd, - GetCurrentWorkingDirectory to LinuxGetCurrentWorkingDirectory, - ReadFd to LinuxReadFd, - SeekFd to LinuxSeekFd, - SetTimestampFd to LinuxSetTimestampFd, - StatFd to LinuxArm64StatFd, - SyncFd to LinuxSync, - TruncateFd to LinuxTruncateFd, - WriteFd to LinuxWriteFd, -) diff --git a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxArm64StatFd.kt b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxArm64StatFd.kt deleted file mode 100644 index 5e0d7ffe..00000000 --- a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxArm64StatFd.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import arrow.core.Either -import arrow.core.left -import arrow.core.right -import kotlinx.cinterop.alloc -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.ptr -import platform.posix.errno -import platform.posix.fstat -import platform.posix.stat -import platform.posix.timespec -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.FileModeType -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructTimespec -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler - -internal object LinuxArm64StatFd : PosixOperationHandler { - override fun invoke(input: StatFd): Either = memScoped { - val statBuf: stat = alloc() - val exitCode = fstat( - input.fd.fd, - statBuf.ptr, - ) - return if (exitCode == 0) { - statBuf.toStructStat().right() - } else { - errno.errnoToStatFdError(input).left() - } - } - - private fun stat.toStructStat(): StructStat = StructStat( - deviceId = st_dev, - inode = st_ino, - mode = FileModeType.fromLinuxModeType(st_mode), - links = st_nlink.toULong(), - usedId = st_uid.toULong(), - groupId = st_gid.toULong(), - specialFileDeviceId = st_rdev, - size = st_size.toULong(), - blockSize = st_blksize.toULong(), - blocks = st_blocks.toULong(), - accessTime = st_atim.toStructTimespec(), - modificationTime = st_mtim.toStructTimespec(), - changeStatusTime = st_ctim.toStructTimespec(), - ) - - private fun timespec.toStructTimespec(): StructTimespec = StructTimespec( - seconds = this.tv_sec.toULong(), - nanoseconds = this.tv_nsec.toULong(), - ) -} diff --git a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStat.linuxArm64.kt b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStat.linuxArm64.kt new file mode 100644 index 00000000..3845b342 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStat.linuxArm64.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import platform.posix.errno +import platform.posix.stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.FileModeType +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toStructTimespec +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fstatat + +internal actual fun platformFstatat( + dirfd: Int, + path: String, + statFlags: Int, +): Either = memScoped { + val statBuf: stat = alloc() + val exitCode = fstatat( + dirfd, + path, + statBuf.ptr, + statFlags, + ) + return if (exitCode == 0) { + statBuf.toStructStat().right() + } else { + errno.left() + } +} + +internal fun stat.toStructStat(): StructStat = StructStat( + deviceId = st_dev, + inode = st_ino, + mode = FileModeType.fromLinuxModeType(st_mode), + links = st_nlink.toULong(), + usedId = st_uid.toULong(), + groupId = st_gid.toULong(), + specialFileDeviceId = st_rdev, + size = st_size.toULong(), + blockSize = st_blksize.toULong(), + blocks = st_blocks.toULong(), + accessTime = st_atim.toStructTimespec(), + modificationTime = st_mtim.toStructTimespec(), + changeStatusTime = st_ctim.toStructTimespec(), +) diff --git a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStatFd.linuxArm64.kt b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStatFd.linuxArm64.kt new file mode 100644 index 00000000..df87e5d5 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/LinuxStatFd.linuxArm64.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import platform.posix.errno +import platform.posix.fstat +import platform.posix.stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat + +internal actual fun platformFstatFd(fd: Int): Either = memScoped { + val statBuf: stat = alloc() + val exitCode = fstat( + fd, + statBuf.ptr, + ) + return if (exitCode == 0) { + statBuf.toStructStat().right() + } else { + errno.left() + } +} diff --git a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/SyscallOpenat2.linuxArm64.kt b/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/SyscallOpenat2.linuxArm64.kt deleted file mode 100644 index 1619f943..00000000 --- a/wasi-emscripten-fs/src/linuxArm64Main/kotlin/posix/SyscallOpenat2.linuxArm64.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.BaseDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.FileMode - -internal actual fun syscallOpenat2( - pathname: String, - baseDirectory: BaseDirectory, - openFlags: ULong, - openMode: FileMode, - resolveMode: Set, -): Long { - TODO("Not yet implemented") -} diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/Dummy.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/Dummy.kt deleted file mode 100644 index 8a3a9e50..00000000 --- a/wasi-emscripten-fs/src/linuxMain/kotlin/Dummy.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -@file:Suppress("FILE_CONTAINS_ONLY_COMMENTS", "FILE_NO_BLANK_LINE_BETWEEN_BLOCKS") - -// Workaround for https://youtrack.jetbrains.com/issue/KTIJ-15797 -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/LinuxFileSystem.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/LinuxFileSystem.kt index 4412f106..50a41a49 100644 --- a/wasi-emscripten-fs/src/linuxMain/kotlin/LinuxFileSystem.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/LinuxFileSystem.kt @@ -10,20 +10,85 @@ import arrow.core.Either import ru.pixnews.wasm.sqlite.open.helper.common.api.Logger import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.FileSystemOperationError import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.FileSystemOperation +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.checkaccess.CheckAccess +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chmod.Chmod +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chmod.ChmodFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chown.Chown +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chown.ChownFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.close.CloseFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.cwd.GetCurrentWorkingDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.AddAdvisoryLockFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.RemoveAdvisoryLockFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.mkdir.Mkdir +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readlink.ReadLink +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.ReadFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.WriteFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.seek.SeekFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.settimestamp.SetTimestamp +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.settimestamp.SetTimestampFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.Stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.sync.SyncFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.truncate.TruncateFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.unlink.UnlinkDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.unlink.UnlinkFile +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxAddAdvisoryLockFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxCheckAccess +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChmod +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChmodFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChown +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChownFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxGetCurrentWorkingDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxMkdir +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxOpen +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxReadFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxReadLink +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxRemoveAdvisoryLockFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSeekFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSetTimestamp +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSetTimestampFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxStat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxStatFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSync +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxTruncateFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxUnlinkDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxUnlinkFile +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxWriteFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.PosixCloseFd import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.BaseFileSystemAdapter import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler -internal expect fun createPlatformFileSystemOperations( - fsState: PosixFileSystemState, -): Map, PosixOperationHandler<*, *, *>> - public class LinuxFileSystem( rootLogger: Logger = Logger, ) : FileSystem { private val fsState = PosixFileSystemState(rootLogger) - private val operations: Map, PosixOperationHandler<*, *, *>> = - createPlatformFileSystemOperations(fsState) + private val operations: Map, PosixOperationHandler<*, *, *>> = mapOf( + Open to LinuxOpen(fsState), + CloseFd to PosixCloseFd(fsState), + AddAdvisoryLockFd to LinuxAddAdvisoryLockFd, + RemoveAdvisoryLockFd to LinuxRemoveAdvisoryLockFd, + CheckAccess to LinuxCheckAccess, + Chmod to LinuxChmod, + ChmodFd to LinuxChmodFd, + Chown to LinuxChown, + ChownFd to LinuxChownFd, + GetCurrentWorkingDirectory to LinuxGetCurrentWorkingDirectory, + Mkdir to LinuxMkdir, + ReadFd to LinuxReadFd, + ReadLink to LinuxReadLink, + SeekFd to LinuxSeekFd, + SetTimestamp to LinuxSetTimestamp, + SetTimestampFd to LinuxSetTimestampFd, + Stat to LinuxStat, + StatFd to LinuxStatFd, + SyncFd to LinuxSync, + TruncateFd to LinuxTruncateFd, + UnlinkFile to LinuxUnlinkFile, + UnlinkDirectory to LinuxUnlinkDirectory, + WriteFd to LinuxWriteFd, + ) private val fsAdapter = BaseFileSystemAdapter(operations) override fun close() { diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64CheckAccess.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxCheckAccess.kt similarity index 98% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64CheckAccess.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxCheckAccess.kt index 14d7659b..ec656eb8 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64CheckAccess.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxCheckAccess.kt @@ -50,7 +50,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_EMPTY_PATH import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLOW import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.SYS_faccessat2 -internal object LinuxX64CheckAccess : PosixOperationHandler { +internal object LinuxCheckAccess : PosixOperationHandler { override fun invoke(input: CheckAccess): Either { val resultCode = syscall( SYS_faccessat2.toLong(), diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chmod.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChmod.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chmod.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChmod.kt index 7e713aa0..8d6f6a4c 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chmod.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChmod.kt @@ -39,7 +39,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLOW import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fchmodat -internal object LinuxX64Chmod : PosixOperationHandler { +internal object LinuxChmod : PosixOperationHandler { override fun invoke(input: Chmod): Either { val resultCode = fchmodat( input.baseDirectory.toDirFd(), diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chown.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChown.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chown.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChown.kt index c8faf9bc..89c5e493 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Chown.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxChown.kt @@ -37,7 +37,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLOW import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fchownat -internal object LinuxX64Chown : PosixOperationHandler { +internal object LinuxChown : PosixOperationHandler { override fun invoke(input: Chown): Either { val resultCode = fchownat( input.baseDirectory.toDirFd(), diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Mkdir.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxMkdir.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Mkdir.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxMkdir.kt index c03e904c..0e53a670 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Mkdir.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxMkdir.kt @@ -41,7 +41,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperat import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.mkdirat -internal object LinuxX64Mkdir : PosixOperationHandler { +internal object LinuxMkdir : PosixOperationHandler { override fun invoke(input: Mkdir): Either { val resultCode = mkdirat( input.baseDirectory.toDirFd(), diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxOpen.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxOpen.kt index 57633c50..18965812 100644 --- a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxOpen.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxOpen.kt @@ -9,108 +9,147 @@ package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix import arrow.core.Either import arrow.core.left import arrow.core.right +import kotlinx.cinterop.alloc +import kotlinx.cinterop.cstr +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import kotlinx.cinterop.sizeOf import platform.posix.E2BIG import platform.posix.EAGAIN import platform.posix.EINVAL import platform.posix.ELOOP import platform.posix.EXDEV +import platform.posix.errno +import platform.posix.memset +import platform.posix.syscall import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.Again import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.InvalidArgument import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NotCapable import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.OpenError import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.TooManySymbolicLinks -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.BaseDirectory import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.Fd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.FileMode import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags.OpenFileFlag import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags.OpenFileFlag.O_ACCMODE -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ResolveModeFlag.RESOLVE_NO_MAGICLINKS import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_BENEATH +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_CACHED +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_IN_ROOT +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_MAGICLINKS +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_SYMLINKS +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_XDEV +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.SYS_openat2 +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.open_how internal class LinuxOpen( private val state: PosixFileSystemState, ) : PosixOperationHandler { override fun invoke(input: Open): Either { - val fdOrErrno = syscallOpenat2( - baseDirectory = input.baseDirectory, - pathname = input.path, - openFlags = input.flags.toLinuxMask(), - openMode = input.mode, - resolveMode = setOf(RESOLVE_NO_MAGICLINKS), - ) - return if (fdOrErrno >= 0) { - val fd = Fd(fdOrErrno.toInt()) + val errorOrFd = memScoped { + val openHow: open_how = alloc { + memset(ptr, 0, sizeOf().toULong()) + flags = input.flags.toLinuxMask() + mode = input.mode.mask.toULong() + resolve = setOf(ResolveModeFlag.RESOLVE_NO_MAGICLINKS).toResolveMask() + } + syscall( + __sysno = SYS_openat2.toLong(), + input.baseDirectory.toDirFd(), + input.path.cstr, + openHow.ptr, + sizeOf().toULong(), + ) + } + return if (errorOrFd < 0) { + errno.errNoToOpenError().left() + } else { + val fd = Fd(errorOrFd.toInt()) state.add(fd) fd.right() - } else { - (-fdOrErrno.toInt()).errNoToOpenError().left() } } -} -private val openFileFlagsMaskToPosixMask = listOf( - OpenFileFlag.O_CREAT to platform.posix.O_CREAT, - OpenFileFlag.O_EXCL to platform.posix.O_EXCL, - OpenFileFlag.O_NOCTTY to platform.posix.O_NOCTTY, - OpenFileFlag.O_TRUNC to platform.posix.O_TRUNC, - OpenFileFlag.O_APPEND to platform.posix.O_APPEND, - OpenFileFlag.O_NONBLOCK to platform.posix.O_NONBLOCK, - OpenFileFlag.O_NDELAY to platform.posix.O_NDELAY, - OpenFileFlag.O_DSYNC to platform.posix.O_DSYNC, - OpenFileFlag.O_ASYNC to platform.posix.O_ASYNC, - OpenFileFlag.O_DIRECTORY to platform.posix.O_DIRECTORY, - OpenFileFlag.O_NOFOLLOW to platform.posix.O_NOFOLLOW, - OpenFileFlag.O_CLOEXEC to platform.posix.O_CLOEXEC, - OpenFileFlag.O_SYNC to platform.posix.O_SYNC, -) + internal enum class ResolveModeFlag { + RESOLVE_BENEATH, + RESOLVE_IN_ROOT, + RESOLVE_NO_MAGICLINKS, + RESOLVE_NO_SYMLINKS, + RESOLVE_NO_XDEV, + RESOLVE_CACHED, + } -@Suppress("CyclomaticComplexMethod") -internal fun OpenFileFlags.toLinuxMask(): ULong { - val openFlagsMask: UInt = this.mask + internal companion object { + private val openFileFlagsMaskToPosixMask = listOf( + OpenFileFlag.O_CREAT to platform.posix.O_CREAT, + OpenFileFlag.O_EXCL to platform.posix.O_EXCL, + OpenFileFlag.O_NOCTTY to platform.posix.O_NOCTTY, + OpenFileFlag.O_TRUNC to platform.posix.O_TRUNC, + OpenFileFlag.O_APPEND to platform.posix.O_APPEND, + OpenFileFlag.O_NONBLOCK to platform.posix.O_NONBLOCK, + OpenFileFlag.O_NDELAY to platform.posix.O_NDELAY, + OpenFileFlag.O_DSYNC to platform.posix.O_DSYNC, + OpenFileFlag.O_ASYNC to platform.posix.O_ASYNC, + OpenFileFlag.O_DIRECTORY to platform.posix.O_DIRECTORY, + OpenFileFlag.O_NOFOLLOW to platform.posix.O_NOFOLLOW, + OpenFileFlag.O_CLOEXEC to platform.posix.O_CLOEXEC, + OpenFileFlag.O_SYNC to platform.posix.O_SYNC, + ) - var mask = when (val mode = openFlagsMask and O_ACCMODE) { - OpenFileFlag.O_RDONLY -> platform.posix.O_RDONLY - OpenFileFlag.O_WRONLY -> platform.posix.O_WRONLY - OpenFileFlag.O_RDWR -> platform.posix.O_RDWR - else -> error("Unknown mode $mode") - } + @Suppress("CyclomaticComplexMethod") + internal fun OpenFileFlags.toLinuxMask(): ULong { + val openFlagsMask: UInt = this.mask - openFileFlagsMaskToPosixMask.forEach { (testMask, posixMask) -> - if (openFlagsMask and testMask == testMask) { - mask = mask or posixMask - } - } - // O_DIRECT, O_LARGEFILE, O_NOATIME: Not supported - // O_PATH, O_TMPFILE: not supported, should be added? + var mask = when (val mode = openFlagsMask and O_ACCMODE) { + OpenFileFlag.O_RDONLY -> platform.posix.O_RDONLY + OpenFileFlag.O_WRONLY -> platform.posix.O_WRONLY + OpenFileFlag.O_RDWR -> platform.posix.O_RDWR + else -> error("Unknown mode $mode") + } - return mask.toULong() -} + openFileFlagsMaskToPosixMask.forEach { (testMask, posixMask) -> + if (openFlagsMask and testMask == testMask) { + mask = mask or posixMask + } + } + // O_DIRECT, O_LARGEFILE, O_NOATIME: Not supported + // O_PATH, O_TMPFILE: not supported, should be added? -private fun Int.errNoToOpenError(): OpenError = when (this) { - E2BIG -> InvalidArgument("E2BIG: extension is not supported") - EAGAIN -> Again("operation cannot be performed") - EINVAL -> InvalidArgument("Invalid argument") - ELOOP -> TooManySymbolicLinks("Too many symbolic or magic links") - EXDEV -> NotCapable("Escape from the root detected") - else -> InvalidArgument("Unknown errno $this") -} + return mask.toULong() + } -internal expect fun syscallOpenat2( - pathname: String, - baseDirectory: BaseDirectory, - openFlags: ULong, - openMode: FileMode, - resolveMode: Set, -): Long + private fun Int.errNoToOpenError(): OpenError = when (this) { + E2BIG -> InvalidArgument("E2BIG: extension is not supported") + EAGAIN -> Again("operation cannot be performed") + EINVAL -> InvalidArgument("Invalid argument") + ELOOP -> TooManySymbolicLinks("Too many symbolic or magic links") + EXDEV -> NotCapable("Escape from the root detected") + else -> InvalidArgument("Unknown errno $this") + } -internal enum class ResolveModeFlag { - RESOLVE_BENEATH, - RESOLVE_IN_ROOT, - RESOLVE_NO_MAGICLINKS, - RESOLVE_NO_SYMLINKS, - RESOLVE_NO_XDEV, - RESOLVE_CACHED, + private fun Set.toResolveMask(): ULong { + var mask = 0UL + if (contains(ResolveModeFlag.RESOLVE_BENEATH)) { + mask = mask and RESOLVE_BENEATH.toULong() + } + if (contains(ResolveModeFlag.RESOLVE_IN_ROOT)) { + mask = mask and RESOLVE_IN_ROOT.toULong() + } + if (contains(ResolveModeFlag.RESOLVE_NO_MAGICLINKS)) { + mask = mask and RESOLVE_NO_MAGICLINKS.toULong() + } + if (contains(ResolveModeFlag.RESOLVE_NO_SYMLINKS)) { + mask = mask and RESOLVE_NO_SYMLINKS.toULong() + } + if (contains(ResolveModeFlag.RESOLVE_NO_XDEV)) { + mask = mask and RESOLVE_NO_XDEV.toULong() + } + if (contains(ResolveModeFlag.RESOLVE_CACHED)) { + mask = mask and RESOLVE_CACHED.toULong() + } + return mask + } + } } diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64ReadLink.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxReadLink.kt similarity index 98% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64ReadLink.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxReadLink.kt index 17e3b5bf..1aaaf548 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64ReadLink.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxReadLink.kt @@ -43,7 +43,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_EMPTY_PATH import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fstatat import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.readlinkat -internal object LinuxX64ReadLink : PosixOperationHandler { +internal object LinuxReadLink : PosixOperationHandler { private const val PATH_STEP = 1024 private val MAX_PATH_SIZE = maxOf(1024 * 1024, PATH_MAX) diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64SetTimestamp.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxSetTimestamp.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64SetTimestamp.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxSetTimestamp.kt index 1471fad4..63b8b0ed 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64SetTimestamp.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxSetTimestamp.kt @@ -44,7 +44,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLO import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.UTIME_OMIT import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.utimensat -internal object LinuxX64SetTimestamp : PosixOperationHandler { +internal object LinuxSetTimestamp : PosixOperationHandler { override fun invoke(input: SetTimestamp): Either = memScoped { val timespec: CArrayPointer = allocArray(2) timespec[0].set(input.atimeNanoseconds) diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStat.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStat.kt new file mode 100644 index 00000000..858e5369 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStat.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import platform.posix.EACCES +import platform.posix.EBADF +import platform.posix.EINVAL +import platform.posix.ELOOP +import platform.posix.ENAMETOOLONG +import platform.posix.ENOENT +import platform.posix.ENOMEM +import platform.posix.ENOTDIR +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.AccessDenied +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.BadFileDescriptor +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.InvalidArgument +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.IoError +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NameTooLong +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NoEntry +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NotDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.TooManySymbolicLinks +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.Stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLOW + +internal expect fun platformFstatat( + dirfd: Int, + path: String, + statFlags: Int, +): Either + +internal object LinuxStat : PosixOperationHandler { + override fun invoke(input: Stat): Either { + return platformFstatat( + input.baseDirectory.toDirFd(), + input.path, + input.getStatFlags(), + ).mapLeft { + it.errnoToStatError(input) + } + } + + private fun Stat.getStatFlags(): Int = if (this.followSymlinks) { + 0 + } else { + AT_SYMLINK_NOFOLLOW + } + + private fun Int.errnoToStatError(request: Stat): StatError = when (this) { + EACCES -> AccessDenied("Access denied for `$request`") + EBADF -> BadFileDescriptor("Bad file descriptor ${request.baseDirectory}") + EINVAL -> InvalidArgument("Invalid argument in `$request`") + ELOOP -> TooManySymbolicLinks("Too many symlinks while resolving `$request`") + ENAMETOOLONG -> NameTooLong("Name too long while resolving `$request`") + ENOENT -> NoEntry("Component of `${request.path}` does not exist") + ENOMEM -> IoError("No memory") + ENOTDIR -> NotDirectory("Error while resolving `${request.path}`: not a directory") + else -> InvalidArgument("Error `$this`") + } +} diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStatFd.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStatFd.kt new file mode 100644 index 00000000..a9defd15 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxStatFd.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import platform.posix.EACCES +import platform.posix.EBADF +import platform.posix.ENOMEM +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.AccessDenied +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.BadFileDescriptor +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.InvalidArgument +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.IoError +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler + +internal expect fun platformFstatFd(fd: Int): Either + +internal object LinuxStatFd : PosixOperationHandler { + override fun invoke(input: StatFd): Either { + return platformFstatFd(input.fd.fd).mapLeft { + it.errnoToStatFdError(input) + } + } + + private fun Int.errnoToStatFdError(request: StatFd): StatError = when (this) { + EACCES -> AccessDenied("Access denied for `$request`") + EBADF -> BadFileDescriptor("Bad file descriptor ${request.fd}") + ENOMEM -> IoError("No memory") + else -> InvalidArgument("Error `$this`") + } +} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkDirectory.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkDirectory.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkDirectory.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkDirectory.kt index a7f37254..40ed5e32 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkDirectory.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkDirectory.kt @@ -41,7 +41,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_REMOVEDIR import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.unlinkat -internal object LinuxX64UnlinkDirectory : PosixOperationHandler { +internal object LinuxUnlinkDirectory : PosixOperationHandler { override fun invoke(input: UnlinkDirectory): Either { val resultCode = unlinkat( input.baseDirectory.toDirFd(), diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkFile.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkFile.kt similarity index 97% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkFile.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkFile.kt index 94199767..59c0494b 100644 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64UnlinkFile.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/LinuxUnlinkFile.kt @@ -40,7 +40,7 @@ import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperat import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.unlinkat -internal object LinuxX64UnlinkFile : PosixOperationHandler { +internal object LinuxUnlinkFile : PosixOperationHandler { override fun invoke(input: UnlinkFile): Either { val resultCode = unlinkat( input.baseDirectory.toDirFd(), diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/PosixStatExt.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/PosixStatExt.kt index 5ee24c58..66d83cf9 100644 --- a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/PosixStatExt.kt +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/PosixStatExt.kt @@ -6,26 +6,7 @@ package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix -import platform.posix.EACCES -import platform.posix.EBADF -import platform.posix.EINVAL -import platform.posix.ELOOP -import platform.posix.ENAMETOOLONG -import platform.posix.ENOENT -import platform.posix.ENOMEM -import platform.posix.ENOTDIR -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.AccessDenied -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.BadFileDescriptor -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.InvalidArgument -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.IoError -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NameTooLong -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NoEntry -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.NotDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.TooManySymbolicLinks import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.FileModeType -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.Stat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd internal fun FileModeType.Companion.fromLinuxModeType( linuxModeType: UInt, @@ -45,22 +26,3 @@ internal fun FileModeType.Companion.fromLinuxModeType( val modeMask = linuxModeType and 0xfffU return FileModeType(typeMask or modeMask) } - -internal fun Int.errnoToStatError(request: Stat): StatError = when (this) { - EACCES -> AccessDenied("Access denied for `$request`") - EBADF -> BadFileDescriptor("Bad file descriptor ${request.baseDirectory}") - EINVAL -> InvalidArgument("Invalid argument in `$request`") - ELOOP -> TooManySymbolicLinks("Too many symlinks while resolving `$request`") - ENAMETOOLONG -> NameTooLong("Name too long while resolving `$request`") - ENOENT -> NoEntry("Component of `${request.path}` does not exist") - ENOMEM -> IoError("No memory") - ENOTDIR -> NotDirectory("Error while resolving `${request.path}`: not a directory") - else -> InvalidArgument("Error `$this`") -} - -internal fun Int.errnoToStatFdError(request: StatFd): StatError = when (this) { - EACCES -> AccessDenied("Access denied for `$request`") - EBADF -> BadFileDescriptor("Bad file descriptor ${request.fd}") - ENOMEM -> IoError("No memory") - else -> InvalidArgument("Error `$this`") -} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/ext/BaseDirectoryExt.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/BaseDirectoryExt.kt similarity index 100% rename from wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/ext/BaseDirectoryExt.kt rename to wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/BaseDirectoryExt.kt diff --git a/wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/StructTimespecExt.kt b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/StructTimespecExt.kt new file mode 100644 index 00000000..ac76c8c6 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxMain/kotlin/posix/ext/StructTimespecExt.kt @@ -0,0 +1,15 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext + +import platform.posix.timespec +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructTimespec + +internal fun timespec.toStructTimespec(): StructTimespec = StructTimespec( + seconds = this.tv_sec.toULong(), + nanoseconds = this.tv_nsec.toULong(), +) diff --git a/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTest.kt b/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTest.kt index d6703389..ed26b7d1 100644 --- a/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTest.kt +++ b/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTest.kt @@ -6,34 +6,65 @@ package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix +import assertk.all import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.tableOf +import assertk.assertions.containsOnly +import assertk.assertions.isNotNull +import kotlinx.io.files.Path +import platform.posix.close +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.BaseDirectory +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.FileMode +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState +import ru.pixnews.wasm.sqlite.test.utils.TempFolder +import ru.pixnews.wasm.sqlite.test.utils.TestLogger +import ru.pixnews.wasm.sqlite.test.utils.absolutePath +import ru.pixnews.wasm.sqlite.test.utils.assertions.FileModeBit +import ru.pixnews.wasm.sqlite.test.utils.assertions.fileMode +import ru.pixnews.wasm.sqlite.test.utils.assertions.isEmpty +import ru.pixnews.wasm.sqlite.test.utils.assertions.isRegularFile +import kotlin.test.AfterTest +import kotlin.test.BeforeTest import kotlin.test.Test -import platform.posix.O_CREAT as POSIX_O_CREAT -import platform.posix.O_RDONLY as POSIX_O_RDONLY -import platform.posix.O_RDWR as POSIX_O_RDWR -import platform.posix.O_TRUNC as POSIX_O_TRUNC class LinuxOpenTest { + lateinit var tempFolder: TempFolder + + @BeforeTest + fun setup() { + tempFolder = TempFolder.create() + } + + @AfterTest + fun cleanup() { + tempFolder.delete() + } + @Test - fun toFlagsMask_should_generate_correct_mask() { - tableOf("fsMask", "expectedLinuxMask") - .row( - OpenFileFlags(OpenFileFlags.O_RDWR or OpenFileFlags.O_CREAT), - POSIX_O_RDWR or POSIX_O_CREAT, - ) - .row( - OpenFileFlags(OpenFileFlags.O_RDONLY), - POSIX_O_RDONLY, - ) - .row( - OpenFileFlags(OpenFileFlags.O_RDWR or OpenFileFlags.O_TRUNC), - POSIX_O_RDWR or POSIX_O_TRUNC, - ) - .forAll { openFileFlags, expectedLinuxMask -> - assertThat(openFileFlags.toLinuxMask()).isEqualTo(expectedLinuxMask.toULong()) - } + fun create_file_with_absolute_path_should_work() { + val fsState = PosixFileSystemState(TestLogger()) + val linuxOpen = LinuxOpen(fsState) + + val tempFileAbsolutePath = tempFolder.absolutePath() + val testFile = Path(tempFileAbsolutePath, "file.test") + + val request = Open( + path = testFile.toString(), + baseDirectory = BaseDirectory.None, + flags = OpenFileFlags(OpenFileFlags.O_CREAT or OpenFileFlags.O_WRONLY), + mode = FileMode(0b111_000_000U), + ) + + val newFd = linuxOpen.invoke(request).getOrNull()?.let { + close(it.fd) + } + + assertThat(newFd).isNotNull() + assertThat(testFile).all { + isRegularFile() + isEmpty() + fileMode().containsOnly(FileModeBit.USER_READ, FileModeBit.USER_WRITE, FileModeBit.USER_EXECUTE) + } } } diff --git a/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTestToFlagsMask.kt b/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTestToFlagsMask.kt new file mode 100644 index 00000000..565043f2 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxTest/kotlin/posix/LinuxOpenTestToFlagsMask.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.tableOf +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxOpen.Companion.toLinuxMask +import kotlin.test.Test +import platform.posix.O_CREAT as POSIX_O_CREAT +import platform.posix.O_RDONLY as POSIX_O_RDONLY +import platform.posix.O_RDWR as POSIX_O_RDWR +import platform.posix.O_TRUNC as POSIX_O_TRUNC + +class LinuxOpenTestToFlagsMask { + @Test + fun toFlagsMask_should_generate_correct_mask() { + tableOf("fsMask", "expectedLinuxMask") + .row( + OpenFileFlags(OpenFileFlags.O_RDWR or OpenFileFlags.O_CREAT), + POSIX_O_RDWR or POSIX_O_CREAT, + ) + .row( + OpenFileFlags(OpenFileFlags.O_RDONLY), + POSIX_O_RDONLY, + ) + .row( + OpenFileFlags(OpenFileFlags.O_RDWR or OpenFileFlags.O_TRUNC), + POSIX_O_RDWR or POSIX_O_TRUNC, + ) + .forAll { openFileFlags, expectedLinuxMask -> + assertThat(openFileFlags.toLinuxMask()).isEqualTo(expectedLinuxMask.toULong()) + } + } +} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/PlatformFileSystemOperations.linuxX64.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/PlatformFileSystemOperations.linuxX64.kt deleted file mode 100644 index 8aa3d621..00000000 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/PlatformFileSystemOperations.linuxX64.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem - -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.FileSystemOperation -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.checkaccess.CheckAccess -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chmod.Chmod -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chmod.ChmodFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chown.Chown -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.chown.ChownFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.close.CloseFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.cwd.GetCurrentWorkingDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.AddAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.lock.RemoveAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.mkdir.Mkdir -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readlink.ReadLink -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.ReadFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.readwrite.WriteFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.seek.SeekFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.settimestamp.SetTimestamp -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.settimestamp.SetTimestampFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.Stat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.sync.SyncFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.truncate.TruncateFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.unlink.UnlinkDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.unlink.UnlinkFile -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxAddAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChmodFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxChownFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxGetCurrentWorkingDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxOpen -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxReadFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxRemoveAdvisoryLockFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSeekFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSetTimestampFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxSync -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxTruncateFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxWriteFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64CheckAccess -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64Chmod -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64Chown -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64Mkdir -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64ReadLink -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64SetTimestamp -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64Stat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64UnlinkDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64UnlinkFile -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.PosixCloseFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler - -internal actual fun createPlatformFileSystemOperations( - fsState: PosixFileSystemState, -): Map, PosixOperationHandler<*, *, *>> = mapOf( - Open to LinuxOpen(fsState), - CloseFd to PosixCloseFd(fsState), - AddAdvisoryLockFd to LinuxAddAdvisoryLockFd, - RemoveAdvisoryLockFd to LinuxRemoveAdvisoryLockFd, - CheckAccess to LinuxX64CheckAccess, - Chmod to LinuxX64Chmod, - ChmodFd to LinuxChmodFd, - Chown to LinuxX64Chown, - ChownFd to LinuxChownFd, - GetCurrentWorkingDirectory to LinuxGetCurrentWorkingDirectory, - Mkdir to LinuxX64Mkdir, - ReadFd to LinuxReadFd, - ReadLink to LinuxX64ReadLink, - SeekFd to LinuxSeekFd, - SetTimestamp to LinuxX64SetTimestamp, - SetTimestampFd to LinuxSetTimestampFd, - Stat to LinuxX64Stat, - StatFd to LinuxX64StatFd, - SyncFd to LinuxSync, - TruncateFd to LinuxTruncateFd, - UnlinkFile to LinuxX64UnlinkFile, - UnlinkDirectory to LinuxX64UnlinkDirectory, - WriteFd to LinuxWriteFd, -) diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStat.linuxX64.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStat.linuxX64.kt new file mode 100644 index 00000000..9baf4885 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStat.linuxX64.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import platform.posix.errno +import platform.posix.stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.FileModeType +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toStructTimespec +import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fstatat + +internal actual fun platformFstatat( + dirfd: Int, + path: String, + statFlags: Int, +): Either = memScoped { + val statBuf: stat = alloc() + val exitCode = fstatat( + dirfd, + path, + statBuf.ptr, + statFlags, + ) + return if (exitCode == 0) { + statBuf.toStructStat().right() + } else { + errno.left() + } +} + +internal fun stat.toStructStat(): StructStat = StructStat( + deviceId = st_dev, + inode = st_ino, + mode = FileModeType.fromLinuxModeType(st_mode), + links = st_nlink, + usedId = st_uid.toULong(), + groupId = st_gid.toULong(), + specialFileDeviceId = st_rdev, + size = st_size.toULong(), + blockSize = st_blksize.toULong(), + blocks = st_blocks.toULong(), + accessTime = st_atim.toStructTimespec(), + modificationTime = st_mtim.toStructTimespec(), + changeStatusTime = st_ctim.toStructTimespec(), +) diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStatFd.linuxX64.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStatFd.linuxX64.kt new file mode 100644 index 00000000..df87e5d5 --- /dev/null +++ b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxStatFd.linuxX64.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file + * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + * SPDX-License-Identifier: Apache-2.0 + */ + +package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix + +import arrow.core.Either +import arrow.core.left +import arrow.core.right +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import platform.posix.errno +import platform.posix.fstat +import platform.posix.stat +import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat + +internal actual fun platformFstatFd(fd: Int): Either = memScoped { + val statBuf: stat = alloc() + val exitCode = fstat( + fd, + statBuf.ptr, + ) + return if (exitCode == 0) { + statBuf.toStructStat().right() + } else { + errno.left() + } +} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Stat.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Stat.kt deleted file mode 100644 index bf02ffe9..00000000 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64Stat.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import arrow.core.Either -import arrow.core.left -import arrow.core.right -import kotlinx.cinterop.alloc -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.ptr -import platform.posix.errno -import platform.posix.stat -import platform.posix.timespec -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.FileModeType -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.Stat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructTimespec -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.AT_SYMLINK_NOFOLLOW -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.fstatat - -internal object LinuxX64Stat : PosixOperationHandler { - override fun invoke(input: Stat): Either = memScoped { - val statBuf: stat = alloc() - val exitCode = fstatat( - input.baseDirectory.toDirFd(), - input.path, - statBuf.ptr, - input.getStatFlags(), - ) - return if (exitCode == 0) { - statBuf.toStructStat().right() - } else { - errno.errnoToStatError(input).left() - } - } - - private fun Stat.getStatFlags(): Int = if (this.followSymlinks) { - 0 - } else { - AT_SYMLINK_NOFOLLOW - } - - internal fun stat.toStructStat(): StructStat = StructStat( - deviceId = st_dev, - inode = st_ino, - mode = FileModeType.fromLinuxModeType(st_mode), - links = st_nlink, - usedId = st_uid.toULong(), - groupId = st_gid.toULong(), - specialFileDeviceId = st_rdev, - size = st_size.toULong(), - blockSize = st_blksize.toULong(), - blocks = st_blocks.toULong(), - accessTime = st_atim.toStructTimespec(), - modificationTime = st_mtim.toStructTimespec(), - changeStatusTime = st_ctim.toStructTimespec(), - ) - - private fun timespec.toStructTimespec(): StructTimespec = StructTimespec( - seconds = this.tv_sec.toULong(), - nanoseconds = this.tv_nsec.toULong(), - ) -} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64StatFd.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64StatFd.kt deleted file mode 100644 index 7f60a556..00000000 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/LinuxX64StatFd.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import arrow.core.Either -import arrow.core.left -import arrow.core.right -import kotlinx.cinterop.alloc -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.ptr -import platform.posix.errno -import platform.posix.fstat -import platform.posix.stat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.error.StatError -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StatFd -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.stat.StructStat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.LinuxX64Stat.toStructStat -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixOperationHandler - -internal object LinuxX64StatFd : PosixOperationHandler { - override fun invoke(input: StatFd): Either = memScoped { - val statBuf: stat = alloc() - val exitCode = fstat( - input.fd.fd, - statBuf.ptr, - ) - return if (exitCode == 0) { - statBuf.toStructStat().right() - } else { - errno.errnoToStatFdError(input).left() - } - } -} diff --git a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/SyscallOpenat2.linuxX64.kt b/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/SyscallOpenat2.linuxX64.kt deleted file mode 100644 index 4b3e9bcf..00000000 --- a/wasi-emscripten-fs/src/linuxX64Main/kotlin/posix/SyscallOpenat2.linuxX64.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import kotlinx.cinterop.alloc -import kotlinx.cinterop.cstr -import kotlinx.cinterop.memScoped -import kotlinx.cinterop.ptr -import kotlinx.cinterop.sizeOf -import platform.posix.errno -import platform.posix.memset -import platform.posix.syscall -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.BaseDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.FileMode -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.ext.toDirFd -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_BENEATH -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_CACHED -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_IN_ROOT -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_MAGICLINKS -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_SYMLINKS -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.RESOLVE_NO_XDEV -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.SYS_openat2 -import ru.pixnews.wasm.sqlite.open.helper.host.platform.linux.open_how - -internal actual fun syscallOpenat2( - pathname: String, - baseDirectory: BaseDirectory, - openFlags: ULong, - openMode: FileMode, - resolveMode: Set, -): Long = memScoped { - val openHow: open_how = alloc { - memset(this.ptr, 0, sizeOf().toULong()) - flags = openFlags - mode = openMode.mask.toULong() - resolve = resolveMode.toResolveMask() - } - val errorOrFd = syscall( - __sysno = SYS_openat2.toLong(), - baseDirectory.toDirFd(), - pathname.cstr, - openHow.ptr, - sizeOf().toULong(), - ) - return if (errorOrFd < 0) { - -errno.toLong() - } else { - errorOrFd - } -} - -private fun Set.toResolveMask(): ULong { - var mask = 0UL - if (contains(ResolveModeFlag.RESOLVE_BENEATH)) { - mask = mask and RESOLVE_BENEATH.toULong() - } - if (contains(ResolveModeFlag.RESOLVE_IN_ROOT)) { - mask = mask and RESOLVE_IN_ROOT.toULong() - } - if (contains(ResolveModeFlag.RESOLVE_NO_MAGICLINKS)) { - mask = mask and RESOLVE_NO_MAGICLINKS.toULong() - } - if (contains(ResolveModeFlag.RESOLVE_NO_SYMLINKS)) { - mask = mask and RESOLVE_NO_SYMLINKS.toULong() - } - if (contains(ResolveModeFlag.RESOLVE_NO_XDEV)) { - mask = mask and RESOLVE_NO_XDEV.toULong() - } - if (contains(ResolveModeFlag.RESOLVE_CACHED)) { - mask = mask and RESOLVE_CACHED.toULong() - } - return mask -} diff --git a/wasi-emscripten-fs/src/linuxX64Test/kotlin/Dummy.kt b/wasi-emscripten-fs/src/linuxX64Test/kotlin/Dummy.kt deleted file mode 100644 index 8a3a9e50..00000000 --- a/wasi-emscripten-fs/src/linuxX64Test/kotlin/Dummy.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -@file:Suppress("FILE_CONTAINS_ONLY_COMMENTS", "FILE_NO_BLANK_LINE_BETWEEN_BLOCKS") - -// Workaround for https://youtrack.jetbrains.com/issue/KTIJ-15797 -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem diff --git a/wasi-emscripten-fs/src/linuxX64Test/kotlin/posix/LinuxOpenTestCommon.kt b/wasi-emscripten-fs/src/linuxX64Test/kotlin/posix/LinuxOpenTestCommon.kt deleted file mode 100644 index e87ba4d4..00000000 --- a/wasi-emscripten-fs/src/linuxX64Test/kotlin/posix/LinuxOpenTestCommon.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2024, the wasm-sqlite-open-helper project authors and contributors. Please see the AUTHORS file - * for details. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - * SPDX-License-Identifier: Apache-2.0 - */ - -package ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix - -import assertk.all -import assertk.assertThat -import assertk.assertions.containsOnly -import assertk.assertions.isNotNull -import kotlinx.io.files.Path -import platform.posix.close -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.BaseDirectory -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.model.FileMode -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.Open -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.op.opencreate.OpenFileFlags -import ru.pixnews.wasm.sqlite.open.helper.host.filesystem.posix.base.PosixFileSystemState -import ru.pixnews.wasm.sqlite.test.utils.TempFolder -import ru.pixnews.wasm.sqlite.test.utils.TestLogger -import ru.pixnews.wasm.sqlite.test.utils.absolutePath -import ru.pixnews.wasm.sqlite.test.utils.assertions.FileModeBit.USER_EXECUTE -import ru.pixnews.wasm.sqlite.test.utils.assertions.FileModeBit.USER_READ -import ru.pixnews.wasm.sqlite.test.utils.assertions.FileModeBit.USER_WRITE -import ru.pixnews.wasm.sqlite.test.utils.assertions.fileMode -import ru.pixnews.wasm.sqlite.test.utils.assertions.isEmpty -import ru.pixnews.wasm.sqlite.test.utils.assertions.isRegularFile -import kotlin.test.AfterTest -import kotlin.test.BeforeTest -import kotlin.test.Test - -class LinuxOpenTestCommon { - lateinit var tempFolder: TempFolder - - @BeforeTest - fun setup() { - tempFolder = TempFolder.create() - } - - @AfterTest - fun cleanup() { - tempFolder.delete() - } - - @Test - fun create_file_with_absolute_path_should_work() { - val fsState = PosixFileSystemState(TestLogger()) - val linuxOpen = LinuxOpen(fsState) - - val tempFileAbsolutePath = tempFolder.absolutePath() - val testFile = Path(tempFileAbsolutePath, "file.test") - - val request = Open( - path = testFile.toString(), - baseDirectory = BaseDirectory.None, - flags = OpenFileFlags(OpenFileFlags.O_CREAT or OpenFileFlags.O_WRONLY), - mode = FileMode(0b111_000_000U), - ) - - val newFd = linuxOpen.invoke(request).getOrNull()?.let { - close(it.fd) - } - - assertThat(newFd).isNotNull() - assertThat(testFile).all { - isRegularFile() - isEmpty() - fileMode().containsOnly(USER_READ, USER_WRITE, USER_EXECUTE) - } - } -}