diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 4b83df09..791a4f3a 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -206,9 +206,13 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result { Ok(name) => name, }; // TODO: get ino from dirent - let ok = writer.try_write(0, 0, &name); - if !ok { - return_errno!(EINVAL, "the given buffer is too small"); + if let Err(e) = writer.try_write(0, 0, &name) { + file_ref.seek(SeekFrom::Current(-1))?; + if writer.written_size == 0 { + return Err(e); + } else { + break; + } } } Ok(writer.written_size) @@ -570,11 +574,11 @@ impl<'a> DirentBufWriter<'a> { written_size: 0, } } - fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool { + fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> Result<()> { let len = ::core::mem::size_of::() + name.len() + 1; let len = (len + 7) / 8 * 8; // align up if self.rest_size < len { - return false; + return_errno!(EINVAL, "the given buffer is too small"); } let dent = LinuxDirent64 { ino: inode, @@ -591,7 +595,7 @@ impl<'a> DirentBufWriter<'a> { } self.rest_size -= len; self.written_size += len; - true + Ok(()) } } diff --git a/test/readdir/main.c b/test/readdir/main.c index 5e07cbfd..ee06d3bd 100644 --- a/test/readdir/main.c +++ b/test/readdir/main.c @@ -1,23 +1,89 @@ #include +#include #include -#include +#include +#include #include #include +#include +#include "test.h" -int main(int argc, const char* argv[]) { - DIR* dirp = opendir("/"); +// ============================================================================ +// The test case of readdir +// ============================================================================ + +static int test_readdir() { + struct dirent *dp; + DIR* dirp; + + dirp = opendir("/"); if (dirp == NULL) { - printf("failed to open directory at /\n"); - return -1; + THROW_ERROR("failed to open directory"); + } + while (1) { + errno = 0; + dp = readdir(dirp); + if (dp == NULL) { + if (errno != 0) { + closedir(dirp); + THROW_ERROR("faild to call readdir"); + } + break; + } } - - struct dirent *dp; - while ((dp = readdir(dirp)) != NULL) { - printf("get: %s\n", dp->d_name); - } - closedir(dirp); - - printf("Read directory test successful\n"); return 0; } + +static int test_getdents_with_big_enough_buffer() { + int fd, len; + char buf[64]; + + fd = open("/", O_RDONLY | O_DIRECTORY); + if (fd < 0) { + THROW_ERROR("failed to open directory"); + } + while (1) { + len = getdents(fd, (struct dirent *)buf, sizeof(buf)); + 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; +} + +static int test_getdents_with_too_small_buffer() { + int fd, len; + char buf[4]; + + fd = open("/", O_RDONLY | O_DIRECTORY); + if (fd < 0) { + THROW_ERROR("failed to open directory"); + } + len = getdents(fd, (struct dirent *)buf, sizeof(buf)); + if (len >= 0 || errno != EINVAL) { + close(fd); + THROW_ERROR("failed to call getdents with small buffer"); + } + close(fd); + return 0; +} + +// ============================================================================ +// Test suite main +// ============================================================================ + +static test_case_t test_cases[] = { + TEST_CASE(test_readdir), + TEST_CASE(test_getdents_with_big_enough_buffer), + TEST_CASE(test_getdents_with_too_small_buffer), +}; + +int main() { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +}