diff options
author | David Robillard <d@drobilla.net> | 2022-10-23 13:41:27 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-10-23 14:57:45 -0400 |
commit | d8b960be46007f9c09356e526d3c2dcff4b186a5 (patch) | |
tree | cd40db8d5634e74f8795922b7ab19fc8c6507648 /include | |
parent | c886d489576cd0bc33d7d22d81981c794067946f (diff) | |
download | zix-d8b960be46007f9c09356e526d3c2dcff4b186a5.tar.gz zix-d8b960be46007f9c09356e526d3c2dcff4b186a5.tar.bz2 zix-d8b960be46007f9c09356e526d3c2dcff4b186a5.zip |
Add filesystem API
Diffstat (limited to 'include')
-rw-r--r-- | include/zix/filesystem.h | 371 | ||||
-rw-r--r-- | include/zix/path.h | 3 | ||||
-rw-r--r-- | include/zix/status.h | 2 | ||||
-rw-r--r-- | include/zix/zix.h | 1 |
4 files changed, 376 insertions, 1 deletions
diff --git a/include/zix/filesystem.h b/include/zix/filesystem.h new file mode 100644 index 0000000..7b01c0e --- /dev/null +++ b/include/zix/filesystem.h @@ -0,0 +1,371 @@ +// Copyright 2007-2022 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC + +#ifndef ZIX_FILESYSTEM_H +#define ZIX_FILESYSTEM_H + +#include "zix/allocator.h" +#include "zix/attributes.h" +#include "zix/status.h" + +#if !(defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64) +# include <stddef.h> +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +ZIX_BEGIN_DECLS + +/** + @defgroup zix_filesystem Filesystem + @ingroup zix_file_system + @{ +*/ + +/** + @defgroup zix_fs_creation Creation and Removal + @{ +*/ + +/// Options to control filesystem copy operations +typedef enum { + ZIX_COPY_OPTION_NONE = 0U, ///< Report any error + ZIX_COPY_OPTION_OVERWRITE_EXISTING = 1U << 0U, ///< Replace existing file +} ZixCopyOption; + +/// Bitwise OR of ZixCopyOptions values +typedef uint32_t ZixCopyOptions; + +/** + Copy the file at path `src` to path `dst`. + + If supported by the system, a lightweight copy will be made to take + advantage of copy-on-write support in the filesystem. Otherwise, a simple + deep copy will be made. + + @param allocator Allocator used for a memory block for copying if necessary. + @param src Path to source file to copy. + @param dst Path to destination file to create. + @param options Options to control the kind of copy and error conditions. + @return #ZIX_STATUS_SUCCESS if `dst` was successfully created, or an error. +*/ +ZIX_API +ZixStatus +zix_copy_file(ZixAllocator* ZIX_NULLABLE allocator, + const char* ZIX_NONNULL src, + const char* ZIX_NONNULL dst, + ZixCopyOptions options); + +/** + Create the directory `dir_path` with all available permissions. + + @return #ZIX_STATUS_SUCCESS if `dir_path` was successfully created, or an + error. +*/ +ZIX_API +ZixStatus +zix_create_directory(const char* ZIX_NONNULL dir_path); + +/** + Create the directory `dir_path` with the permissions of another. + + This is like zix_create_directory(), but will copy the permissions from + another directory. + + @return #ZIX_STATUS_SUCCESS if `dir_path` was successfully created, or an + error. +*/ +ZIX_API +ZixStatus +zix_create_directory_like(const char* ZIX_NONNULL dir_path, + const char* ZIX_NONNULL existing_path); + +/** + Create the directory `dir_path` and any parent directories if necessary. + + @param allocator Allocator used for a temporary path buffer if necessary. + + @param dir_path The path to the deepest directory to create. + + @return #ZIX_STATUS_SUCCESS if all directories in `dir_path` were + successfully created (or already existed), or an error. +*/ +ZIX_API +ZixStatus +zix_create_directories(ZixAllocator* ZIX_NULLABLE allocator, + const char* ZIX_NONNULL dir_path); + +/** + Create a hard link at path `link` that points to path `target`. + + @return #ZIX_STATUS_SUCCESS, or an error. +*/ +ZIX_API +ZixStatus +zix_create_hard_link(const char* ZIX_NONNULL target_path, + const char* ZIX_NONNULL link_path); + +/** + Create a symbolic link at path `link` that points to path `target`. + + Note that portable code should use zix_create_directory_symlink() if the + target is a directory, since this function won't work for that on some + systems (like Windows). + + @return #ZIX_STATUS_SUCCESS, or an error. +*/ +ZIX_API +ZixStatus +zix_create_symlink(const char* ZIX_NONNULL target_path, + const char* ZIX_NONNULL link_path); + +/** + Create a symbolic link at path `link` that points to the directory `target`. + + This is a separate function from zix_create_symlink() because some systems + (like Windows) require directory symlinks to be created specially. + + @return #ZIX_STATUS_SUCCESS, or an error. +*/ +ZIX_API +ZixStatus +zix_create_directory_symlink(const char* ZIX_NONNULL target_path, + const char* ZIX_NONNULL link_path); + +/** + Create a unique temporary directory at a given path pattern. + + The last six characters of `pattern` must be "XXXXXX" and will be replaced + with unique characters in the result. + + @param allocator Allocator used for the returned path. + + @param path_pattern A path pattern ending in "XXXXXX". + + @return The path of the created directory, or null. +*/ +ZIX_API +char* ZIX_ALLOCATED +zix_create_temporary_directory(ZixAllocator* ZIX_NULLABLE allocator, + const char* ZIX_NONNULL path_pattern); + +/// Remove the file or empty directory at `path` +ZIX_API +ZixStatus +zix_remove(const char* ZIX_NONNULL path); + +/** + @} + @defgroup zix_fs_access Access + @{ +*/ + +/** + Visit every file in the directory at `path`. + + @param path A path to a directory. + + @param data Opaque user data that is passed to `f`. + + @param f A function called on every entry in the directory. The `path` + parameter is always the directory path passed to this function, the `name` + parameter is the name of the directory entry (not its full path). +*/ +ZIX_API +void +zix_dir_for_each(const char* ZIX_NONNULL path, + void* ZIX_NULLABLE data, + void (*ZIX_NONNULL f)(const char* ZIX_NONNULL path, + const char* ZIX_NONNULL name, + void* ZIX_NONNULL data)); + +/** + Return whether the given paths point to files with identical contents. + + @param allocator Allocator used for a memory block for comparison if + necessary. + + @param a_path Path to the first file to compare + + @param b_path Path to the second file to compare + + @return True if the two files have byte-for-byte identical contents. +*/ +ZIX_API +bool +zix_file_equals(ZixAllocator* ZIX_NULLABLE allocator, + const char* ZIX_NONNULL a_path, + const char* ZIX_NONNULL b_path); + +/** + @} + @defgroup zix_fs_resolution Resolution + @{ +*/ + +/** + Return `path` as a canonical absolute path to a "real" file. + + This expands all symbolic links, relative references, and removes extra + directory separators. + + Since this function may return null anyway, it accepts a null parameter to + allow easier chaining of path functions when only the final result is + required, for example: + + @code{.c} + char* path = zix_path_join(alloc, "/some/dir", "filename.txt"); + char* canonical = zix_canonical_path(path); + if (canonical) { + // Do something with the canonical path... + } else { + // No canonical path for some reason, we don't care which... + } + @endcode + + @return A new canonical version of `path`, or null if it doesn't exist. +*/ +ZIX_API +char* ZIX_ALLOCATED +zix_canonical_path(ZixAllocator* ZIX_NULLABLE allocator, + const char* ZIX_NULLABLE path); + +/** + @} + @defgroup zix_fs_locking Locking + @{ +*/ + +/** + A mode for locking files. + + The same mode should be used for the lock and the corresponding unlock. +*/ +typedef enum { + ZIX_FILE_LOCK_BLOCK, ///< Block until the operation succeeds + ZIX_FILE_LOCK_TRY, ///< Fail if the operation would block +} ZixFileLockMode; + +/** + Set an advisory exclusive lock on `file`. + + @param file Handle for open file to lock. + @param mode Lock mode. + @return #ZIX_STATUS_SUCCESS if the file was locked, or an error. +*/ +ZIX_API +ZixStatus +zix_file_lock(FILE* ZIX_NONNULL file, ZixFileLockMode mode); + +/** + Remove an advisory exclusive lock on `file`. + + @param file Handle for open file to lock. + @param mode Lock mode. + @return #ZIX_STATUS_SUCCESS if the file was unlocked, or an error. +*/ +ZIX_API +ZixStatus +zix_file_unlock(FILE* ZIX_NONNULL file, ZixFileLockMode mode); + +/** + @} + @defgroup zix_fs_queries Queries + @{ +*/ + +/** + An offset into a file or a file size in bytes. + + This is signed, and may be 64 bits even on 32-bit systems. +*/ +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 +typedef int64_t ZixFileOffset; +#else +typedef ptrdiff_t ZixFileOffset; +#endif + +/** + A type of file. + + Note that not all types may be supported, and the system may support + additional types not enumerated here. +*/ +typedef enum { + ZIX_FILE_TYPE_NONE, ///< Non-existent file + ZIX_FILE_TYPE_REGULAR, ///< Regular file + ZIX_FILE_TYPE_DIRECTORY, ///< Directory + ZIX_FILE_TYPE_SYMLINK, ///< Symbolic link + ZIX_FILE_TYPE_BLOCK, ///< Special block file + ZIX_FILE_TYPE_CHARACTER, ///< Special character file + ZIX_FILE_TYPE_FIFO, ///< FIFO + ZIX_FILE_TYPE_SOCKET, ///< Socket + ZIX_FILE_TYPE_UNKNOWN, ///< Existing file with unknown type +} ZixFileType; + +/** + Return the type of a file or directory, resolving symlinks. +*/ +ZIX_API +ZixFileType +zix_file_type(const char* ZIX_NONNULL path); + +/** + Return the type of a file or directory or symlink. + + On Windows, a directory symlink (actually a "reparse point") always appears + as a directory. +*/ +ZIX_API +ZixFileType +zix_symlink_type(const char* ZIX_NONNULL path); + +/** + Return the size of a file. + + Note that the returned value is signed and must be checked for errors. + Non-negative values can be thought of as the "end" offset just past the last + byte. + + @return A non-negative size in bytes, or -1 on error. +*/ +ZIX_API +ZixFileOffset +zix_file_size(const char* ZIX_NONNULL path); + +/** + @} + @defgroup zix_fs_environment Environment + @{ +*/ + +/** + Return the current working directory. + + @param allocator Allocator used for the returned path. +*/ +ZIX_API +char* ZIX_ALLOCATED +zix_current_path(ZixAllocator* ZIX_NULLABLE allocator); + +/** + Return the path to a directory suitable for making temporary files. + + @param allocator Allocator used for the returned path. + + @return A new path to a temporary directory, or null on error. +*/ +ZIX_API +char* ZIX_ALLOCATED +zix_temp_directory_path(ZixAllocator* ZIX_NULLABLE allocator); + +/** + @} + @} +*/ + +ZIX_END_DECLS + +#endif /* ZIX_FILESYSTEM_H */ diff --git a/include/zix/path.h b/include/zix/path.h index 5d3bd60..7a52d31 100644 --- a/include/zix/path.h +++ b/include/zix/path.h @@ -67,7 +67,8 @@ zix_path_preferred(ZixAllocator* ZIX_NULLABLE allocator, replaced with a single "\" on Windows, and a single "/" everwhere else). Note that this function doesn't access the filesystem, so won't do anything - like case normalization or symbolic link dereferencing. + like case normalization or symbolic link dereferencing. For that, use + zix_canonical_path(). */ ZIX_API char* ZIX_ALLOCATED diff --git a/include/zix/status.h b/include/zix/status.h index 0e95f43..dfd6412 100644 --- a/include/zix/status.h +++ b/include/zix/status.h @@ -28,6 +28,8 @@ typedef enum { ZIX_STATUS_OVERFLOW, ///< Overflow ZIX_STATUS_NOT_SUPPORTED, ///< Not supported ZIX_STATUS_UNAVAILABLE, ///< Resource unavailable + ZIX_STATUS_NO_SPACE, ///< Out of storage space + ZIX_STATUS_MAX_LINKS, ///< Too many links } ZixStatus; /// Return a string describing a status code diff --git a/include/zix/zix.h b/include/zix/zix.h index a91b6f8..b144cee 100644 --- a/include/zix/zix.h +++ b/include/zix/zix.h @@ -58,6 +58,7 @@ @{ */ +#include "zix/filesystem.h" #include "zix/path.h" /** |