Skip to content

Commit

Permalink
Add g_readdir_entries() to OS calls
Browse files Browse the repository at this point in the history
  • Loading branch information
matt335672 committed Dec 2, 2024
1 parent 5f9ea93 commit 01922bd
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 0 deletions.
59 changes: 59 additions & 0 deletions common/os_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#define ctid_t id_t
#endif
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
Expand Down Expand Up @@ -4243,3 +4244,61 @@ g_qsort(void *base, size_t nitems, size_t size,
{
qsort(base, nitems, size, compar);
}

/*****************************************************************************/
struct list *
g_readdir(const char *dir)
{
DIR *handle;
struct list *result = NULL;
struct dirent *dent;
int saved_errno;

errno = 0; // See readdir(3)
if ((handle = opendir(dir)) != NULL &&
(result = list_create()) != NULL)
{
result->auto_free = 1;
while (1)
{
errno = 0;
dent = readdir(handle);
if (dent == NULL)
{
break; // errno = 0 for end-of-dir, or != 0 for error
}

// Ignore '.' and '..'
if (dent->d_name[0] == '.' && dent->d_name[1] == '\0')
{
continue;
}
if (dent->d_name[0] == '.' && dent->d_name[1] == '.' &&
dent->d_name[2] == '\0')
{
continue;
}

if (!list_add_strdup(result, dent->d_name))
{
// Memory allocation failure
errno = ENOMEM;
break;
}
}
}

saved_errno = errno;
if (errno != 0)
{
list_delete(result);
result = NULL;
}
if (handle != NULL)
{
closedir(handle);
}
errno = saved_errno;

return result;
}
13 changes: 13 additions & 0 deletions common/os_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,19 @@ void
g_qsort(void *base, size_t nitems, size_t size,
int (*compar)(const void *, const void *));

/**
* Returns a list of the filenames contained within a directory
*
* @param dir Name of directory
* @return list of directory entry names
*
* If NULL is returned, further information may be available in errno. No
* other errors are specifically logged.
* The special files '.' and '..' are not returned.
*/
struct list *
g_readdir(const char *dir);

/* glib-style wrappers */
#define g_new(struct_type, n_structs) \
(struct_type *) malloc(sizeof(struct_type) * (n_structs))
Expand Down
74 changes: 74 additions & 0 deletions tests/common/test_os_calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <poll.h>
#include <errno.h>

#include "os_calls.h"
#include "list.h"
Expand All @@ -20,6 +21,9 @@
// File for testing ro/rw opens
#define RO_RW_FILE "./test_ro_rw"

// Directory for testing files
#define TEST_READDIR "./test_readdir"

/******************************************************************************/
/***
* Gets the number of open file descriptors for the current process */
Expand Down Expand Up @@ -487,6 +491,74 @@ START_TEST(test_g_sck_fd_overflow)
}
END_TEST

/******************************************************************************/
static int qsort_func_strlist(const void *a, const void *b)
{
return strcmp(*(const char **)a, *(const char **)b);
}

START_TEST(test_g_readdir)
{
int status;
const char *entries[] = { "one", "two", "three", "four", "five", 0};
unsigned int count = 0;
const char **name;

// Don't check results of create dir, as we may be re-running this
// after a fail
(void)g_mkdir(TEST_READDIR);
// This should work though
status = g_set_current_dir(TEST_READDIR);
ck_assert_int_eq(status, 0);

// Create some files in the directory
for (name = entries; *name != NULL; ++name, ++count)
{
int fd = g_file_open_rw(*name);
ck_assert(fd >= 0);
g_file_close(fd);
}

// Can we read them, and are there the expected number?
struct list *dentries = g_readdir(".");
ck_assert_ptr_ne(dentries, NULL);
ck_assert_ptr_ne(dentries, NULL);
ck_assert_int_eq(dentries->count, count);

// Sort both lists according to the current locale
qsort(entries, count, sizeof(entries[0]), qsort_func_strlist);
qsort(dentries->items, count, sizeof(dentries->items[0]),
qsort_func_strlist);

// Check both lists are identical
int i;
for (i = 0 ; i < count; ++i)
{
ck_assert_str_eq(entries[i], (const char *)dentries->items[i]);
}

// Clean up
list_delete(dentries);
for (i = 0 ; i < count ; ++i)
{
g_file_delete(entries[i]);
}
g_set_current_dir("..");
status = g_remove_dir(TEST_READDIR); // Returns a boolean(?)
ck_assert_int_ne(status, 0);


}
END_TEST

START_TEST(test_g_readdir_not_dir)
{
struct list *dentries = g_readdir("NoSuchDirectory");
ck_assert_ptr_eq(dentries, 0);
ck_assert_int_eq(errno, ENOENT);
}
END_TEST

/******************************************************************************/
Suite *
make_suite_test_os_calls(void)
Expand All @@ -512,6 +584,8 @@ make_suite_test_os_calls(void)
tcase_add_test(tc_os_calls, test_g_file_is_open);
tcase_add_test(tc_os_calls, test_g_sck_fd_passing);
tcase_add_test(tc_os_calls, test_g_sck_fd_overflow);
tcase_add_test(tc_os_calls, test_g_readdir);
tcase_add_test(tc_os_calls, test_g_readdir_not_dir);

// Add other test cases in other files
suite_add_tcase(s, make_tcase_test_os_calls_signals());
Expand Down

0 comments on commit 01922bd

Please sign in to comment.