Asynchronous file system operations for Kotlin built on libuv and based on the file system API for Node.js.
The datkt.fs
package an be installed with NPM.
$ npm install @datkt/fs
- Kotlin/Native and the
konanc
command line program.
## Compile a program in 'main.kt' and link fs.klib found in `node_modules/`
$ konanc main.kt $(konanc-config -clr node_modules/@datkt/fs)
where main.kt
might be
import datkt.fs.*
fun main(args: Array<String>) {
mkdir("./directory") { err ->
if (null != err) {
println("Failed to make directory: ${err.message}")
} else {
writeFile("./directory/file", "hello world") { err ->
if (null != err) {
println("Failed to write file: ${err.message}")
}
}
}
}
// kick off file system event loop
datkt.fs.loop.run()
}
- object loop
- fun access(path, mode, callback)
- fun chmod(path, mode, callback)
- fun chown(path, uid, gid, callback)
- fun lchown(path, uid, gid, callback)
- fun link(source, path, callback)
- fun symlink(source, path, type, callback)
- fun stat(path, callback)
- fun lstat(path, callback)
- fun mkdir(path, mode, callback)
- fun readdir(path, callback)
- fun open(path, flags, mode, callback)
- class Stats(...)
An object
that represents an interface into the
uv event loop used internally for
asynchronous work done by the functions exposed in this package.
datkt.fs.loop.run()
will invoke any queued work for the event loop.
object loop {
fun run(): Int
fun stop()
}
Invoke the uv event loop. Calls uv_run internally.
Stop the uv event loop. Calls uv_stop internally.
Test user permissions for a file specified at path
and mode
calling
callback
with an Error
if one errors.
access("/home") { err ->
if (null != err) {
println("Something went wrong checking access to /home")
}
}
The possible values for the mode
argument to test file access
permissions can be seen below.
F_OK
- Test for the existence of a fileR_OK
- Test for read permissions on a fileW_OK
- Test for write permissions on a fileX_OK
- Test for execution permissions on a file
Change user permissions of a file specified at path
and mode
calling
callback
with an Error
if one occurs.
// make read, write, execute permissions for everyone
val mode = (
S_IRUSR or S_IWUSR or S_IXUSR or
S_IRGRP or S_IWGRP or S_IXGRP or
S_IROTH or S_IWOTH or S_IXOTH
)
// modify program permissions
chmod("/home/program", mode) { err ->
if (null != err) {
println("Something went wrong changing program permissions: ${err.message}")
}
}
The possible values for the mode
argument can be seen below. They can
be grouped into a bit mask by the logical OR (or
) operator.
S_IRWXU
- Read, write, and execute by owner (700
)S_IRUSR
- Read by owner (400
)S_IWUSR
- Write by owner (200
)S_IXUSR
- Execute by owner (100
)S_IRWXG
- Read, write, and Execute by group (070
)S_IRGRP
- Read by group (040
)S_IWGRP
- Write by group (020
)S_IXGRP
- Execute by group (010
)S_IRWXO
- Read, write, and execute by others (007
)S_IROTH
- Read by others (004
)S_IWOTH
- Write by others (002
)S_IXOTH
- Execute by others (001
)
Change user and group ownership of a file specified at path
for user
id uid
, and group id gid
calling callback
with an Error
, if one
occurs.
chown("/home/file", 1000, 10) { err ->
if (null != err) {
println("Something went wrong changing file ownership: ${err.message}")
}
}
Change user and group ownership of a symbolic link specified at path
for
user id uid
, and group id gid
calling callback
with an Error
, if one
occurs.
symlink("/home/file", "/home/link") { err ->
lchown("/home/link", 1000, 10) { err ->
if (null != err) {
println("Something went wrong changing link ownership: ${err.message}")
}
}
}
Create a new hard link at path
for a file specified at source
calling callback
with an Error
, if one occurs.
link("/home/file", "/home/link") { err ->
if (null != err) {
println("Something went creating hard link: ${err.message}")
}
}
symlink("/home/file", "/home/symlink") { err ->
if (null != err) {
println("Something went creating soft link: ${err.message}")
}
}
Query the stats of a file specified at path
, if it exists, calling
callback
with an Error
, if one occurs, otherwise an instance of
Stats
as the second argument.
stat("/home/file") { err, stats ->
if (null != err) {
println(err.message)
} else {
println(stats)
}
}
Query the stats of a file specified at path
, if it is a link or file, calling
callback
with an Error
, if one occurs, otherwise an instance of
Stats
as the second argument.
lstat("/home/file") { err, stats ->
if (null != err) {
println(err.message)
} else {
println(stats)
}
}
Make a directory specified at path
with with mode
calling calling
with an Error
, if one occurs. The mode
defaults to
DEFAULT_MKDIR_MODE
(see below) if not specified.
mkdir("/path/to/directory") { err ->
if (null != err) {
println(err.message)
}
}
See File Modes for a list of all file modes.
The default mode is defined by the DEFAULT_MKDIR_MODE
constant.
val DEFAULT_MKDIR_MODE = (S_IRWXU or S_IRWXG or S_IRWXO)
Read a directory specified at path
for files entries calling
callback
with an Error
, if one occurs, otherwise an Array<String>
with file names.
readdir("/home") { err, entries, ->
for (entry in entries) {
println(entry)
}
}
Open a file specified at path
with optional flags and mode calling
callback
with an Error
, if one occurs, otherwise with a valid file
descriptor.
open("/path/to/file") { err, fd ->
if (null != err) {
println(err.message)
} else {
// do something with fd
}
}
By default, all files will be opened in DEFAULT_OPEN_MODE
where:
// equivalent to (0666)
val DEFAULT_OPEN_MODE = (
S_IRUSR or S_IWUSR or
S_IRGRP or S_IWGRP or
S_IROTH or S_IWOTH
)
"r"
- Open file for reading. An error occurs if the file does not exist."r+"
- Open file for reading and writing. An error occurs if the file does not exist."w"
- Open file for writing. The file is created if it does not exist, otherwise it is truncated."w+"
- Open file for reading and writing. The file is created if it does not exist, otherwise it is truncated."a"
- Open file for appending. Writes start at the end of the file. The file is created if it does not exist, otherwise it is truncated.
class Stats(
val dev: Long = 0,
val mode: Long = 0,
val nlink: Long = 0,
val uid: Long = 0,
val gid: Long = 0,
val rdev: Long = 0,
val ino: Long = 0,
val size: Long = 0,
val blksize: Long = 0,
val blocks: Long = 0,
val atime: Long = 0,
val mtime: Long = 0,
val ctime: Long = 0,
val birthtime: Long = 0
)
Check if a given mode is present in the stat's mode bit field.
if (stat.hasMode(S_IFREG)) {
// stat points to a regular file
}
Check if the stat points to a character
device.
Equivalent to stat.hasMode(S_IFCHR)
.
if (stat.isCharacterDevice()) {
// stat points to a character device
}
Check if the stat points to a symbolic link.
Equivalent to stat.hasMode(S_IFLNK)
.
if (stat.isSymbolicLink()) {
// stat points to a symbolic link
}
Check if the stat points to a block
device.
Equivalent to stat.hasMode(S_IFBLK)
.
if (stat.isBlockDevice()) {
// stat points to a block device
}
Check if the stat points to a directory. Equivalent to stat.hasMode(S_IFDIR)
.
if (stat.isDirectory()) {
// stat points to a directory
}
Check if the stat points to a socket. Equivalent to stat.hasMode(S_IFSOCK)
.
if (stat.isSocket()) {
// stat points to a socket
}
Check if the stat points to a FIFO.
Equivalent to stat.hasMode(S_IFIFO)
.
if (stat.isFIFO()) {
// stat points to a FIFO (named pipe)
}
Check if the stat points to a regular file.
Equivalent to stat.hasMode(S_IFREG)
.
if (stat.isFile()) {
// stat points to a file
}
MIT