1use alloc::{string::{String, ToString}, sync::Arc, vec::Vec, vec};
2use crate::{
3 abi::xv6::riscv64::fs::xv6fs::{Dirent, Stat},
4 arch::Trapframe,
5 device::manager::DeviceManager,
6 executor::TransparentExecutor,
7 fs::{
8 FileType,
9 SeekFrom,
10 DirectoryEntry, DeviceFileInfo,
12 },
13 library::std::string::{
14 cstring_to_string,
15 parse_c_string_from_userspace,
16 parse_string_array_from_userspace,
17 },
18 object::capability::StreamError,
19 sched::scheduler::get_scheduler,
20 task::mytask,
21};
22
23fn read_directory_as_xv6_dirent(buf_ptr: *mut u8, count: usize, buffer_data: &[u8]) -> usize {
25 if count < Dirent::DIRENT_SIZE {
26 return 0; }
28
29 if let Some(dir_entry) = DirectoryEntry::parse(buffer_data) {
31 let inum = (dir_entry.file_id & 0xFFFF) as u16; let name = dir_entry.name_str().unwrap_or("");
34
35 let xv6_dirent = Dirent::new(inum, name);
36
37 if count >= Dirent::DIRENT_SIZE {
39 let dirent_bytes = xv6_dirent.as_bytes();
41 unsafe {
42 core::ptr::copy_nonoverlapping(
43 dirent_bytes.as_ptr(),
44 buf_ptr,
45 Dirent::DIRENT_SIZE
46 );
47 }
48 return Dirent::DIRENT_SIZE;
49 }
50 }
51
52 0 }
54
55const MAX_PATH_LENGTH: usize = 128;
56const MAX_ARG_COUNT: usize = 64;
57
58pub fn sys_exec(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
59 let task = mytask().unwrap();
60
61 trapframe.increment_pc_next(task);
63
64 let path_ptr = trapframe.get_arg(0);
66 let argv_ptr = trapframe.get_arg(1);
67
68 let path_str = match parse_c_string_from_userspace(task, path_ptr, MAX_PATH_LENGTH) {
70 Ok(path) => match to_absolute_path_v2(&task, &path) {
71 Ok(abs_path) => abs_path,
72 Err(_) => return usize::MAX, },
74 Err(_) => return usize::MAX, };
76
77 let argv_strings = match parse_string_array_from_userspace(task, argv_ptr, MAX_ARG_COUNT, MAX_PATH_LENGTH) {
79 Ok(args) => args,
80 Err(_) => return usize::MAX, };
82
83 let argv_refs: Vec<&str> = argv_strings.iter().map(|s| s.as_str()).collect();
85
86 match TransparentExecutor::execute_binary(&path_str, &argv_refs, &[], task, trapframe, false) {
88 Ok(_) => {
89 trapframe.get_return_value()
93 },
94 Err(_) => {
95 usize::MAX }
99 }
100}
101
102#[repr(i32)]
103enum OpenMode {
104 ReadOnly = 0x000,
105 WriteOnly = 0x001,
106 ReadWrite = 0x002,
107 Create = 0x200,
108 Truncate = 0x400,
109}
110
111pub fn sys_open(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
112 let task = mytask().unwrap();
113 let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
114 let mode = trapframe.get_arg(1) as i32;
115
116 trapframe.increment_pc_next(task);
118
119 let path_str = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
121 Ok((path, _)) => match to_absolute_path_v2(&task, &path) {
122 Ok(abs_path) => abs_path,
123 Err(_) => return usize::MAX,
124 },
125 Err(_) => return usize::MAX, };
127
128 let vfs = task.vfs.as_ref().unwrap();
130
131 let file = vfs.open(&path_str, 0);
133
134 match file {
135 Ok(kernel_obj) => {
136 let handle = task.handle_table.insert(kernel_obj);
138 match handle {
139 Ok(handle) => {
140 match abi.allocate_fd(handle as u32) {
141 Ok(fd) => fd,
142 Err(_) => usize::MAX, }
144 },
145 Err(_) => usize::MAX, }
147 }
148 Err(_) =>{
149 if mode & OpenMode::Create as i32 != 0 {
151 let res = vfs.create_file(&path_str, FileType::RegularFile);
152 if res.is_err() {
153 return usize::MAX; }
155 match vfs.open(&path_str, 0) {
156 Ok(kernel_obj) => {
157 let handle = task.handle_table.insert(kernel_obj);
159 match handle {
160 Ok(handle) => {
161 match abi.allocate_fd(handle as u32) {
162 Ok(fd) => fd,
163 Err(_) => usize::MAX, }
165 },
166 Err(_) => usize::MAX, }
168 }
169 Err(_) => usize::MAX, }
171 } else {
172 return usize::MAX; }
174 }
175 }
176}
177
178pub fn sys_dup(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
179 let task = mytask().unwrap();
180 let fd = trapframe.get_arg(0) as usize;
181 trapframe.increment_pc_next(task);
182
183 if let Some(old_handle) = abi.get_handle(fd) {
185 if let Some(old_kernel_obj) = task.handle_table.get(old_handle) {
186 let kernel_obj = old_kernel_obj.clone();
187 let handle = task.handle_table.insert(kernel_obj);
188 match handle {
189 Ok(new_handle) => {
190 match abi.allocate_fd(new_handle as u32) {
191 Ok(fd) => fd,
192 Err(_) => usize::MAX, }
194 },
195 Err(_) => usize::MAX, }
197 } else {
198 usize::MAX }
200 } else {
201 usize::MAX }
203}
204
205pub fn sys_close(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
206 let task = mytask().unwrap();
207 let fd = trapframe.get_arg(0) as usize;
208 trapframe.increment_pc_next(task);
209
210 if let Some(handle) = abi.remove_fd(fd) {
212 if task.handle_table.remove(handle).is_some() {
213 0 } else {
215 usize::MAX }
217 } else {
218 usize::MAX }
220}
221
222pub fn sys_read(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
223 let task = mytask().unwrap();
224 let fd = trapframe.get_arg(0) as usize;
225 let buf_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1)).unwrap() as *mut u8;
226 let count = trapframe.get_arg(2) as usize;
227
228 let handle = match abi.get_handle(fd) {
230 Some(h) => h,
231 None => {
232 trapframe.increment_pc_next(task);
233 return usize::MAX; }
235 };
236
237 let kernel_obj = match task.handle_table.get(handle) {
238 Some(obj) => obj,
239 None => {
240 trapframe.increment_pc_next(task);
241 return usize::MAX; }
243 };
244
245 let is_directory = if let Some(file_obj) = kernel_obj.as_file() {
247 if let Ok(metadata) = file_obj.metadata() {
248 matches!(metadata.file_type, FileType::Directory)
249 } else {
250 false
251 }
252 } else {
253 false
254 };
255
256 let stream = match kernel_obj.as_stream() {
257 Some(stream) => stream,
258 None => {
259 trapframe.increment_pc_next(task);
260 return usize::MAX; }
262 };
263
264 if is_directory {
265 let directory_entry_size = core::mem::size_of::<DirectoryEntry>();
267 let mut temp_buffer = vec![0u8; directory_entry_size];
268
269 match stream.read(&mut temp_buffer) {
270 Ok(n) => {
271 trapframe.increment_pc_next(task); if n > 0 && n >= directory_entry_size {
273 let converted_bytes = read_directory_as_xv6_dirent(buf_ptr, count, &temp_buffer[..n]);
275 if converted_bytes > 0 {
276 return converted_bytes; }
278 }
279 0 },
281 Err(e) => {
282 match e {
283 StreamError::EndOfStream => {
284 trapframe.increment_pc_next(task); 0 },
287 StreamError::WouldBlock => {
288 get_scheduler().schedule(trapframe); },
293 _ => {
294 trapframe.increment_pc_next(task);
295 usize::MAX }
297 }
298 }
299 }
300 } else {
301 let mut buffer = unsafe { core::slice::from_raw_parts_mut(buf_ptr, count) };
303
304 match stream.read(&mut buffer) {
305 Ok(n) => {
306 trapframe.increment_pc_next(task); n
308 }, Err(e) => {
310 match e {
311 StreamError::EndOfStream => {
312 trapframe.increment_pc_next(task); 0 },
315 StreamError::WouldBlock => get_scheduler().schedule(trapframe), _ => {
317 trapframe.increment_pc_next(task); usize::MAX
320 }
321 }
322 }
323 }
324 }
325}
326
327pub fn sys_write(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
328 let task = mytask().unwrap();
329 let fd = trapframe.get_arg(0) as usize;
330 let buf_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1)).unwrap() as *const u8;
331 let count = trapframe.get_arg(2) as usize;
332
333 trapframe.increment_pc_next(task);
335
336 let handle = match abi.get_handle(fd) {
338 Some(h) => h,
339 None => return usize::MAX, };
341
342 let kernel_obj = match task.handle_table.get(handle) {
343 Some(obj) => obj,
344 None => return usize::MAX, };
346
347 let stream = match kernel_obj.as_stream() {
348 Some(stream) => stream,
349 None => return usize::MAX, };
351
352 let buffer = unsafe { core::slice::from_raw_parts(buf_ptr, count) };
353
354 match stream.write(buffer) {
355 Ok(n) => n,
356 Err(_) => usize::MAX, }
358}
359
360pub fn sys_lseek(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
361 let task = mytask().unwrap();
362 let fd = trapframe.get_arg(0) as usize;
363 let offset = trapframe.get_arg(1) as i64;
364 let whence = trapframe.get_arg(2) as i32;
365
366 trapframe.increment_pc_next(task);
368
369 let handle = match abi.get_handle(fd) {
371 Some(h) => h,
372 None => return usize::MAX, };
374
375 let kernel_obj = match task.handle_table.get(handle) {
376 Some(obj) => obj,
377 None => return usize::MAX, };
379
380 let file = match kernel_obj.as_file() {
381 Some(file) => file,
382 None => return usize::MAX, };
384
385 let whence = match whence {
386 0 => SeekFrom::Start(offset as u64),
387 1 => SeekFrom::Current(offset),
388 2 => SeekFrom::End(offset),
389 _ => return usize::MAX, };
391
392 match file.seek(whence) {
393 Ok(pos) => pos as usize,
394 Err(_) => usize::MAX, }
396}
397
398pub fn sys_mknod(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
400 let task = mytask().unwrap();
401 trapframe.increment_pc_next(task);
402 let name_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
403 let name = get_path_str_v2(name_ptr).unwrap();
404 let path = to_absolute_path_v2(&task, &name).unwrap();
405
406 let major = trapframe.get_arg(1) as u32;
407 let minor = trapframe.get_arg(2) as u32;
408
409 match (major, minor) {
410 (1, 0) => {
411 let console_dev = Some(DeviceManager::get_mut_manager().register_device(Arc::new(
413 crate::abi::xv6::drivers::console::ConsoleDevice::new(0, "console")
414 )));
415
416 let vfs = task.vfs.as_mut().unwrap();
417 let _res = vfs.create_file(&path, FileType::CharDevice(
418 DeviceFileInfo {
419 device_id: console_dev.unwrap(),
420 device_type: crate::device::DeviceType::Char,
421 }
422 ));
423 },
425 _ => {},
426 }
427 0
428}
429
430
431pub fn sys_fstat(abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut crate::arch::Trapframe) -> usize {
432 let fd = trapframe.get_arg(0) as usize;
433
434 let task = mytask()
435 .expect("sys_fstat: No current task found");
436 trapframe.increment_pc_next(task); let stat_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1) as usize)
439 .expect("sys_fstat: Failed to translate stat pointer") as *mut Stat;
440
441 let handle = match abi.get_handle(fd) {
443 Some(h) => h,
444 None => return usize::MAX, };
446
447 let kernel_obj = match task.handle_table.get(handle) {
448 Some(obj) => obj,
449 None => return usize::MAX, };
451
452 let file = match kernel_obj.as_file() {
453 Some(file) => file,
454 None => return usize::MAX, };
456
457 let metadata = file.metadata()
458 .expect("sys_fstat: Failed to get file metadata");
459
460 if stat_ptr.is_null() {
461 return usize::MAX; }
463
464 let stat = unsafe { &mut *stat_ptr };
465
466 *stat = Stat {
467 dev: 0,
468 ino: metadata.file_id as u32,
469 file_type: match metadata.file_type {
470 FileType::Directory => 1, FileType::RegularFile => 2, FileType::CharDevice(_) => 3, FileType::BlockDevice(_) => 3, _ => 0, },
476 nlink: 1,
477 size: metadata.size as u64,
478 };
479
480 0
481}
482
483pub fn sys_mkdir(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
484 let task = mytask().unwrap();
485 trapframe.increment_pc_next(task);
486
487 let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
488 let path = match get_path_str_v2(path_ptr) {
489 Ok(p) => to_absolute_path_v2(&task, &p).unwrap(),
490 Err(_) => return usize::MAX, };
492
493 let vfs = task.vfs.as_mut().unwrap();
495 match vfs.create_dir(&path) {
496 Ok(_) => 0, Err(_) => usize::MAX, }
499}
500
501pub fn sys_unlink(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
502 let task = mytask().unwrap();
503 trapframe.increment_pc_next(task);
504
505 let path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
506 let path = match cstring_to_string(path_ptr, MAX_PATH_LENGTH) {
507 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
508 Err(_) => return usize::MAX, };
510
511 let vfs = task.vfs.as_mut().unwrap();
513 match vfs.remove(&path) {
514 Ok(_) => 0, Err(_) => usize::MAX, }
517}
518
519pub fn sys_link(_abi: &mut crate::abi::xv6::riscv64::Xv6Riscv64Abi, trapframe: &mut Trapframe) -> usize {
520 let task = mytask().unwrap();
521 trapframe.increment_pc_next(task);
522
523 let src_path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(0)).unwrap() as *const u8;
524 let dst_path_ptr = task.vm_manager.translate_vaddr(trapframe.get_arg(1)).unwrap() as *const u8;
525
526 let src_path = match cstring_to_string(src_path_ptr, MAX_PATH_LENGTH) {
527 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
528 Err(_) => return usize::MAX, };
530
531 let dst_path = match cstring_to_string(dst_path_ptr, MAX_PATH_LENGTH) {
532 Ok((p, _)) => to_absolute_path_v2(&task, &p).unwrap(),
533 Err(_) => return usize::MAX, };
535
536 let vfs = task.vfs.as_ref().unwrap();
537 match vfs.create_hardlink(&src_path, &dst_path) {
538 Ok(_) => 0, Err(err) => {
540 use crate::fs::FileSystemErrorKind;
541
542 match err.kind {
544 FileSystemErrorKind::NotFound => {
545 2 },
548 FileSystemErrorKind::FileExists => {
549 17 },
552 FileSystemErrorKind::CrossDevice => {
553 18 },
556 FileSystemErrorKind::InvalidOperation => {
557 1 },
560 FileSystemErrorKind::PermissionDenied => {
561 13 },
563 _ => {
564 5 }
567 }
568 }
569 }
570}
571
572fn to_absolute_path_v2(task: &crate::task::Task, path: &str) -> Result<String, ()> {
575 if path.starts_with('/') {
576 Ok(path.to_string())
577 } else {
578 let cwd = task.cwd.clone().ok_or(())?;
579 let mut absolute_path = cwd;
580 if !absolute_path.ends_with('/') {
581 absolute_path.push('/');
582 }
583 absolute_path.push_str(path);
584 let mut components = Vec::new();
586 for comp in absolute_path.split('/') {
587 match comp {
588 "" | "." => {},
589 ".." => { components.pop(); },
590 _ => components.push(comp),
591 }
592 }
593 Ok("/".to_string() + &components.join("/"))
594 }
595}
596
597fn get_path_str_v2(ptr: *const u8) -> Result<String, ()> {
600 const MAX_PATH_LENGTH: usize = 128;
601 cstring_to_string(ptr, MAX_PATH_LENGTH).map(|(s, _)| s).map_err(|_| ())
602}