-module(fio). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/fio.gleam"). -export([read/1, read_bits/1, write/2, write_bits/2, append/2, append_bits/2, write_atomic/2, write_bits_atomic/2, delete/1, delete_directory/1, delete_all/1, exists/1, file_info/1, link_info/1, is_directory/1, is_file/1, is_symlink/1, copy/2, rename/2, create_symlink/2, create_hard_link/2, read_link/1, set_permissions/2, set_permissions_octal/2, create_directory/1, create_directory_all/1, list/1, current_directory/0, tmp_dir/0, touch/1, with_temp_file/1, with_temp_directory/1, list_recursive/1, copy_directory/2, ensure_file/1, copy_if_newer/2, read_fold/4, checksum/2, verify_checksum/3, join/2, split/1, base_name/1, directory_name/1, extension/1, strip_extension/1, stem/1, with_extension/2, join_all/1, is_absolute/1, expand/1, safe_relative/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/fio.gleam", 12). ?DOC(" Read a UTF-8 text file. Returns `NotUtf8(path)` on invalid UTF-8.\n"). -spec read(binary()) -> {ok, binary()} | {error, fio@error:fio_error()}. read(Path) -> fio@internal@io:read(Path). -file("src/fio.gleam", 17). ?DOC(" Read a file as raw bytes (`BitArray`).\n"). -spec read_bits(binary()) -> {ok, bitstring()} | {error, fio@error:fio_error()}. read_bits(Path) -> fio@internal@io:read_bits(Path). -file("src/fio.gleam", 24). ?DOC(" Write UTF-8 text to a file (creates/overwrites).\n"). -spec write(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. write(Path, Content) -> fio@internal@io:write(Path, Content). -file("src/fio.gleam", 29). ?DOC(" Write raw bytes (`BitArray`) to a file (creates/overwrites).\n"). -spec write_bits(binary(), bitstring()) -> {ok, nil} | {error, fio@error:fio_error()}. write_bits(Path, Content) -> fio@internal@io:write_bits(Path, Content). -file("src/fio.gleam", 34). ?DOC(" Append UTF-8 text to a file (creates if missing).\n"). -spec append(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. append(Path, Content) -> fio@internal@io:append(Path, Content). -file("src/fio.gleam", 39). ?DOC(" Append raw bytes (`BitArray`) to a file.\n"). -spec append_bits(binary(), bitstring()) -> {ok, nil} | {error, fio@error:fio_error()}. append_bits(Path, Content) -> fio@internal@io:append_bits(Path, Content). -file("src/fio.gleam", 46). ?DOC( " Write UTF-8 text atomically: writes to a sibling temp file, then renames\n" " it into place with a single `rename(2)` syscall.\n" " Readers never observe partial content. Returns `AtomicFailed` on error.\n" ). -spec write_atomic(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. write_atomic(Path, Content) -> fio@internal@io:write_atomic(Path, Content). -file("src/fio.gleam", 52). ?DOC( " Write raw bytes (`BitArray`) atomically.\n" " Same atomic guarantee as `write_atomic`.\n" ). -spec write_bits_atomic(binary(), bitstring()) -> {ok, nil} | {error, fio@error:fio_error()}. write_bits_atomic(Path, Content) -> fio@internal@io:write_bits_atomic(Path, Content). -file("src/fio.gleam", 62). ?DOC(" Delete a file (not a directory).\n"). -spec delete(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. delete(Path) -> fio@internal@io:delete_file(Path). -file("src/fio.gleam", 67). ?DOC(" Delete an empty directory.\n"). -spec delete_directory(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. delete_directory(Path) -> fio@internal@io:delete_directory(Path). -file("src/fio.gleam", 72). ?DOC(" Delete a path recursively; idempotent (succeeds if missing).\n"). -spec delete_all(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. delete_all(Path) -> fio@internal@io:delete_recursive(Path). -file("src/fio.gleam", 79). ?DOC(" Check if a path exists (file, directory, or symlink).\n"). -spec exists(binary()) -> boolean(). exists(Path) -> fio@internal@io:exists(Path). -file("src/fio.gleam", 84). ?DOC(" Get file metadata (follows symlinks).\n"). -spec file_info(binary()) -> {ok, fio@types:file_info()} | {error, fio@error:fio_error()}. file_info(Path) -> fio@internal@io:file_info(Path). -file("src/fio.gleam", 89). ?DOC(" Get file metadata without following symlinks.\n"). -spec link_info(binary()) -> {ok, fio@types:file_info()} | {error, fio@error:fio_error()}. link_info(Path) -> fio@internal@io:link_info(Path). -file("src/fio.gleam", 94). ?DOC(" Check if a path is a directory (follows symlinks).\n"). -spec is_directory(binary()) -> {ok, boolean()} | {error, fio@error:fio_error()}. is_directory(Path) -> fio@internal@io:is_directory(Path). -file("src/fio.gleam", 99). ?DOC(" Check if a path is a regular file (follows symlinks).\n"). -spec is_file(binary()) -> {ok, boolean()} | {error, fio@error:fio_error()}. is_file(Path) -> fio@internal@io:is_file(Path). -file("src/fio.gleam", 104). ?DOC(" Check if a path is a symbolic link (does not follow symlinks).\n"). -spec is_symlink(binary()) -> {ok, boolean()} | {error, fio@error:fio_error()}. is_symlink(Path) -> fio@internal@io:is_symlink(Path). -file("src/fio.gleam", 111). ?DOC(" Copy a file from source to destination.\n"). -spec copy(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. copy(Src, Dest) -> fio@internal@io:copy_file(Src, Dest). -file("src/fio.gleam", 116). ?DOC(" Rename or move a file or directory.\n"). -spec rename(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. rename(Src, Dest) -> fio@internal@io:rename(Src, Dest). -file("src/fio.gleam", 123). ?DOC(" Create a symbolic link.\n"). -spec create_symlink(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. create_symlink(Target, Link) -> fio@internal@io:create_symlink(Target, Link). -file("src/fio.gleam", 131). ?DOC(" Create a hard link to an existing file.\n"). -spec create_hard_link(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. create_hard_link(Target, Link) -> fio@internal@io:create_hard_link(Target, Link). -file("src/fio.gleam", 139). ?DOC(" Read the target path of a symbolic link.\n"). -spec read_link(binary()) -> {ok, binary()} | {error, fio@error:fio_error()}. read_link(Path) -> fio@internal@io:read_link(Path). -file("src/fio.gleam", 146). ?DOC(" Set file permissions using the `FilePermissions` type.\n"). -spec set_permissions(binary(), fio@types:file_permissions()) -> {ok, nil} | {error, fio@error:fio_error()}. set_permissions(Path, Permissions) -> fio@internal@io:set_permissions(Path, Permissions). -file("src/fio.gleam", 154). ?DOC(" Set file permissions with an octal integer.\n"). -spec set_permissions_octal(binary(), integer()) -> {ok, nil} | {error, fio@error:fio_error()}. set_permissions_octal(Path, Mode) -> fio@internal@io:set_permissions_octal(Path, Mode). -file("src/fio.gleam", 161). ?DOC(" Create a directory. Parent directory must exist.\n"). -spec create_directory(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. create_directory(Path) -> fio@internal@io:create_directory(Path). -file("src/fio.gleam", 166). ?DOC(" Create a directory and all parent directories.\n"). -spec create_directory_all(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. create_directory_all(Path) -> fio@internal@io:create_directory_all(Path). -file("src/fio.gleam", 171). ?DOC(" List the contents of a directory (names only).\n"). -spec list(binary()) -> {ok, list(binary())} | {error, fio@error:fio_error()}. list(Path) -> fio@internal@io:list_directory(Path). -file("src/fio.gleam", 178). ?DOC(" Get the current working directory.\n"). -spec current_directory() -> {ok, binary()} | {error, fio@error:fio_error()}. current_directory() -> fio@internal@io:current_directory(). -file("src/fio.gleam", 183). ?DOC(" Get the system temporary directory path.\n"). -spec tmp_dir() -> binary(). tmp_dir() -> fio@internal@io:tmp_dir(). -file("src/fio.gleam", 188). ?DOC(" Touch a file: create or update modification time.\n"). -spec touch(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. touch(Path) -> fio@internal@io:touch(Path). -file("src/fio.gleam", 196). ?DOC( " Run a callback with a path to a temporary file that is automatically\n" " deleted when the callback returns (even if it returns an Error).\n" ). -spec with_temp_file( fun((binary()) -> {ok, ETI} | {error, fio@error:fio_error()}) ) -> {ok, ETI} | {error, fio@error:fio_error()}. with_temp_file(Callback) -> Path = fio@path:join( fio@internal@io:tmp_dir(), fio_ffi:unique_name(<<"fio_tmp_file_"/utf8>>) ), Result = Callback(Path), _ = fio@internal@io:delete_file(Path), Result. -file("src/fio.gleam", 209). ?DOC( " Run a callback with a path to a temporary directory that is automatically\n" " deleted (recursively) when the callback returns.\n" ). -spec with_temp_directory( fun((binary()) -> {ok, ETN} | {error, fio@error:fio_error()}) ) -> {ok, ETN} | {error, fio@error:fio_error()}. with_temp_directory(Callback) -> Path = fio@path:join( fio@internal@io:tmp_dir(), fio_ffi:unique_name(<<"fio_tmp_dir_"/utf8>>) ), Result = begin _pipe = fio@internal@io:create_directory(Path), gleam@result:'try'(_pipe, fun(_) -> Callback(Path) end) end, _ = fio@internal@io:delete_recursive(Path), Result. -file("src/fio.gleam", 225). ?DOC(" Recursively list files and directories (paths relative to `path`).\n"). -spec list_recursive(binary()) -> {ok, list(binary())} | {error, fio@error:fio_error()}. list_recursive(Path) -> fio@recursive:list_recursive(Path). -file("src/fio.gleam", 230). ?DOC(" Recursively copy a directory and its contents.\n"). -spec copy_directory(binary(), binary()) -> {ok, nil} | {error, fio@error:fio_error()}. copy_directory(Src, Dest) -> fio@recursive:copy_directory(Src, Dest). -file("src/fio.gleam", 238). ?DOC( " Create a file if it does not already exist.\n" " If the file already exists this is a no-op and returns `Ok(Nil)`.\n" ). -spec ensure_file(binary()) -> {ok, nil} | {error, fio@error:fio_error()}. ensure_file(Path) -> case fio@internal@io:exists(Path) of true -> {ok, nil}; false -> fio@internal@io:write(Path, <<""/utf8>>) end. -file("src/fio.gleam", 249). ?DOC( " Copy `src` to `dest` only when `src` is newer than `dest`.\n" "\n" " If `dest` does not exist the copy always happens.\n" " Returns `Ok(True)` when a copy was performed, `Ok(False)` when skipped.\n" ). -spec copy_if_newer(binary(), binary()) -> {ok, boolean()} | {error, fio@error:fio_error()}. copy_if_newer(Src, Dest) -> gleam@result:'try'( fio@internal@io:file_info(Src), fun(Src_info) -> case fio@internal@io:file_info(Dest) of {error, enoent} -> gleam@result:'try'( fio@internal@io:copy_file(Src, Dest), fun(_) -> {ok, true} end ); {error, E} -> {error, E}; {ok, Dest_info} -> case erlang:element(10, Src_info) > erlang:element( 10, Dest_info ) of false -> {ok, false}; true -> gleam@result:'try'( fio@internal@io:copy_file(Src, Dest), fun(_) -> {ok, true} end ) end end end ). -file("src/fio.gleam", 281). ?DOC( " Read a file in chunks, folding each chunk into an accumulator.\n" "\n" " Opens the file, reads it in `chunk_size`-byte pieces, and calls `f` on each\n" " chunk until EOF. The file handle is always closed before returning.\n" "\n" " ```gleam\n" " // Count bytes without loading the whole file into memory\n" " fio.read_fold(\"big.bin\", 65_536, 0, fn(acc, chunk) {\n" " acc + bit_array.byte_size(chunk)\n" " })\n" " ```\n" ). -spec read_fold(binary(), integer(), EUB, fun((EUB, bitstring()) -> EUB)) -> {ok, EUB} | {error, fio@error:fio_error()}. read_fold(Path, Chunk_size, Initial, F) -> fio@handle:with( Path, read_only, fun(H) -> fio@handle:fold_chunks(H, Chunk_size, Initial, F) end ). -file("src/fio.gleam", 295). ?DOC( " Compute a file checksum using the specified algorithm.\n" " Returns a hex-encoded string.\n" ). -spec checksum(binary(), fio@types:hash_algorithm()) -> {ok, binary()} | {error, fio@error:fio_error()}. checksum(Path, Algorithm) -> Algo_str = case Algorithm of sha256 -> <<"sha256"/utf8>>; sha512 -> <<"sha512"/utf8>>; md5 -> <<"md5"/utf8>> end, fio@internal@io:checksum(Path, Algo_str). -file("src/fio.gleam", 308). ?DOC(" Verify that a file's checksum matches the expected hex-encoded hash.\n"). -spec verify_checksum(binary(), binary(), fio@types:hash_algorithm()) -> {ok, boolean()} | {error, fio@error:fio_error()}. verify_checksum(Path, Expected, Algorithm) -> _pipe = checksum(Path, Algorithm), gleam@result:map(_pipe, fun(Actual) -> Actual =:= Expected end). -file("src/fio.gleam", 320). ?DOC(" Join two path segments.\n"). -spec join(binary(), binary()) -> binary(). join(Left, Right) -> fio@path:join(Left, Right). -file("src/fio.gleam", 325). ?DOC(" Split a path into its segments.\n"). -spec split(binary()) -> list(binary()). split(Path_str) -> fio@path:split(Path_str). -file("src/fio.gleam", 330). ?DOC(" Get the base name (filename) of a path.\n"). -spec base_name(binary()) -> binary(). base_name(Path_str) -> fio@path:base_name(Path_str). -file("src/fio.gleam", 335). ?DOC(" Get the directory portion of a path.\n"). -spec directory_name(binary()) -> binary(). directory_name(Path_str) -> fio@path:directory_name(Path_str). -file("src/fio.gleam", 340). ?DOC(" Get the file extension (without dot).\n"). -spec extension(binary()) -> {ok, binary()} | {error, nil}. extension(Path_str) -> fio@path:extension(Path_str). -file("src/fio.gleam", 345). ?DOC(" Remove the extension from a path.\n"). -spec strip_extension(binary()) -> binary(). strip_extension(Path_str) -> fio@path:strip_extension(Path_str). -file("src/fio.gleam", 350). ?DOC(" Get the stem (filename without extension).\n"). -spec stem(binary()) -> binary(). stem(Path_str) -> fio@path:stem(Path_str). -file("src/fio.gleam", 355). ?DOC(" Change the extension of a path.\n"). -spec with_extension(binary(), binary()) -> binary(). with_extension(Path_str, Ext) -> fio@path:with_extension(Path_str, Ext). -file("src/fio.gleam", 360). ?DOC(" Join a list of path segments.\n"). -spec join_all(list(binary())) -> binary(). join_all(Segments) -> fio@path:join_all(Segments). -file("src/fio.gleam", 365). ?DOC(" Check if a path is absolute.\n"). -spec is_absolute(binary()) -> boolean(). is_absolute(Path_str) -> fio@path:is_absolute(Path_str). -file("src/fio.gleam", 371). ?DOC( " Expand/normalize a path, resolving `.` and `..` segments.\n" " Returns `Error(Nil)` if `..` would go above the root.\n" ). -spec expand(binary()) -> {ok, binary()} | {error, nil}. expand(Path_str) -> fio@path:expand(Path_str). -file("src/fio.gleam", 377). ?DOC( " Validate that a path is a safe relative path (does not escape root).\n" " On Windows it also normalizes backslashes into `/`.\n" ). -spec safe_relative(binary()) -> {ok, binary()} | {error, nil}. safe_relative(Path_str) -> fio@path:safe_relative(Path_str).