Add directory stream wrappers #40
25
src/dir.c
25
src/dir.c
@@ -1,10 +1,20 @@
|
||||
/* POSIX directory-stream wrappers. */
|
||||
/*
|
||||
* POSIX directory-stream wrappers.
|
||||
*
|
||||
* opendir(3), fdopendir(3), readdir(3), closedir(3), and rewinddir(3) expose
|
||||
* three different failure conventions between them. These wrappers turn all
|
||||
* three into error contexts and make end-of-directory an explicit AKERR_EOF.
|
||||
*/
|
||||
#include <akstdlib.h>
|
||||
|
andrew marked this conversation as resolved
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "aksl_internal.h"
|
||||
|
||||
/*
|
||||
* opendir(3) returns NULL for failure. Clear *dest first so a failed open
|
||||
* cannot leave the caller holding a stale directory stream.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_opendir(const char *pathname, DIR **dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
@@ -19,6 +29,10 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_opendir(const char *pathname, DIR **dest
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* fdopendir(3) takes ownership of fd only when it succeeds. On success the
|
||||
* matching aksl_closedir call closes both the stream and its descriptor.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_fdopendir(int fd, DIR **dest)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
@@ -30,6 +44,10 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_fdopendir(int fd, DIR **dest)
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* readdir(3) owns and may reuse its returned storage. Copy the entry into the
|
||||
* caller's destination, and use errno to distinguish failure from exhaustion.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_readdir(DIR *dirp, struct dirent *dest)
|
||||
{
|
||||
struct dirent *entry = NULL;
|
||||
@@ -50,6 +68,7 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_readdir(DIR *dirp, struct dirent *dest)
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/* closedir(3) reports its failure directly and invalidates dirp on success. */
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_closedir(DIR *dirp)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
@@ -60,6 +79,10 @@ akerr_ErrorContext AKERR_NOIGNORE *aksl_closedir(DIR *dirp)
|
||||
SUCCEED_RETURN(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* rewinddir(3) has no failure return. Preserve that contract after rejecting
|
||||
* a NULL stream, which would otherwise be undefined behaviour.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *aksl_rewinddir(DIR *dirp)
|
||||
{
|
||||
PREPARE_ERROR(e);
|
||||
|
||||
@@ -23,14 +23,21 @@ static int test_open_errors_and_nulls(void)
|
||||
DIR *dirp = (DIR *)1;
|
||||
struct dirent entry;
|
||||
|
||||
/* opendir propagates missing-path and non-directory failures. */
|
||||
|
andrew marked this conversation as resolved
Outdated
andrew
commented
None of these checks have any comments explaining what the actual error cases are that they're testing None of these checks have any comments explaining what the actual error cases are that they're testing
|
||||
AKSL_CHECK_STATUS(aksl_opendir("/nonexistent/aksl/dir", &dirp), ENOENT);
|
||||
AKSL_CHECK(dirp == NULL);
|
||||
AKSL_CHECK(aksl_temp_file(file, sizeof(file)) == 0);
|
||||
AKSL_CHECK_STATUS(aksl_opendir(file, &dirp), ENOTDIR);
|
||||
|
||||
/* Every pointer required by the wrapped operation rejects NULL. */
|
||||
AKSL_CHECK_STATUS(aksl_opendir(NULL, &dirp), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_STATUS(aksl_opendir(".", NULL), AKERR_NULLPOINTER);
|
||||
|
||||
/* fdopendir propagates an invalid descriptor and validates its out-param. */
|
||||
AKSL_CHECK_STATUS(aksl_fdopendir(-1, &dirp), EBADF);
|
||||
AKSL_CHECK_STATUS(aksl_fdopendir(0, NULL), AKERR_NULLPOINTER);
|
||||
|
||||
/* The remaining wrappers reject NULL streams and destinations. */
|
||||
AKSL_CHECK_STATUS(aksl_readdir(NULL, &entry), AKERR_NULLPOINTER);
|
||||
AKSL_CHECK_OK(aksl_opendir(".", &dirp));
|
||||
AKSL_CHECK_STATUS(aksl_readdir(dirp, NULL), AKERR_NULLPOINTER);
|
||||
|
||||
Reference in New Issue
Block a user
None of these functions have
manstyle comment blocks for context on their operations, the same way other sources in this library do.