Document file metadata wrapper behavior
All checks were successful
libakstdlib CI Build / coverage (push) Successful in 2m44s
libakstdlib CI Build / cmake_build (push) Successful in 2m56s
libakstdlib CI Build / sanitizers (push) Successful in 3m1s
libakstdlib CI Build / mutation_test (push) Successful in 12m58s

Co-authored-by: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
2026-08-03 09:02:19 -04:00
parent 8c94231167
commit 01034fc668
2 changed files with 56 additions and 0 deletions

View File

@@ -3,6 +3,12 @@
#include <errno.h>
#include "aksl_internal.h"
/*
* stat(2) follows pathname through any symbolic links and writes the target's
* metadata into the caller-owned struct stat. A file that is gone, cannot be
* searched, or lives below a non-directory component is reported as the errno
* from libc rather than as a library-specific status.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_stat(const char *pathname, struct stat *dest)
{
PREPARE_ERROR(e);
@@ -12,6 +18,12 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_stat(const char *pathname, struct stat *
FAIL_NONZERO_RETURN(e, stat(pathname, dest), AKSL_ERRNO_OR(AKERR_IO), "pathname=%s", pathname);
SUCCEED_RETURN(e);
}
/*
* lstat(2) is stat(2) without the final symbolic-link traversal. That is the
* difference a caller needs when it is deciding whether a path is a link or
* when the link's ownership and mode are the metadata of interest.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_lstat(const char *pathname, struct stat *dest)
{
PREPARE_ERROR(e);
@@ -21,11 +33,24 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_lstat(const char *pathname, struct stat
FAIL_NONZERO_RETURN(e, lstat(pathname, dest), AKSL_ERRNO_OR(AKERR_IO), "pathname=%s", pathname);
SUCCEED_RETURN(e);
}
/*
* fstat(2) gets metadata from an already-open descriptor, so it has no path
* lookup race and remains useful after the file has been renamed or unlinked.
* A closed or otherwise invalid descriptor reports EBADF from libc.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstat(int fd, struct stat *dest)
{
PREPARE_ERROR(e); FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "fd=%d, dest=%p", fd, (void *)dest);
errno = 0; FAIL_NONZERO_RETURN(e, fstat(fd, dest), AKSL_ERRNO_OR(AKERR_IO), "fd=%d", fd); SUCCEED_RETURN(e);
}
/*
* fstatat(2) is the directory-descriptor form of stat(2). pathname is resolved
* relative to dirfd unless it is absolute, and flags retain the libc choices
* such as inspecting a link itself. Keeping those flags unchanged prevents this
* wrapper from inventing a smaller policy than the POSIX call already exposes.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatat(int dirfd, const char *pathname, struct stat *dest, int flags)
{
PREPARE_ERROR(e);
@@ -35,6 +60,12 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatat(int dirfd, const char *pathname,
FAIL_NONZERO_RETURN(e, fstatat(dirfd, pathname, dest, flags), AKSL_ERRNO_OR(AKERR_IO), "dirfd=%d pathname=%s flags=%d", dirfd, pathname, flags);
SUCCEED_RETURN(e);
}
/*
* statvfs(3) writes information about the mounted filesystem containing path,
* not merely the named file. The result includes the filesystem block sizes and
* available space the caller needs before it decides whether an operation fits.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_statvfs(const char *path, struct statvfs *dest)
{
PREPARE_ERROR(e);
@@ -44,6 +75,12 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_statvfs(const char *path, struct statvfs
FAIL_NONZERO_RETURN(e, statvfs(path, dest), AKSL_ERRNO_OR(AKERR_IO), "path=%s", path);
SUCCEED_RETURN(e);
}
/*
* fstatvfs(3) is the descriptor form of statvfs(3). It asks the filesystem that
* owns fd for the same capacity and flag information without resolving a path
* again, and reports a bad descriptor through the errno libc supplies.
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatvfs(int fd, struct statvfs *dest)
{
PREPARE_ERROR(e); FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "fd=%d, dest=%p", fd, (void *)dest);