Wrap file metadata calls
All checks were successful
All checks were successful
Co-authored-by: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
@@ -207,6 +207,7 @@ add_library(akstdlib SHARED
|
||||
src/stdlib.c
|
||||
src/string.c
|
||||
src/stream.c
|
||||
src/stat.c
|
||||
src/collections.c
|
||||
)
|
||||
|
||||
@@ -317,6 +318,7 @@ set(AKSL_TESTS
|
||||
strbuf
|
||||
stream
|
||||
streamio
|
||||
stat
|
||||
strhash
|
||||
string
|
||||
strto
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
/* off_t, for the aksl_fseeko/aksl_ftello pair. POSIX, like aksl_realpath. */
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -808,6 +810,57 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2_str(const char *str, uint32
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief stat(2).
|
||||
* @param[in] pathname Path to inspect. Required.
|
||||
* @param[out] dest File metadata. Required.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_stat(const char *pathname, struct stat *dest);
|
||||
|
||||
/**
|
||||
* @brief lstat(2), inspecting a symbolic link itself.
|
||||
* @param[in] pathname Path to inspect. Required.
|
||||
* @param[out] dest File metadata. Required.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_lstat(const char *pathname, struct stat *dest);
|
||||
|
||||
/**
|
||||
* @brief fstat(2).
|
||||
* @param[in] fd Open file descriptor.
|
||||
* @param[out] dest File metadata. Required.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstat(int fd, struct stat *dest);
|
||||
|
||||
/**
|
||||
* @brief fstatat(2).
|
||||
* @param[in] dirfd Directory descriptor, or AT_FDCWD.
|
||||
* @param[in] pathname Path to inspect. Required.
|
||||
* @param[out] dest File metadata. Required.
|
||||
* @param[in] flags libc fstatat flags, passed unchanged.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatat(int dirfd, const char *pathname, struct stat *dest, int flags);
|
||||
|
||||
/**
|
||||
* @brief statvfs(3).
|
||||
* @param[in] path Path on the filesystem. Required.
|
||||
* @param[out] dest Filesystem metadata. Required.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_statvfs(const char *path, struct statvfs *dest);
|
||||
|
||||
/**
|
||||
* @brief fstatvfs(3).
|
||||
* @param[in] fd Open file descriptor.
|
||||
* @param[out] dest Filesystem metadata. Required.
|
||||
* @return NULL on success, an error context otherwise.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatvfs(int fd, struct statvfs *dest);
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
/** @name Streams: open, read, write, close
|
||||
*
|
||||
|
||||
51
src/stat.c
Normal file
51
src/stat.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/* sys/stat.h and sys/statvfs.h metadata wrappers. */
|
||||
#include <akstdlib.h>
|
||||
#include <errno.h>
|
||||
#include "aksl_internal.h"
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_stat(const char *pathname, struct stat *dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, pathname, AKERR_NULLPOINTER, "pathname=%p, dest=%p", (void *)pathname, (void *)dest);
|
||||
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "pathname=%p, dest=%p", (void *)pathname, (void *)dest);
|
||||
errno = 0;
|
||||
FAIL_NONZERO_RETURN(e, stat(pathname, dest), AKSL_ERRNO_OR(AKERR_IO), "pathname=%s", pathname);
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_lstat(const char *pathname, struct stat *dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, pathname, AKERR_NULLPOINTER, "pathname=%p, dest=%p", (void *)pathname, (void *)dest);
|
||||
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "pathname=%p, dest=%p", (void *)pathname, (void *)dest);
|
||||
errno = 0;
|
||||
FAIL_NONZERO_RETURN(e, lstat(pathname, dest), AKSL_ERRNO_OR(AKERR_IO), "pathname=%s", pathname);
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
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);
|
||||
}
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_fstatat(int dirfd, const char *pathname, struct stat *dest, int flags)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, pathname, AKERR_NULLPOINTER, "dirfd=%d, pathname=%p, dest=%p", dirfd, (void *)pathname, (void *)dest);
|
||||
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "dirfd=%d, pathname=%p, dest=%p", dirfd, (void *)pathname, (void *)dest);
|
||||
errno = 0;
|
||||
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);
|
||||
}
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_statvfs(const char *path, struct statvfs *dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "path=%p, dest=%p", (void *)path, (void *)dest);
|
||||
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "path=%p, dest=%p", (void *)path, (void *)dest);
|
||||
errno = 0;
|
||||
FAIL_NONZERO_RETURN(e, statvfs(path, dest), AKSL_ERRNO_OR(AKERR_IO), "path=%s", path);
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
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);
|
||||
errno = 0; FAIL_NONZERO_RETURN(e, fstatvfs(fd, dest), AKSL_ERRNO_OR(AKERR_IO), "fd=%d", fd); SUCCEED_RETURN(e);
|
||||
}
|
||||
86
tests/test_stat.c
Normal file
86
tests/test_stat.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/* File metadata wrapper tests. */
|
||||
#include "aksl_capture.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int test_stat_success_and_fstat(void)
|
||||
{
|
||||
char path[AKSL_TMP_MAX];
|
||||
int fd = -1;
|
||||
struct stat path_dest;
|
||||
struct stat fd_dest;
|
||||
struct statvfs vfs_dest;
|
||||
AKSL_CHECK(aksl_temp_file(path, sizeof(path)) == 0);
|
||||
fd = open(path, O_RDWR);
|
||||
AKSL_CHECK(fd >= 0);
|
||||
AKSL_CHECK(write(fd, "stat", 4) == 4);
|
||||
AKSL_CHECK_OK(aksl_stat(path, &path_dest));
|
||||
AKSL_CHECK(S_ISREG(path_dest.st_mode));
|
||||
AKSL_CHECK(path_dest.st_size == 4);
|
||||
AKSL_CHECK_OK(aksl_fstat(fd, &fd_dest));
|
||||
AKSL_CHECK(fd_dest.st_ino == path_dest.st_ino);
|
||||
AKSL_CHECK_OK(aksl_fstatvfs(fd, &vfs_dest));
|
||||
AKSL_CHECK(vfs_dest.f_frsize != 0);
|
||||
AKSL_CHECK(close(fd) == 0);
|
||||
AKSL_CHECK_STATUS(aksl_fstat(fd, &fd_dest), EBADF);
|
||||
AKSL_CHECK(unlink(path) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_stat_paths_and_fstatat(void)
|
||||
{
|
||||
char path[AKSL_TMP_MAX];
|
||||
char child[AKSL_TMP_MAX * 2];
|
||||
char linkpath[AKSL_TMP_MAX * 2];
|
||||
struct stat dest;
|
||||
struct stat ldest;
|
||||
struct statvfs vdest;
|
||||
AKSL_CHECK_STATUS(aksl_stat("/nonexistent/aksl/stat", &dest), ENOENT);
|
||||
AKSL_CHECK(aksl_temp_file(path, sizeof(path)) == 0);
|
||||
AKSL_CHECK(snprintf(child, sizeof(child), "%s/child", path) < (int)sizeof(child));
|
||||
AKSL_CHECK_STATUS(aksl_stat(child, &dest), ENOTDIR);
|
||||
AKSL_CHECK(snprintf(linkpath, sizeof(linkpath), "%s.link", path) < (int)sizeof(linkpath));
|
||||
AKSL_CHECK(symlink(path, linkpath) == 0);
|
||||
AKSL_CHECK_OK(aksl_stat(linkpath, &dest));
|
||||
AKSL_CHECK_OK(aksl_lstat(linkpath, &ldest));
|
||||
AKSL_CHECK(S_ISREG(dest.st_mode));
|
||||
AKSL_CHECK(S_ISLNK(ldest.st_mode));
|
||||
AKSL_CHECK_OK(aksl_fstatat(AT_FDCWD, path, &dest, 0));
|
||||
errno = E2BIG;
|
||||
AKSL_CHECK_STATUS(aksl_fstatat(AT_FDCWD, path, &dest, 0x40000000), EINVAL);
|
||||
AKSL_CHECK(errno == EINVAL);
|
||||
AKSL_CHECK_OK(aksl_statvfs(".", &vdest));
|
||||
AKSL_CHECK(vdest.f_frsize != 0);
|
||||
AKSL_CHECK(unlink(linkpath) == 0);
|
||||
AKSL_CHECK(unlink(path) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_stat_null_arguments(void)
|
||||
{
|
||||
char path[AKSL_TMP_MAX];
|
||||
struct stat dest;
|
||||
struct statvfs vdest;
|
||||
AKSL_CHECK(aksl_temp_file(path, sizeof(path)) == 0);
|
||||
AKSL_CHECK_STATUS(aksl_stat(NULL, &dest), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_stat(path, NULL), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_lstat(NULL, &dest), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_lstat(path, NULL), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_fstat(0, NULL), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_fstatat(AT_FDCWD, NULL, &dest, 0), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_fstatat(AT_FDCWD, path, NULL, 0), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_statvfs(NULL, &vdest), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_statvfs(path, NULL), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_fstatvfs(0, NULL), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK(unlink(path) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int failures = 0;
|
||||
AKSL_RUN(failures, test_stat_success_and_fstat);
|
||||
AKSL_RUN(failures, test_stat_paths_and_fstatat);
|
||||
AKSL_RUN(failures, test_stat_null_arguments);
|
||||
AKSL_REPORT(failures);
|
||||
}
|
||||
Reference in New Issue
Block a user