JustBash.Fs.InMemoryFs (JustBash v0.1.0)
View SourceIn-memory filesystem implementation for JustBash.
Provides a complete virtual filesystem with support for:
- Files (with binary content)
- Directories
- Symbolic links
- File permissions (mode)
- Modification times
All operations are synchronous and work on an in-memory data structure.
Summary
Functions
Append content to a file, creating it if it doesn't exist.
Get the base name (file name) of a path.
Change file/directory permissions.
Copy a file or directory.
Get the directory name (parent path) of a path.
Check if a path exists in the filesystem.
Get all paths in the filesystem.
Create a hard link.
Get the stat information for a path (does NOT follow symlinks).
Create a directory.
Move/rename a file or directory.
Create a new in-memory filesystem with optional initial files.
Normalize a filesystem path.
Read the contents of a file.
Read directory contents.
Read the target of a symbolic link.
Resolve a path relative to a base path.
Remove a file or directory.
Get the stat information for a path (follows symlinks).
Create a symbolic link.
Write content to a file, creating it if it doesn't exist.
Types
@type cp_opts() :: [{:recursive, boolean()}]
@type directory_entry() :: %{ type: :directory, mode: non_neg_integer(), mtime: DateTime.t() }
@type file_entry() :: %{ type: :file, content: binary(), mode: non_neg_integer(), mtime: DateTime.t() }
@type fs_entry() :: file_entry() | directory_entry() | symlink_entry()
@type mkdir_opts() :: [{:recursive, boolean()}]
@type stat_result() :: %{ is_file: boolean(), is_directory: boolean(), is_symbolic_link: boolean(), mode: non_neg_integer(), size: non_neg_integer(), mtime: DateTime.t() }
@type symlink_entry() :: %{ type: :symlink, target: String.t(), mode: non_neg_integer(), mtime: DateTime.t() }
@type write_opts() :: [mode: non_neg_integer(), mtime: DateTime.t()]
Functions
Append content to a file, creating it if it doesn't exist.
Get the base name (file name) of a path.
Examples
iex> InMemoryFs.basename("/home/user/file.txt")
"file.txt"
@spec chmod(t(), String.t(), non_neg_integer()) :: {:ok, t()} | {:error, :enoent}
Change file/directory permissions.
Copy a file or directory.
Options
:recursive- copy directory contents recursively (required for directories)
Returns
{:ok, updated_fs}on success{:error, :enoent}if source doesn't exist{:error, :eisdir}if source is directory and not recursive
Get the directory name (parent path) of a path.
Examples
iex> InMemoryFs.dirname("/home/user/file.txt")
"/home/user"
iex> InMemoryFs.dirname("/file.txt")
"/"
Check if a path exists in the filesystem.
Examples
iex> fs = InMemoryFs.new(%{"/file.txt" => "hello"})
iex> InMemoryFs.exists?(fs, "/file.txt")
true
iex> InMemoryFs.exists?(fs, "/nonexistent")
false
Get all paths in the filesystem.
Create a hard link.
@spec lstat(t(), String.t()) :: {:ok, stat_result()} | {:error, :enoent}
Get the stat information for a path (does NOT follow symlinks).
@spec mkdir(t(), String.t(), mkdir_opts()) :: {:ok, t()} | {:error, :eexist | :enoent}
Create a directory.
Options
:recursive- create parent directories if needed (default: false)
Returns
{:ok, updated_fs}on success{:error, :eexist}if path already exists (and not recursive with existing dir){:error, :enoent}if parent doesn't exist (and not recursive)
Move/rename a file or directory.
Create a new in-memory filesystem with optional initial files.
Options
Initial files can be provided as a map:
- Simple form:
%{"/path/to/file" => "content"} - Extended form:
%{"/path/to/file" => %{content: "content", mode: 0o755, mtime: ~U[...]}}
Examples
iex> fs = InMemoryFs.new()
iex> fs = InMemoryFs.new(%{"/home/user/file.txt" => "hello"})
iex> fs = InMemoryFs.new(%{"/bin/script" => %{content: "#!/bin/bash", mode: 0o755}})
Normalize a filesystem path.
Handles:
- Empty paths and "/" -> "/"
- Trailing slashes removal
- Resolving "." and ".." components
- Ensuring leading "/"
Examples
iex> InMemoryFs.normalize_path("/home/user/../user/./file")
"/home/user/file"
Read the contents of a file.
Returns
{:ok, content}- binary content of the file{:error, :enoent}- file does not exist{:error, :eisdir}- path is a directory{:error, :eloop}- too many symlink levels
Read directory contents.
Returns
{:ok, entries}- list of entry names (not full paths), sorted{:error, :enoent}- directory does not exist{:error, :enotdir}- path is not a directory
Read the target of a symbolic link.
Resolve a path relative to a base path.
Examples
iex> InMemoryFs.resolve_path("/home/user", "file.txt")
"/home/user/file.txt"
iex> InMemoryFs.resolve_path("/home/user", "/etc/passwd")
"/etc/passwd"
Remove a file or directory.
Options
:recursive- remove directory contents recursively (default: false):force- don't error if path doesn't exist (default: false)
Returns
{:ok, updated_fs}on success{:error, :enoent}if path doesn't exist (and not force){:error, :enotempty}if directory has contents (and not recursive)
@spec stat(t(), String.t()) :: {:ok, stat_result()} | {:error, :enoent}
Get the stat information for a path (follows symlinks).
Returns
{:ok, stat} with stat containing:
:is_file- boolean:is_directory- boolean:is_symbolic_link- always false (stat follows symlinks):mode- file permissions:size- byte size (0 for directories):mtime- modification time
Errors
{:error, :enoent}- path does not exist
Create a symbolic link.
@spec write_file(t(), String.t(), binary(), write_opts()) :: {:ok, t()} | {:error, :eisdir}
Write content to a file, creating it if it doesn't exist.
Parent directories are created automatically.
Options
:mode- file permissions (default: 0o644):mtime- modification time (default: now)
Returns
{:ok, updated_fs}on success{:error, :eisdir}if path is a directory