Fix getdents cannot output all entries in a directory
This commit is contained in:
parent
c4c3315c06
commit
d7b994bc7d
@ -8,7 +8,7 @@ pub fn do_getdents(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|||||||
getdents_common::<()>(fd, buf)
|
getdents_common::<()>(fd, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getdents_common<T: DirentType + Copy + Default>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
fn getdents_common<T: DirentType + Copy>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
||||||
debug!(
|
debug!(
|
||||||
"getdents: fd: {}, buf: {:?}, buf_size: {}",
|
"getdents: fd: {}, buf: {:?}, buf_size: {}",
|
||||||
fd,
|
fd,
|
||||||
@ -33,8 +33,8 @@ fn getdents_common<T: DirentType + Copy + Default>(fd: FileDesc, buf: &mut [u8])
|
|||||||
}
|
}
|
||||||
Ok(name) => name,
|
Ok(name) => name,
|
||||||
};
|
};
|
||||||
// TODO: get ino from dirent
|
// TODO: get ino and type from dirent
|
||||||
let dirent = LinuxDirent::<T>::new(1, &name);
|
let dirent = LinuxDirent::<T>::new(1, &name, DT_UNKNOWN);
|
||||||
if let Err(e) = writer.try_write(&dirent, &name) {
|
if let Err(e) = writer.try_write(&dirent, &name) {
|
||||||
file_ref.seek(SeekFrom::Current(-1))?;
|
file_ref.seek(SeekFrom::Current(-1))?;
|
||||||
if writer.written_size == 0 {
|
if writer.written_size == 0 {
|
||||||
@ -47,8 +47,10 @@ fn getdents_common<T: DirentType + Copy + Default>(fd: FileDesc, buf: &mut [u8])
|
|||||||
Ok(writer.written_size)
|
Ok(writer.written_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DT_UNKNOWN: u8 = 0;
|
||||||
|
|
||||||
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
||||||
struct LinuxDirent<T: DirentType + Copy + Default> {
|
struct LinuxDirent<T: DirentType + Copy> {
|
||||||
/// Inode number
|
/// Inode number
|
||||||
ino: u64,
|
ino: u64,
|
||||||
/// Offset to next structure
|
/// Offset to next structure
|
||||||
@ -61,15 +63,20 @@ struct LinuxDirent<T: DirentType + Copy + Default> {
|
|||||||
name: [u8; 0],
|
name: [u8; 0],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DirentType + Copy + Default> LinuxDirent<T> {
|
impl<T: DirentType + Copy> LinuxDirent<T> {
|
||||||
fn new(ino: u64, name: &str) -> Self {
|
fn new(ino: u64, name: &str, d_type: u8) -> Self {
|
||||||
let ori_len = ::core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1;
|
let ori_len = if !T::at_the_end_of_linux_dirent() {
|
||||||
|
core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1
|
||||||
|
} else {
|
||||||
|
// pad the file type at the end
|
||||||
|
core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1 + core::mem::size_of::<u8>()
|
||||||
|
};
|
||||||
let len = align_up(ori_len, 8); // align up to 8 bytes
|
let len = align_up(ori_len, 8); // align up to 8 bytes
|
||||||
Self {
|
Self {
|
||||||
ino,
|
ino,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
reclen: len as u16,
|
reclen: len as u16,
|
||||||
type_: Default::default(),
|
type_: T::set_type(d_type),
|
||||||
name: [],
|
name: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,9 +86,9 @@ impl<T: DirentType + Copy + Default> LinuxDirent<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DirentType + Copy + Default> Copy for LinuxDirent<T> {}
|
impl<T: DirentType + Copy> Copy for LinuxDirent<T> {}
|
||||||
|
|
||||||
impl<T: DirentType + Copy + Default> Clone for LinuxDirent<T> {
|
impl<T: DirentType + Copy> Clone for LinuxDirent<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ino: self.ino,
|
ino: self.ino,
|
||||||
@ -93,10 +100,27 @@ impl<T: DirentType + Copy + Default> Clone for LinuxDirent<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 u8 {
|
||||||
impl DirentType for () {}
|
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> {
|
struct DirentBufWriter<'a> {
|
||||||
buf: &'a mut [u8],
|
buf: &'a mut [u8],
|
||||||
@ -114,7 +138,7 @@ impl<'a> DirentBufWriter<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_write<T: DirentType + Copy + Default>(
|
fn try_write<T: DirentType + Copy>(
|
||||||
&mut self,
|
&mut self,
|
||||||
dirent: &LinuxDirent<T>,
|
dirent: &LinuxDirent<T>,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -127,6 +151,21 @@ impl<'a> DirentBufWriter<'a> {
|
|||||||
ptr.write(*dirent);
|
ptr.write(*dirent);
|
||||||
let name_ptr = ptr.add(1) as _;
|
let name_ptr = ptr.add(1) as _;
|
||||||
write_cstr(name_ptr, name);
|
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::<LinuxDirent<T>>() + 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.rest_size -= dirent.len();
|
||||||
self.written_size += dirent.len();
|
self.written_size += dirent.len();
|
||||||
|
@ -7,6 +7,38 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "test_fs.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
|
// The test case of readdir
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -14,21 +46,28 @@
|
|||||||
static int test_readdir() {
|
static int test_readdir() {
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
|
char entries[32][256] = { 0 };
|
||||||
|
|
||||||
dirp = opendir("/");
|
dirp = opendir("/");
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
THROW_ERROR("failed to open directory");
|
THROW_ERROR("failed to open directory");
|
||||||
}
|
}
|
||||||
|
int entry_cnt = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
dp = readdir(dirp);
|
dp = readdir(dirp);
|
||||||
if (dp == NULL) {
|
if (dp == NULL) {
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
closedir(dirp);
|
closedir(dirp);
|
||||||
THROW_ERROR("faild to call readdir");
|
THROW_ERROR("failed to call readdir");
|
||||||
}
|
}
|
||||||
break;
|
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);
|
closedir(dirp);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user