%%% -------------------------------------------------- %%% @author Benjamin Peinhardt %%% @doc Erlang ffi glue code for the simplifile Gleam package. %%% @end %%% -------------------------------------------------- -module(simplifile_erl). %% API -export([ append_bits/2, create_directory/1, create_dir_all/1, delete_file/1, create_symlink/2, delete/1, delete_directory/1, file_info/1, is_directory/1, is_file/1, is_symlink/1, read_bits/1, read_directory/1, rename_file/2, set_permissions_octal/2, write_bits/2 ]). -include_lib("kernel/include/file.hrl"). %% A macro for checking whether the error returned is one of the atoms for a posixe error. -define(is_posix_error(Error), Error =:= eacces orelse Error =:= eagain orelse Error =:= ebadf orelse Error =:= ebadmsg orelse Error =:= ebusy orelse Error =:= edeadlk orelse Error =:= edeadlock orelse Error =:= edquot orelse Error =:= eexist orelse Error =:= efault orelse Error =:= efbig orelse Error =:= eftype orelse Error =:= eintr orelse Error =:= einval orelse Error =:= eio orelse Error =:= eisdir orelse Error =:= eloop orelse Error =:= emfile orelse Error =:= emlink orelse Error =:= emultihop orelse Error =:= enametoolong orelse Error =:= enfile orelse Error =:= enobufs orelse Error =:= enodev orelse Error =:= enolck orelse Error =:= enolink orelse Error =:= enoent orelse Error =:= enomem orelse Error =:= enospc orelse Error =:= enosr orelse Error =:= enostr orelse Error =:= enosys orelse Error =:= enotblk orelse Error =:= enotdir orelse Error =:= enotsup orelse Error =:= enxio orelse Error =:= eopnotsupp orelse Error =:= eoverflow orelse Error =:= eperm orelse Error =:= epipe orelse Error =:= erange orelse Error =:= erofs orelse Error =:= espipe orelse Error =:= esrch orelse Error =:= estale orelse Error =:= etxtbsy orelse Error =:= exdev). %% Only return the error if it's a posix error. Also converts ok to {ok, nil}, %% as gleam doesn't have atoms. posix_result(Result) -> case Result of ok -> {ok, nil}; {ok, Value} -> {ok, Value}; {error, Reason} when ?is_posix_error(Reason) -> {error, Reason} end. %% Read the binary contents of a file read_bits(Filename) -> posix_result(file:read_file(Filename)). %% Write bytes to a file write_bits(Filename, Contents) -> posix_result(file:write_file(Filename, Contents)). %% Append bytes to a file append_bits(Filename, Contents) -> posix_result(file:write_file(Filename, Contents, [append])). %% Delete the file at the given path delete_file(Filename) -> posix_result(file:delete(Filename)). %% Create a directory at the given path. Missing parent directories are not created. create_directory(Dir) -> posix_result(file:make_dir(Dir)). %% Create a symbolic link New to the file or directory Existing (does not need to exist). create_symlink(Existing, New) -> posix_result(file:make_symlink(Existing, New)). %% List the contents of a directory read_directory(Dir) -> case file:list_dir(Dir) of {ok, Filenames} -> {ok, [unicode:characters_to_binary(Filename) || Filename <- Filenames]}; {error, Reason} when ?is_posix_error(Reason) -> {error, Reason} end. %% Delete a directory at the given path. Directory must be empty. delete_directory(Dir) -> posix_result(file:del_dir(Dir)). %% Deletes a file/directory and everything in it. delete(Dir) -> posix_result(file:del_dir_r(Dir)). %% Creates the entire path for a given directory to exist create_dir_all(Filename) -> posix_result(filelib:ensure_dir(Filename)). %% Move file from one path to another rename_file(Source, Destination) -> posix_result(file:rename(Source, Destination)). %% Set the permissions for the given file. set_permissions_octal(Filename, Permissions) -> posix_result(file:change_mode(Filename, Permissions)). is_directory(Path) -> case file:read_file_info(Path) of {ok, FileInfo} -> case FileInfo#file_info.type of directory -> {ok, true}; _ -> {ok, false} end; {error, enoent} -> {ok, false}; {error, Reason} -> posix_result({error, Reason}) end. is_file(Path) -> case file:read_file_info(Path) of {ok, FileInfo} -> case FileInfo#file_info.type of regular -> {ok, true}; _ -> {ok, false} end; {error, enoent} -> {ok, false}; {error, Reason} -> posix_result({error, Reason}) end. is_symlink(Path) -> case file:read_link_info(Path) of {ok, FileInfo} -> case FileInfo#file_info.type of symlink -> {ok, true}; _ -> {ok, false} end; {error, enoent} -> {ok, false}; {error, Reason} -> posix_result({error, Reason}) end. file_info_result(Result) -> case Result of {ok, {file_info, Size, _Type, _Access, Atime, Mtime, Ctime, Mode, Links, MajorDevice, _MinorDevice, Inode, Uid, Gid}} -> {ok, {file_info, Size, Mode, Links, Inode, Uid, Gid, MajorDevice, Atime, Mtime, Ctime}}; {error, Reason} when ?is_posix_error(Reason) -> Result end. file_info(Filename) -> file_info_result(file:read_file_info(Filename, [{time, posix}])).