Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
15e9104d9e
|
|||
|
01034fc668
|
|||
|
8c94231167
|
@@ -207,6 +207,7 @@ add_library(akstdlib SHARED
|
|||||||
src/stdlib.c
|
src/stdlib.c
|
||||||
src/string.c
|
src/string.c
|
||||||
src/stream.c
|
src/stream.c
|
||||||
|
src/stat.c
|
||||||
src/collections.c
|
src/collections.c
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -317,6 +318,7 @@ set(AKSL_TESTS
|
|||||||
strbuf
|
strbuf
|
||||||
stream
|
stream
|
||||||
streamio
|
streamio
|
||||||
|
stat
|
||||||
strhash
|
strhash
|
||||||
string
|
string
|
||||||
strto
|
strto
|
||||||
|
|||||||
@@ -76,6 +76,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
/* off_t, for the aksl_fseeko/aksl_ftello pair. POSIX, like aksl_realpath. */
|
/* off_t, for the aksl_fseeko/aksl_ftello pair. POSIX, like aksl_realpath. */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@@ -808,6 +811,88 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_strhash_djb2_str(const char *str, uint32
|
|||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/* ====================================================================== */
|
||||||
|
/** @name File and filesystem metadata
|
||||||
|
*
|
||||||
|
* The stat family reports into caller-owned POSIX structs rather than a smaller
|
||||||
|
* library-defined copy: the platform owns the fields, and a wrapper should not
|
||||||
|
* discard a field merely because this library does not currently use it. libc
|
||||||
|
* failures retain their errno value as the status, so callers can distinguish
|
||||||
|
* absent paths from inaccessible ones without parsing an error message.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* ====================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stat(2).
|
||||||
|
* @param[in] pathname Path to inspect. Required.
|
||||||
|
* @param[out] dest File metadata. Required.
|
||||||
|
* @throws AKERR_NULLPOINTER If pathname or dest is NULL.
|
||||||
|
* @throws AKERR_IO If stat(2) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno stat(2) set, reported directly as the status.
|
||||||
|
* @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.
|
||||||
|
* @throws AKERR_NULLPOINTER If pathname or dest is NULL.
|
||||||
|
* @throws AKERR_IO If lstat(2) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno lstat(2) set, reported directly as the status.
|
||||||
|
* @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.
|
||||||
|
* @throws AKERR_NULLPOINTER If dest is NULL.
|
||||||
|
* @throws AKERR_IO If fstat(2) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno fstat(2) set, reported directly as the status.
|
||||||
|
* @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.
|
||||||
|
* @throws AKERR_NULLPOINTER If pathname or dest is NULL.
|
||||||
|
* @throws AKERR_IO If fstatat(2) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno fstatat(2) set, reported directly as the status.
|
||||||
|
* @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.
|
||||||
|
* @throws AKERR_NULLPOINTER If path or dest is NULL.
|
||||||
|
* @throws AKERR_IO If statvfs(3) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno statvfs(3) set, reported directly as the status.
|
||||||
|
* @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.
|
||||||
|
* @throws AKERR_NULLPOINTER If dest is NULL.
|
||||||
|
* @throws AKERR_IO If fstatvfs(3) failed and left errno at 0.
|
||||||
|
* @throws (errno) The errno fstatvfs(3) set, reported directly as the status.
|
||||||
|
* @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
|
/** @name Streams: open, read, write, close
|
||||||
*
|
*
|
||||||
|
|||||||
108
src/stat.c
Normal file
108
src/stat.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* sys/stat.h and sys/statvfs.h metadata wrappers.
|
||||||
|
*
|
||||||
|
* These calls make information about a file or filesystem available only by a
|
||||||
|
* return value that must be checked alongside a caller-owned POSIX struct. The
|
||||||
|
* wrappers put failure in the return value, where AKERR_NOIGNORE prevents it
|
||||||
|
* from being silently dropped, while preserving the errno that distinguishes
|
||||||
|
* missing paths, inaccessible paths, and invalid descriptors. errno is cleared
|
||||||
|
* immediately before each libc call, so a broken libc that reports failure
|
||||||
|
* without setting errno is still an AKERR_IO failure rather than status 0.
|
||||||
|
*/
|
||||||
|
#include <akstdlib.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
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=0x%x", 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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
errno = 0;
|
||||||
|
FAIL_NONZERO_RETURN(e, fstatvfs(fd, dest), AKSL_ERRNO_OR(AKERR_IO), "fd=%d", fd);
|
||||||
|
SUCCEED_RETURN(e);
|
||||||
|
}
|
||||||
134
tests/test_stat.c
Normal file
134
tests/test_stat.c
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/* File metadata wrapper tests. */
|
||||||
|
#include "aksl_capture.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A bit libc has never assigned in the AT_ space. fstatat(2) must reject it
|
||||||
|
* with EINVAL rather than ignoring it, which is what proves flags reach libc
|
||||||
|
* unmasked. Re-check this constant if AT_ ever grows into 0x40000000.
|
||||||
|
*/
|
||||||
|
#define AKSL_TEST_AT_INVALID 0x40000000
|
||||||
|
|
||||||
|
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;
|
||||||
|
/* A real file makes the mode and four-byte size observable to stat(2). */
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* fstat(2) addresses the same opened inode, not a second pathname lookup. */
|
||||||
|
AKSL_CHECK_OK(aksl_fstat(fd, &fd_dest));
|
||||||
|
AKSL_CHECK(fd_dest.st_ino == path_dest.st_ino);
|
||||||
|
|
||||||
|
/* fstatvfs(3) describes the backing filesystem and has a usable block size. */
|
||||||
|
AKSL_CHECK_OK(aksl_fstatvfs(fd, &vfs_dest));
|
||||||
|
AKSL_CHECK(vfs_dest.f_frsize != 0);
|
||||||
|
AKSL_CHECK(close(fd) == 0);
|
||||||
|
|
||||||
|
/* A descriptor that was just closed must surface libc's EBADF. */
|
||||||
|
AKSL_CHECK_STATUS(aksl_fstat(fd, &fd_dest), EBADF);
|
||||||
|
AKSL_CHECK_STATUS(aksl_fstatvfs(fd, &vfs_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 directory[AKSL_TMP_MAX];
|
||||||
|
char linkpath[AKSL_TMP_MAX * 2];
|
||||||
|
char *basename = NULL;
|
||||||
|
int dirfd = -1;
|
||||||
|
struct stat dest;
|
||||||
|
struct stat ldest;
|
||||||
|
struct stat path_dest;
|
||||||
|
struct statvfs vdest;
|
||||||
|
/* Missing paths and a regular file used as a directory preserve errno. */
|
||||||
|
AKSL_CHECK_STATUS(aksl_stat("/nonexistent/aksl/stat", &dest), ENOENT);
|
||||||
|
AKSL_CHECK_STATUS(aksl_lstat("/nonexistent/aksl/stat", &ldest), ENOENT);
|
||||||
|
/* The temporary path is a regular file, so adding a child tests ENOTDIR. */
|
||||||
|
AKSL_CHECK(aksl_temp_file(path, sizeof(path)) == 0);
|
||||||
|
AKSL_CHECK(snprintf(child, sizeof(child), "%s/child", path) < (int)sizeof(child));
|
||||||
|
AKSL_CHECK_OK(aksl_stat(path, &path_dest));
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* stat follows the link while lstat reports the link object itself. */
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* A real dirfd must resolve a relative name against that directory. */
|
||||||
|
AKSL_CHECK(snprintf(directory, sizeof(directory), "%s", path) < (int)sizeof(directory));
|
||||||
|
basename = strrchr(directory, '/');
|
||||||
|
AKSL_CHECK(basename != NULL);
|
||||||
|
*basename = '\0';
|
||||||
|
dirfd = open(directory, O_RDONLY | O_DIRECTORY);
|
||||||
|
AKSL_CHECK(dirfd >= 0);
|
||||||
|
AKSL_CHECK_OK(aksl_fstatat(dirfd, strrchr(path, '/') + 1, &dest, 0));
|
||||||
|
AKSL_CHECK(dest.st_ino == path_dest.st_ino);
|
||||||
|
AKSL_CHECK(close(dirfd) == 0);
|
||||||
|
|
||||||
|
/* A valid non-zero flag must reach libc, making this call an lstat. */
|
||||||
|
AKSL_CHECK_OK(aksl_fstatat(AT_FDCWD, linkpath, &dest, AT_SYMLINK_NOFOLLOW));
|
||||||
|
AKSL_CHECK(S_ISLNK(dest.st_mode));
|
||||||
|
|
||||||
|
/* Invalid flags must replace stale errno with the EINVAL libc reports. */
|
||||||
|
errno = E2BIG;
|
||||||
|
AKSL_CHECK_STATUS(aksl_fstatat(AT_FDCWD, path, &dest, AKSL_TEST_AT_INVALID), EINVAL);
|
||||||
|
|
||||||
|
/* statvfs reports ENOENT before it can describe a missing filesystem path. */
|
||||||
|
AKSL_CHECK_STATUS(aksl_statvfs("/nonexistent/aksl/stat", &vdest), ENOENT);
|
||||||
|
|
||||||
|
/* statvfs reports the filesystem containing the current directory. */
|
||||||
|
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;
|
||||||
|
/* Create a valid path so each failure below isolates a NULL argument. */
|
||||||
|
AKSL_CHECK(aksl_temp_file(path, sizeof(path)) == 0);
|
||||||
|
/* Every wrapper refuses either missing caller-owned input or output storage. */
|
||||||
|
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