occlum/src/libos/src/fs/file_ops/dirent.rs
Tate, Hongliang Tian 5933499f9b Refactor LibOS to conform with logging strategy
This commit introduces a unified logging strategy, summarized as below:

1. Use `error!` to mark errors or unexpected conditions, e.g., a
 `Result::Err` returned from a system call.
2. Use `warn!` to warn about potentially problematic issues, e.g.,
 executing a workaround or fake implementation.
3. Use `info!` to show important events (from users' perspective) in
 normal execution, e.g., creating/exiting a process/thread.
4. Use `debug!` to track major events in normal execution, e.g., the
 high-level arguments of a system call.
5. Use `trace!` to record the most detailed info, e.g., when a system
 call enters and exits the LibOS.
2020-03-25 02:53:31 +00:00

101 lines
2.8 KiB
Rust

use super::*;
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
struct LinuxDirent64 {
/// Inode number
ino: u64,
/// Offset to next structure
offset: u64,
/// Size of this dirent
reclen: u16,
/// File type
type_: u8,
/// Filename (null-terminated)
name: [u8; 0],
}
struct DirentBufWriter<'a> {
buf: &'a mut [u8],
rest_size: usize,
written_size: usize,
}
impl<'a> DirentBufWriter<'a> {
unsafe fn new(buf: &'a mut [u8]) -> Self {
let rest_size = buf.len();
DirentBufWriter {
buf,
rest_size,
written_size: 0,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> Result<()> {
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
let len = (len + 7) / 8 * 8; // align up
if self.rest_size < len {
return_errno!(EINVAL, "the given buffer is too small");
}
let dent = LinuxDirent64 {
ino: inode,
offset: 0,
reclen: len as u16,
type_,
name: [],
};
unsafe {
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent64;
ptr.write(dent);
let name_ptr = ptr.add(1) as _;
write_cstr(name_ptr, name);
}
self.rest_size -= len;
self.written_size += len;
Ok(())
}
}
/// Write a Rust string to C string
unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
debug!(
"getdents64: fd: {}, buf: {:?}, buf_size: {}",
fd,
buf.as_ptr(),
buf.len()
);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let info = file_ref.metadata()?;
if info.type_ != FileType::Dir {
return_errno!(ENOTDIR, "");
}
let mut writer = unsafe { DirentBufWriter::new(buf) };
loop {
let name = match file_ref.read_entry() {
Err(e) => {
let errno = e.errno();
if errno == ENOENT {
break;
}
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
}
Ok(name) => name,
};
// TODO: get ino from dirent
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)
}