170 lines
4.4 KiB
C
170 lines
4.4 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/syscall.h>
|
|
#include <dirent.h>
|
|
#include <stdbool.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include "test_fs.h"
|
|
|
|
// ============================================================================
|
|
// Helper function
|
|
// ============================================================================
|
|
|
|
#define NUM 9
|
|
static bool check_dir_entries(char entries[][256], int entry_cnt) {
|
|
char *expected_entries[NUM] = {
|
|
"bin",
|
|
"dev",
|
|
"host",
|
|
"lib",
|
|
"lib64",
|
|
"proc",
|
|
"opt",
|
|
"root",
|
|
"tmp",
|
|
};
|
|
for (int i = 0; i < NUM; i++) {
|
|
bool find_entry = false;
|
|
for (int j = 0; j < entry_cnt; j++) {
|
|
if (strncmp(expected_entries[i], entries[j], strlen(expected_entries[i])) == 0) {
|
|
find_entry = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!find_entry) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// The test case of readdir
|
|
// ============================================================================
|
|
|
|
static int test_readdir() {
|
|
struct dirent *dp;
|
|
DIR *dirp;
|
|
char entries[32][256] = { 0 };
|
|
|
|
dirp = opendir("/");
|
|
if (dirp == NULL) {
|
|
THROW_ERROR("failed to open directory");
|
|
}
|
|
int entry_cnt = 0;
|
|
while (1) {
|
|
errno = 0;
|
|
dp = readdir(dirp);
|
|
if (dp == NULL) {
|
|
if (errno != 0) {
|
|
closedir(dirp);
|
|
THROW_ERROR("failed to call readdir");
|
|
}
|
|
break;
|
|
}
|
|
strncpy(entries[entry_cnt], dp->d_name, 256);
|
|
++entry_cnt;
|
|
}
|
|
if (!check_dir_entries(entries, entry_cnt)) {
|
|
THROW_ERROR("failed to check the result of readdir");
|
|
}
|
|
closedir(dirp);
|
|
return 0;
|
|
}
|
|
|
|
static int getdents_with_big_enough_buffer(bool use_explicit_syscall) {
|
|
int fd, len;
|
|
char buf[64];
|
|
|
|
fd = open("/", O_RDONLY | O_DIRECTORY);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open directory");
|
|
}
|
|
while (1) {
|
|
if (use_explicit_syscall) {
|
|
len = syscall(__NR_getdents, fd, buf, sizeof(buf));
|
|
#ifndef __GLIBC__
|
|
} else {
|
|
len = getdents(fd, (struct dirent *)buf, sizeof(buf));
|
|
#endif
|
|
}
|
|
if (len < 0) {
|
|
close(fd);
|
|
THROW_ERROR("failed to call getdents");
|
|
} else if (len == 0) {
|
|
// On end of directory, 0 is returned
|
|
break;
|
|
}
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
#ifndef __GLIBC__
|
|
static int test_getdents_with_big_enough_buffer() {
|
|
bool use_explicit_syscall = false;
|
|
return getdents_with_big_enough_buffer(use_explicit_syscall);
|
|
}
|
|
#endif
|
|
|
|
static int test_getdents_via_explicit_syscall_with_big_enough_buffer() {
|
|
bool use_explicit_syscall = true;
|
|
return getdents_with_big_enough_buffer(use_explicit_syscall);
|
|
}
|
|
|
|
static int getdents_with_too_small_buffer(bool use_explicit_syscall) {
|
|
int fd, len;
|
|
char buf[4];
|
|
|
|
fd = open("/", O_RDONLY | O_DIRECTORY);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open directory");
|
|
}
|
|
if (use_explicit_syscall) {
|
|
len = syscall(__NR_getdents, fd, buf, sizeof(buf));
|
|
#ifndef __GLIBC__
|
|
} else {
|
|
len = getdents(fd, (struct dirent *)buf, sizeof(buf));
|
|
#endif
|
|
}
|
|
if (len >= 0 || errno != EINVAL) {
|
|
close(fd);
|
|
THROW_ERROR("failed to call getdents with small buffer");
|
|
}
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
#ifndef __GLIBC__
|
|
static int test_getdents_with_too_small_buffer() {
|
|
bool use_explicit_syscall = false;
|
|
return getdents_with_too_small_buffer(use_explicit_syscall);
|
|
}
|
|
#endif
|
|
|
|
static int test_getdents_via_explicit_syscall_with_too_small_buffer() {
|
|
bool use_explicit_syscall = true;
|
|
return getdents_with_too_small_buffer(use_explicit_syscall);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test suite main
|
|
// ============================================================================
|
|
|
|
static test_case_t test_cases[] = {
|
|
TEST_CASE(test_readdir),
|
|
#ifndef __GLIBC__
|
|
TEST_CASE(test_getdents_with_big_enough_buffer),
|
|
#endif
|
|
TEST_CASE(test_getdents_via_explicit_syscall_with_big_enough_buffer),
|
|
#ifndef __GLIBC__
|
|
TEST_CASE(test_getdents_with_too_small_buffer),
|
|
#endif
|
|
TEST_CASE(test_getdents_via_explicit_syscall_with_too_small_buffer),
|
|
};
|
|
|
|
int main() {
|
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
|
}
|