This is an old revision of the document!
Table of Contents
lua_fs
lua_fs is a Lua loadable shared library that exposes the C++17 std::filesystem library through sol2. Paths can be passed as ordinary Lua strings or as fs.path objects. Filesystem failures raise a Lua error containing the operating-system error message.
API Reference
All examples assume:
local fs = require("lua_fs")
Paths may be Lua strings or fs.path objects. A function that encounters an operating-system error raises a Lua error. Boolean query functions return false for a missing path unless the underlying operation itself fails.
`fs.path`
fs.path(value) constructs a path object. value is optional for an empty path or can be a string/path value. Path objects are useful when several lexical operations are chained; filesystem functions accept them anywhere a string is accepted.
local path = fs.path("logs/app.2026.txt") print(path:parent_path(), path:stem(), path:extension())
Path methods
| Method | Description and result | Example |
|---|---|---|
path:string() | Returns the platform-native path representation as a string. | print(path:string()) |
path:generic_string() | Returns a portable representation using / separators. | print(path:generic_string()) |
path:filename() | Returns the final path component, or an empty string. | local name = path:filename() |
path:parent_path() | Returns the lexical parent path. | local folder = path:parent_path() |
path:root_name() | Returns a root name such as C: on Windows. | print(path:root_name()) |
path:root_directory() | Returns the root directory component, such as / or \\. | print(path:root_directory()) |
path:relative_path() | Returns the path with its root components removed. | print(path:relative_path()) |
path:stem() | Returns the filename without its final extension. | print(path:stem()) |
path:extension() | Returns the final extension, including its dot, or an empty string. | assert(path:extension() == ".txt") |
path:lexically_normal() | Returns a normalized path without accessing the filesystem. | local clean = path:lexically_normal() |
path:lexically_relative(base) | Returns the lexical path from base to path; it can be empty when no relative form exists. | print(path:lexically_relative("logs")) |
path:has_root_name() | Returns whether the path has a root name. | if path:has_root_name() then ... end |
path:has_root_directory() | Returns whether the path has a root directory. | print(path:has_root_directory()) |
path:has_parent_path() | Returns whether a parent component exists. | print(path:has_parent_path()) |
path:has_filename() | Returns whether a filename component exists. | print(path:has_filename()) |
path:has_stem() | Returns whether a stem component exists. | print(path:has_stem()) |
path:has_extension() | Returns whether an extension component exists. | print(path:has_extension()) |
path:is_absolute() | Returns whether the path is absolute according to the host platform. | print(path:is_absolute()) |
path:is_relative() | Returns whether the path is not absolute. | print(path:is_relative()) |
path:empty() | Returns whether the path contains no characters. | assert(not path:empty()) |
path:append(value) | Appends a path component using the platform separator and returns the same path object. | path:append("archive") |
path:concat(value) | Concatenates text without inserting a separator and returns the same path object. | path:concat(".bak") |
Path and environment functions
| Function | Description and result | Example |
|---|---|---|
fs.absolute(path) | Returns an absolute path without requiring the target to exist. | print(fs.absolute("data/input.txt")) |
fs.canonical(path) | Returns the fully resolved absolute path. Every component must exist. | print(fs.canonical("data")) |
fs.weakly_canonical(path) | Resolves existing components and permits a non-existing final portion. | print(fs.weakly_canonical("data/new.txt")) |
fs.relative(path, base) | Returns the path from base to path, using the current directory for omitted filesystem context. | print(fs.relative("data/a.txt", "data")) |
fs.proximate(path, base) | Returns relative(path, base), or an absolute path when a relative result is not possible. | print(fs.proximate("data/a.txt", "data")) |
fs.current_path() | Returns the process working directory. | print(fs.current_path()) |
fs.set_current_path(path) | Changes the process working directory. Returns no value. | fs.set_current_path("work") |
fs.temp_directory_path() | Returns the operating system temporary directory. | local temp = fs.temp_directory_path() |
fs.directory(path) | Returns a 1-based Lua array of immediate child paths. | for _, p in ipairs(fs.directory("data")) do print(p) end |
fs.recursive_directory(path) | Returns a 1-based Lua array containing all descendants recursively. | for _, p in ipairs(fs.recursive_directory("data")) do print(p) end |
Queries and metadata
| Function | Description and result | Example |
|---|---|---|
fs.exists(path) | Returns true when the path exists, including a symlink target check. | if fs.exists("config.lua") then ... end |
fs.equivalent(left, right) | Returns whether two existing paths refer to the same filesystem object. | print(fs.equivalent("a", "b")) |
fs.status(path) | Returns metadata after following symlinks. | local info = fs.status("file.txt") |
fs.symlink_status(path) | Returns metadata for the link itself without following a symlink. | local info = fs.symlink_status("link") |
fs.is_block_file(path) | Returns whether the path is a block device. | print(fs.is_block_file(path)) |
fs.is_character_file(path) | Returns whether the path is a character device. | print(fs.is_character_file(path)) |
fs.is_fifo(path) | Returns whether the path is a named pipe/FIFO. | print(fs.is_fifo(path)) |
fs.is_other(path) | Returns whether the path exists but is not a regular file, directory, or symlink. | print(fs.is_other(path)) |
fs.is_socket(path) | Returns whether the path is a socket where the platform supports that type. | print(fs.is_socket(path)) |
fs.is_symlink(path) | Returns whether the path is a symbolic link. | print(fs.is_symlink(path)) |
fs.is_regular_file(path) | Returns whether the path is a regular file. | assert(fs.is_regular_file("file.txt")) |
fs.is_directory(path) | Returns whether the path is a directory. | if fs.is_directory(path) then ... end |
fs.file_size(path) | Returns the file size in bytes. The path must refer to a regular file. | print(fs.file_size("file.txt")) |
fs.hard_link_count(path) | Returns the number of hard links to the filesystem object. | print(fs.hard_link_count("file.txt")) |
fs.last_write_time(path) | Returns the last modification time as Unix seconds. | print(os.date("%F", fs.last_write_time(path))) |
fs.set_last_write_time(path, seconds) | Sets the last modification time from Unix seconds. Returns no value. | fs.set_last_write_time(path, os.time()) |
fs.space(path) | Returns { capacity, free, available }, measured in bytes, for the filesystem containing path. | print(fs.space(".").available) |
status and symlink_status return a table with these fields:
local info = fs.status("file.txt") print(info.type, info.permissions) print(info.exists, info.is_regular_file, info.is_directory, info.is_symlink)
type is the numeric C++ file-type value and permissions is the numeric permission bitmask. Use the fs.perms constants below when interpreting or changing that mask.
Filesystem mutations
| Function | Description and result | Example |
|---|---|---|
fs.create_directory(path) | Creates one directory. Returns true if created and false if it already existed. | fs.create_directory("output") |
fs.create_directories(path) | Creates a directory and any missing parents. Returns true if anything was created. | fs.create_directories("output/images") |
fs.remove(path) | Removes one file, empty directory, or symlink. Returns true if removed. | fs.remove("output/old.txt") |
fs.remove_all(path) | Recursively removes a path and its contents. Returns the number of removed filesystem objects. | print(fs.remove_all("output")) |
fs.rename(from, to) | Renames or moves a filesystem object. Returns no value. | fs.rename("draft.txt", "final.txt") |
fs.copy(from, to, options) | Copies a file or directory according to fs.copy_options. Returns no value. | fs.copy("assets", "backup", fs.copy_options.recursive) |
fs.copy_file(from, to, options) | Copies one file and returns true when the copy succeeds. | fs.copy_file("a.txt", "b.txt", fs.copy_options.overwrite_existing) |
fs.resize_file(path, size) | Changes a regular file to size bytes. Returns no value. | fs.resize_file("cache.bin", 0) |
fs.create_hard_link(existing, link) | Creates a hard link named link to existing. Returns no value. | fs.create_hard_link("a.txt", "a-link.txt") |
fs.create_symlink(existing, link) | Creates a symbolic link. On Windows, the process may need symlink privileges. Returns no value. | fs.create_symlink("a.txt", "a-link.txt") |
fs.create_directory_symlink(existing, link) | Creates a symbolic link specifically for a directory. Returns no value. | fs.create_directory_symlink("assets", "assets-link") |
fs.permissions(path, bits, options) | Replaces, adds, or removes permission bits. Use fs.perms and fs.perm_options. Returns no value. | fs.permissions("private.txt", fs.perms.owner_read, fs.perm_options.replace) |
Option and permission constants
fs.copy_options contains the flags accepted by copy and copy_file:
| Constant | Meaning |
|---|---|
none | Use default copy behavior. |
skip_existing | Keep an existing destination. |
overwrite_existing | Replace an existing destination. |
update_existing | Replace only when the source is newer. |
recursive | Copy directory contents recursively. |
copy_symlinks | Copy symlinks as symlinks. |
skip_symlinks | Do not copy symlinks. |
directories_only | Copy directory structure without regular files. |
create_symlinks | Create symlinks instead of copies. |
create_hard_links | Create hard links instead of copies. |
fs.perms contains the standard permission bits: owner_read, owner_write, owner_exec, group_read, group_write, group_exec, others_read, others_write, others_exec, all, set_uid, set_gid, and sticky_bit.
fs.perm_options contains replace, add, and remove:
fs.permissions("script.sh", fs.perms.owner_exec, fs.perm_options.add) fs.permissions("script.sh", fs.perms.others_write, fs.perm_options.remove)
