Ferricstore.FS (ferricstore v0.10.1)

Copy Markdown View Source

Thin Elixir wrapper over Ferricstore.Bitcask.NIF.fs_* that:

  • Preserves bang-style raise semantics (touch!, mkdir_p!, rm!, rm_rf!) matching File.* call sites we're replacing.
  • Keeps the non-bang variants returning :ok | {:error, {kind, msg}} so callers using with / case can pattern-match on the stable atom kinds.

Metadata ops and bounded file reads run on DirtyIo, while recursive removal runs on Tokio's blocking pool. This keeps filesystem work off Normal schedulers.

For potentially long operations (rm_rf of a large tree), the caller owns the waiting: fs_rm_rf_async returns immediately and delivers a :tokio_complete message. The rm_rf!/1 helper here blocks the calling process until the message arrives — keeping the call-site shape compatible with File.rm_rf!/1.

Summary

Types

err_kind()

@type err_kind() ::
  :not_found
  | :already_exists
  | :permission_denied
  | :not_a_directory
  | :is_a_directory
  | :directory_not_empty
  | :invalid_path
  | :symlink
  | :insecure_permissions
  | :too_large
  | :other

fs_error()

@type fs_error() :: {:error, {err_kind(), binary()}}

Functions

append_sync_nofollow(path, payload)

@spec append_sync_nofollow(binary(), binary()) :: :ok | fs_error()

append_sync_nofollow_bounded(path, payload, max_bytes)

@spec append_sync_nofollow_bounded(binary(), binary(), non_neg_integer()) ::
  :ok | fs_error()

atomic_replace_nofollow(path, payload, max_bytes)

@spec atomic_replace_nofollow(binary(), binary(), non_neg_integer()) ::
  :ok | fs_error()

copy_sync_nofollow(source, dest)

@spec copy_sync_nofollow(binary(), binary()) :: :ok | fs_error()

dir?(path)

@spec dir?(binary()) :: boolean()

exists?(path)

@spec exists?(binary()) :: boolean()

ls(path)

@spec ls(binary()) :: {:ok, [binary()]} | fs_error()

ls!(path)

@spec ls!(binary()) :: [binary()]

mkdir_p(path)

@spec mkdir_p(binary()) :: :ok | fs_error()

mkdir_p!(path)

@spec mkdir_p!(binary()) :: :ok

read_nofollow(path, max_bytes)

@spec read_nofollow(binary(), non_neg_integer()) :: {:ok, binary()} | fs_error()

read_private_nofollow(path, max_bytes)

@spec read_private_nofollow(binary(), non_neg_integer()) ::
  {:ok, binary()} | fs_error()

rename(old_path, new_path)

@spec rename(binary(), binary()) :: :ok | fs_error()

rename!(old_path, new_path)

@spec rename!(binary(), binary()) :: :ok

rm(path)

@spec rm(binary()) :: :ok | fs_error()

rm!(path)

@spec rm!(binary()) :: :ok

rm_rf(path)

@spec rm_rf(binary()) :: :ok | fs_error()

Recursive remove, blocking the caller until the async NIF completes.

Idempotent: removing a non-existent path is :ok. Never raises for missing paths — matches File.rm_rf/1 (returns {:ok, []} there).

rm_rf!(path)

@spec rm_rf!(binary()) :: :ok

touch(path)

@spec touch(binary()) :: :ok | fs_error()

touch!(path)

@spec touch!(binary()) :: :ok