Skip to content

Commit 5b460bf

Browse files
committed
ch7: more util & builtin
1 parent c1966f2 commit 5b460bf

File tree

12 files changed

+360
-10
lines changed

12 files changed

+360
-10
lines changed

easy-fs/src/layout.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ impl DiskInode {
447447

448448
/// A directory entry
449449
#[repr(C)]
450+
#[derive(Clone)]
450451
pub struct DirEntry {
451452
name: [u8; NAME_LENGTH_LIMIT + 1], // filename len at most 27 + '\0'
452453
inode_number: u32,

easy-fs/src/vfs.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,40 @@ impl Inode {
100100
.map(f)
101101
}
102102

103+
/// Get inodes of dir entries
104+
pub fn dirents(&self, cursor: u32) -> Vec<(String, Arc<Inode>)> {
105+
let fs = self.fs.lock();
106+
let cursor = cursor as usize;
107+
self.read_disk_inode(|disk_inode| {
108+
assert!(disk_inode.is_dir());
109+
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
110+
if cursor >= file_count {
111+
return Vec::new();
112+
}
113+
let mut v = Vec::with_capacity(file_count - cursor);
114+
let mut dirent = DirEntry::new_empty();
115+
for i in cursor..file_count {
116+
assert_eq!(
117+
disk_inode.read_at(i * DIRENT_SZ, dirent.as_bytes_mut(), &self.block_device),
118+
DIRENT_SZ
119+
);
120+
let inode_id = dirent.inode_number();
121+
let (block_id, block_offset) = fs.get_disk_inode_pos(inode_id);
122+
v.push((
123+
String::from(dirent.name()),
124+
Arc::new(Self::new(
125+
inode_id,
126+
block_id,
127+
block_offset,
128+
self.fs.clone(),
129+
self.block_device.clone(),
130+
)),
131+
))
132+
}
133+
v
134+
})
135+
}
136+
103137
/// Find inode under current inode(recursively) by name
104138
pub fn find(&self, path: &str) -> Option<Arc<Inode>> {
105139
let fs = self.fs.lock();
@@ -246,7 +280,6 @@ impl Inode {
246280

247281
fn clear_locked(&self, fs: &mut EasyFileSystem) {
248282
self.modify_disk_inode(|disk_inode| {
249-
assert!(disk_inode.is_file());
250283
let size = disk_inode.size;
251284
let data_blocks_dealloc = disk_inode.clear_size(&self.block_device);
252285
assert_eq!(

os/src/syscall/fs.rs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,22 +249,25 @@ pub struct Stat {
249249
pub ino: u64,
250250
pub mode: StatMode,
251251
pub nlink: u32,
252-
pad: [u64; 7],
252+
pub size: u64, // added
253+
pad: [u64; 6],
253254
}
254255

255256
impl Stat {
256-
pub fn new(ino: u64, mode: StatMode, nlink: u32) -> Self {
257+
pub fn new(ino: u64, mode: StatMode, nlink: u32, size: u64) -> Self {
257258
Self {
258259
dev: 0,
259260
ino,
260261
mode,
261262
nlink,
262-
pad: [0; 7],
263+
size,
264+
pad: [0; 6],
263265
}
264266
}
265267
}
266268

267269
bitflags! {
270+
#[derive(Default)]
268271
pub struct StatMode: u32 {
269272
const NULL = 0;
270273
/// directory
@@ -295,8 +298,9 @@ pub fn sys_fstat(fd: usize, ptr: *mut Stat) -> isize {
295298
} else {
296299
StatMode::NULL
297300
};
301+
let size = inode.get_size();
298302
let nlink = inode.nlink();
299-
let stat = Stat::new(ino as u64, mode, nlink);
303+
let stat = Stat::new(ino as u64, mode, nlink, size as u64);
300304

301305
let dst_vs = mm::translated_byte_buffer(
302306
task_inner.get_user_token(),
@@ -339,3 +343,61 @@ pub fn sys_dup(fd: usize) -> isize {
339343
inner.fd_table[new_fd] = Some(file);
340344
new_fd as isize
341345
}
346+
347+
/// The max length of inode name
348+
const NAME_LENGTH_LIMIT: usize = 27;
349+
#[repr(C, align(32))]
350+
#[derive(Clone, Default)]
351+
pub struct Dirent {
352+
pub ftype: FileType,
353+
pub name: [u8; NAME_LENGTH_LIMIT],
354+
pub next_offset: u32,
355+
}
356+
357+
bitflags! {
358+
#[derive(Default)]
359+
pub struct FileType: u8 {
360+
const UNKNOWN = 0;
361+
const DIR = 1 << 0;
362+
const REG = 1 << 1;
363+
}
364+
}
365+
366+
pub fn sys_getdents(fd: usize, ptr: *mut Dirent, len: usize) -> isize {
367+
let task = task::current_task().unwrap();
368+
let inner = task.inner_exclusive_access();
369+
let token = inner.get_user_token();
370+
371+
let file = match inner.fd_table.get(fd) {
372+
Some(Some(file)) => {
373+
let file_clone = file.clone();
374+
match file_clone.downcast_arc::<OSInode>() {
375+
Some(os_inode) if os_inode.is_dir() => os_inode.clone_inner_inode(),
376+
_ => return -1,
377+
}
378+
}
379+
_ => return -1,
380+
};
381+
let cursor = mm::translate_ref(token, unsafe { ptr.add(len - 1) }).next_offset;
382+
let dirents = file.dirents(cursor);
383+
let nread = len.min(dirents.len());
384+
for i in 0..nread {
385+
let ename = dirents[i].0.as_bytes();
386+
let inode = &dirents[i].1;
387+
let ftype = if inode.is_dir() {
388+
FileType::DIR
389+
} else if inode.is_file() {
390+
FileType::REG
391+
} else {
392+
FileType::UNKNOWN
393+
};
394+
let mut name = [0u8; NAME_LENGTH_LIMIT];
395+
name[..ename.len()].copy_from_slice(&ename[..]);
396+
*mm::translated_refmut(token, unsafe { ptr.add(i) }) = Dirent {
397+
ftype,
398+
name,
399+
next_offset: cursor + i as u32 + 1,
400+
};
401+
}
402+
nread as isize
403+
}

os/src/syscall/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const SYSCALL_CHDIR: usize = 49;
1515
const SYSCALL_OPENAT: usize = 56;
1616
const SYSCALL_CLOSE: usize = 57;
1717
const SYSCALL_PIPE: usize = 59;
18+
const SYSCALL_GETDENTS: usize = 61;
1819
const SYSCALL_READ: usize = 63;
1920
const SYSCALL_WRITE: usize = 64;
2021
const SYSCALL_FSTAT: usize = 80;
@@ -54,6 +55,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
5455
SYSCALL_OPENAT => sys_openat(args[0] as isize, args[1] as *const u8, args[2] as u32),
5556
SYSCALL_CLOSE => sys_close(args[0]),
5657
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
58+
SYSCALL_GETDENTS => sys_getdents(args[0], args[1] as *mut _, args[2]),
5759
SYSCALL_READ => sys_read(args[0], args[1] as *const u8, args[2]),
5860
SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),
5961
SYSCALL_FSTAT => sys_fstat(args[0] as usize, args[1] as *mut Stat),
@@ -63,7 +65,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
6365
SYSCALL_SIGACTION => sys_sigaction(args[0] as i32, args[1] as *const _, args[2] as *mut _),
6466
SYSCALL_SIGPROCMASK => sys_sigprocmask(args[0] as u32),
6567
SYSCALL_SIGRETURN => sys_sigreturn(),
66-
SYSCALL_GET_TIME => sys_get_time(args[0] as *mut TimeVal),
68+
SYSCALL_GET_TIME => sys_get_time(args[0] as *mut _),
6769
SYSCALL_GETPID => sys_getpid(),
6870
SYSCALL_MUNMAP => sys_munmap(args[0], args[1]),
6971
SYSCALL_FORK => sys_fork(),

user/src/bin/echo.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
#[macro_use]
5+
extern crate user_lib;
6+
extern crate alloc;
7+
8+
#[no_mangle]
9+
fn main(_argc: usize, argv: &[&str]) -> i32 {
10+
let s = argv[1..].join(" ");
11+
println!("{}", s);
12+
0
13+
}

user/src/bin/ls.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use alloc::vec;
5+
use user_lib::{exit, getdents, open, Dirent, FileType, OpenFlags};
6+
7+
#[macro_use]
8+
extern crate user_lib;
9+
extern crate alloc;
10+
11+
#[no_mangle]
12+
fn main(argc: usize, argv: &[&str]) -> i32 {
13+
let path = if argc == 1 {
14+
".\0"
15+
} else if argc == 2 {
16+
argv[1]
17+
} else {
18+
panic!("wrong number of args!");
19+
};
20+
let fd = open(path, OpenFlags::RDONLY);
21+
if fd == -1 {
22+
println!("Error open {}", path);
23+
exit(-1);
24+
}
25+
26+
const BUF_SIZE: usize = 16;
27+
let mut total = 0usize;
28+
let mut entries = vec![Dirent::default(); BUF_SIZE];
29+
let mut n = BUF_SIZE;
30+
loop {
31+
n = match getdents(fd as usize, &mut entries.as_mut_slice()[..n]) {
32+
-1 => {
33+
println!("Error read dir {}", path);
34+
exit(-1);
35+
unreachable!()
36+
}
37+
0 => break,
38+
v => v as usize,
39+
};
40+
total += n;
41+
for i in 0..n {
42+
let entry = &entries[i];
43+
let color_code = match entry.ftype {
44+
FileType::DIR => 94,
45+
FileType::REG => 0,
46+
_ => panic!("unknown file type {}", entry.name()),
47+
};
48+
print_color(format_args!("{}\n", entry.name()), color_code);
49+
}
50+
}
51+
print_color(format_args!("total {}\n", total), 90);
52+
0
53+
}
54+
55+
fn print_color(args: core::fmt::Arguments, color_code: u8) {
56+
print!("\u{1b}[{}m{}\u{1b}[0m", color_code, args);
57+
}

user/src/bin/mkdir.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use user_lib::{exit, mkdir};
5+
6+
#[macro_use]
7+
extern crate user_lib;
8+
9+
#[no_mangle]
10+
fn main(argc: usize, argv: &[&str]) -> i32 {
11+
assert_eq!(argc, 2, "wrong number of args!");
12+
let path = argv[1];
13+
14+
if mkdir(path) == -1 {
15+
println!("Error mkdir {}", path);
16+
exit(-1);
17+
}
18+
0
19+
}

user/src/bin/stat.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use user_lib::{exit, fstat, open, OpenFlags, Stat};
5+
6+
#[macro_use]
7+
extern crate user_lib;
8+
9+
#[no_mangle]
10+
fn main(argc: usize, argv: &[&str]) -> i32 {
11+
assert_eq!(argc, 2, "wrong number of args!");
12+
let path = argv[1];
13+
14+
let fd = open(path, OpenFlags::RDONLY);
15+
if fd == -1 {
16+
println!("Error open {}", path);
17+
exit(-1);
18+
}
19+
let mut stat = Stat::new();
20+
if fstat(fd as usize, &mut stat) == -1 {
21+
println!("Error unlink {}", path);
22+
exit(-1);
23+
}
24+
25+
println!("File: {}", path);
26+
println!("Size: {}\t{:?}", stat.size, stat.mode);
27+
println!("Device: {}", stat.dev);
28+
println!("Inode: {}", stat.ino);
29+
0
30+
}

user/src/bin/unlink.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use user_lib::{exit, fstat, open, unlink, OpenFlags, Stat, StatMode};
5+
6+
#[macro_use]
7+
extern crate user_lib;
8+
9+
#[no_mangle]
10+
fn main(argc: usize, argv: &[&str]) -> i32 {
11+
assert_eq!(argc, 2, "wrong number of args!");
12+
let path = argv[1];
13+
14+
let fd = open(path, OpenFlags::RDONLY);
15+
if fd == -1 {
16+
println!("Error open {}", path);
17+
exit(-1);
18+
}
19+
let mut stat = Stat::new();
20+
if fstat(fd as usize, &mut stat) == -1 {
21+
println!("Error fstat {}", path);
22+
exit(-1);
23+
}
24+
25+
const DIRENT_SZ: usize = 32;
26+
if stat.mode == StatMode::DIR && stat.size as usize > 2 * DIRENT_SZ {
27+
// 2 dirent: . and ..
28+
println!("Directory not empty!");
29+
exit(-1);
30+
}
31+
32+
if unlink(path) == -1 {
33+
println!("Error unlink {}", path);
34+
exit(-1);
35+
}
36+
0
37+
}

0 commit comments

Comments
 (0)