diff --git a/src/libos/src/fs/file_ops/dirent.rs b/src/libos/src/fs/file_ops/dirent.rs index dd32c25b..4641e387 100644 --- a/src/libos/src/fs/file_ops/dirent.rs +++ b/src/libos/src/fs/file_ops/dirent.rs @@ -8,7 +8,7 @@ pub fn do_getdents(fd: FileDesc, buf: &mut [u8]) -> Result { getdents_common::<()>(fd, buf) } -fn getdents_common(fd: FileDesc, buf: &mut [u8]) -> Result { +fn getdents_common(fd: FileDesc, buf: &mut [u8]) -> Result { debug!( "getdents: fd: {}, buf: {:?}, buf_size: {}", fd, @@ -33,8 +33,8 @@ fn getdents_common(fd: FileDesc, buf: &mut [u8]) } Ok(name) => name, }; - // TODO: get ino from dirent - let dirent = LinuxDirent::::new(1, &name); + // TODO: get ino and type from dirent + let dirent = LinuxDirent::::new(1, &name, DT_UNKNOWN); if let Err(e) = writer.try_write(&dirent, &name) { file_ref.seek(SeekFrom::Current(-1))?; if writer.written_size == 0 { @@ -47,8 +47,10 @@ fn getdents_common(fd: FileDesc, buf: &mut [u8]) Ok(writer.written_size) } +const DT_UNKNOWN: u8 = 0; + #[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes. -struct LinuxDirent { +struct LinuxDirent { /// Inode number ino: u64, /// Offset to next structure @@ -61,15 +63,20 @@ struct LinuxDirent { name: [u8; 0], } -impl LinuxDirent { - fn new(ino: u64, name: &str) -> Self { - let ori_len = ::core::mem::size_of::>() + name.len() + 1; +impl LinuxDirent { + fn new(ino: u64, name: &str, d_type: u8) -> Self { + let ori_len = if !T::at_the_end_of_linux_dirent() { + core::mem::size_of::>() + name.len() + 1 + } else { + // pad the file type at the end + core::mem::size_of::>() + name.len() + 1 + core::mem::size_of::() + }; let len = align_up(ori_len, 8); // align up to 8 bytes Self { ino, offset: 0, reclen: len as u16, - type_: Default::default(), + type_: T::set_type(d_type), name: [], } } @@ -79,9 +86,9 @@ impl LinuxDirent { } } -impl Copy for LinuxDirent {} +impl Copy for LinuxDirent {} -impl Clone for LinuxDirent { +impl Clone for LinuxDirent { fn clone(&self) -> Self { Self { ino: self.ino, @@ -93,10 +100,27 @@ impl Clone for LinuxDirent { } } -trait DirentType {} +trait DirentType { + fn set_type(d_type: u8) -> Self; + fn at_the_end_of_linux_dirent() -> bool; +} -impl DirentType for u8 {} -impl DirentType for () {} +impl DirentType for u8 { + fn set_type(d_type: u8) -> Self { + d_type + } + fn at_the_end_of_linux_dirent() -> bool { + false + } +} +impl DirentType for () { + fn set_type(d_type: u8) -> Self { + Default::default() + } + fn at_the_end_of_linux_dirent() -> bool { + true + } +} struct DirentBufWriter<'a> { buf: &'a mut [u8], @@ -114,7 +138,7 @@ impl<'a> DirentBufWriter<'a> { } } - fn try_write( + fn try_write( &mut self, dirent: &LinuxDirent, name: &str, @@ -127,6 +151,21 @@ impl<'a> DirentBufWriter<'a> { ptr.write(*dirent); let name_ptr = ptr.add(1) as _; write_cstr(name_ptr, name); + if T::at_the_end_of_linux_dirent() { + // pad zero bytes and file type at the end + let mut ptr = name_ptr.add(name.len() + 1); + let mut rest_len = { + let written_len = core::mem::size_of::>() + name.len() + 1; + dirent.len() - written_len + }; + while rest_len > 1 { + ptr.write(0); + ptr = ptr.add(1); + rest_len -= 1; + } + // the last one is file type + ptr.write(DT_UNKNOWN); + } } self.rest_size -= dirent.len(); self.written_size += dirent.len(); diff --git a/test/readdir/main.c b/test/readdir/main.c index 94c11b69..a6dab88f 100644 --- a/test/readdir/main.c +++ b/test/readdir/main.c @@ -7,6 +7,38 @@ #include #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 // ============================================================================ @@ -14,21 +46,28 @@ 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("faild to call readdir"); + 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;