Add fcntl
This commit is contained in:
		
							parent
							
								
									785d3237b9
								
							
						
					
					
						commit
						44ef19726f
					
				| @ -11,12 +11,6 @@ pub struct FileTable { | ||||
|     num_fds: usize, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| struct FileTableEntry { | ||||
|     file: FileRef, | ||||
|     close_on_spawn: bool, | ||||
| } | ||||
| 
 | ||||
| impl FileTable { | ||||
|     pub fn new() -> FileTable { | ||||
|         FileTable { | ||||
| @ -25,12 +19,38 @@ impl FileTable { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn dup(&mut self, fd: FileDesc, min_fd: FileDesc, close_on_spawn: bool) -> Result<FileDesc, Error> { | ||||
|         let file_ref = self.get(fd)?; | ||||
| 
 | ||||
|         let min_fd = min_fd as usize; | ||||
|         let min_free_fd = { | ||||
|             let mut table = &mut self.table; | ||||
| 
 | ||||
|             // Make sure that min_fd does not exceed the capacity of the table
 | ||||
|             if min_fd >= table.len() { | ||||
|                 let expand_size = min_fd - table.len() + 1; | ||||
|                 for _ in 0..expand_size { | ||||
|                     table.push(None) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             table.iter() | ||||
|                 .enumerate() | ||||
|                 .skip(min_fd as usize) | ||||
|                 .find(|&(idx, opt)| opt.is_none()) | ||||
|                 .unwrap().0 | ||||
|         } as FileDesc; | ||||
| 
 | ||||
|         self.put_at(min_free_fd, file_ref, close_on_spawn); | ||||
| 
 | ||||
|         Ok(min_free_fd) | ||||
|     } | ||||
| 
 | ||||
|     pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { | ||||
|         let mut table = &mut self.table; | ||||
| 
 | ||||
|         let min_free_fd = if self.num_fds < table.len() { | ||||
|             table | ||||
|                 .iter() | ||||
|             table.iter() | ||||
|                 .enumerate() | ||||
|                 .find(|&(idx, opt)| opt.is_none()) | ||||
|                 .unwrap() | ||||
| @ -59,13 +79,30 @@ impl FileTable { | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { | ||||
|         let entry = self.get_entry(fd)?; | ||||
|         Ok(entry.file.clone()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry, Error> { | ||||
|         if fd as usize >= self.table.len() { | ||||
|             return errno!(EBADF, "Invalid file descriptor"); | ||||
|         } | ||||
| 
 | ||||
|         let table = &self.table; | ||||
|         match table[fd as usize].as_ref() { | ||||
|             Some(table_entry) => Ok(table_entry.file.clone()), | ||||
|             Some(table_entry) => Ok(table_entry), | ||||
|             None => errno!(EBADF, "Invalid file descriptor"), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry, Error> { | ||||
|         if fd as usize >= self.table.len() { | ||||
|             return errno!(EBADF, "Invalid file descriptor"); | ||||
|         } | ||||
| 
 | ||||
|         let table = &mut self.table; | ||||
|         match table[fd as usize].as_mut() { | ||||
|             Some(table_entry) => Ok(table_entry), | ||||
|             None => errno!(EBADF, "Invalid file descriptor"), | ||||
|         } | ||||
|     } | ||||
| @ -114,11 +151,33 @@ impl Clone for FileTable { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FileTableEntry { | ||||
|     file: FileRef, | ||||
|     close_on_spawn: bool, | ||||
| } | ||||
| 
 | ||||
| impl FileTableEntry { | ||||
|     fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||
|     pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||
|         FileTableEntry { | ||||
|             file, | ||||
|             close_on_spawn, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_file(&self) -> &FileRef { | ||||
|         &self.file | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_close_on_spawn(&self) -> bool { | ||||
|         self.close_on_spawn | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_file_mut(&mut self) -> &mut FileRef { | ||||
|         &mut self.file | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_close_on_spawn(&mut self, close_on_spawn: bool) { | ||||
|         self.close_on_spawn = close_on_spawn; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -390,7 +390,7 @@ fn split_path(path: &str) -> (&str, &str) { | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     struct OpenFlags: u32 { | ||||
|     pub struct OpenFlags: u32 { | ||||
|         /// read only
 | ||||
|         const RDONLY = 0; | ||||
|         /// write only
 | ||||
| @ -614,3 +614,84 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) { | ||||
|     ptr.copy_from(s.as_ptr(), s.len()); | ||||
|     ptr.add(s.len()).write(0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum FcntlCmd { | ||||
|     /// Duplicate the file descriptor fd using the lowest-numbered available
 | ||||
|     /// file descriptor greater than or equal to arg.
 | ||||
|     DupFd(FileDesc), | ||||
|     /// As for `DupFd`, but additionally set the close-on-exec flag for the
 | ||||
|     /// duplicate file descriptor.
 | ||||
|     DupFdCloexec(FileDesc), | ||||
|     /// Return (as the function result) the file descriptor flags
 | ||||
|     GetFd(), | ||||
|     /// Set the file descriptor to be close-on-exec or not
 | ||||
|     SetFd(u32), | ||||
|     /// Get the file status flags
 | ||||
|     GetFl(), | ||||
|     /// Set the file status flags
 | ||||
|     SetFl(OpenFlags), | ||||
| } | ||||
| 
 | ||||
| pub const F_DUPFD : u32             = 0; | ||||
| pub const F_GETFD : u32             = 1; | ||||
| pub const F_SETFD : u32             = 2; | ||||
| pub const F_GETFL : u32             = 3; | ||||
| pub const F_SETFL : u32             = 4; | ||||
| pub const F_DUPFD_CLOEXEC : u32     = 1030; | ||||
| 
 | ||||
| pub const FD_CLOEXEC : u32          = 1; | ||||
| 
 | ||||
| impl FcntlCmd { | ||||
|     #[deny(unreachable_patterns)] | ||||
|     pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd, Error> { | ||||
|         Ok(match cmd { | ||||
|             F_DUPFD => FcntlCmd::DupFd(arg as FileDesc), | ||||
|             F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc), | ||||
|             F_GETFD => FcntlCmd::GetFd(), | ||||
|             F_SETFD => FcntlCmd::SetFd(arg as u32), | ||||
|             F_GETFL => FcntlCmd::GetFl(), | ||||
|             F_SETFL => FcntlCmd::SetFl(OpenFlags::from_bits_truncate(arg as u32)), | ||||
|             _ => return errno!(EINVAL, "invalid command"), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> { | ||||
|     info!("do_fcntl: {:?}, {:?}", &fd, cmd); | ||||
|     let current_ref = process::get_current(); | ||||
|     let mut current = current_ref.lock().unwrap(); | ||||
|     let files_ref = current.get_files(); | ||||
|     let mut files = files_ref.lock().unwrap(); | ||||
|     Ok(match cmd { | ||||
|         FcntlCmd::DupFd(min_fd) => { | ||||
|             let dup_fd = files.dup(fd, *min_fd, false)?; | ||||
|             dup_fd as isize | ||||
|         }, | ||||
|         FcntlCmd::DupFdCloexec(min_fd) => { | ||||
|             let dup_fd = files.dup(fd, *min_fd, true)?; | ||||
|             dup_fd as isize | ||||
|         }, | ||||
|         FcntlCmd::GetFd() => { | ||||
|             let entry = files.get_entry(fd)?; | ||||
|             let fd_flags = if entry.is_close_on_spawn() { | ||||
|                 FD_CLOEXEC | ||||
|             } else { | ||||
|                 0 | ||||
|             }; | ||||
|             fd_flags as isize | ||||
|         }, | ||||
|         FcntlCmd::SetFd(fd_flags) => { | ||||
|             let entry = files.get_entry_mut(fd)?; | ||||
|             entry.set_close_on_spawn((fd_flags & FD_CLOEXEC) != 0); | ||||
|             0 | ||||
|         }, | ||||
|         FcntlCmd::GetFl() => { | ||||
|             unimplemented!(); | ||||
|         }, | ||||
|         FcntlCmd::SetFl(flags) => { | ||||
|             unimplemented!(); | ||||
|         }, | ||||
|     }) | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use {fs, process, std, vm}; | ||||
| use fs::{File, FileDesc, off_t, AccessModes, AccessFlags, AT_FDCWD}; | ||||
| use fs::{File, FileDesc, off_t, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; | ||||
| use prelude::*; | ||||
| use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | ||||
| use std::ffi::{CStr, CString}; | ||||
| @ -72,6 +72,7 @@ pub extern "C" fn dispatch_syscall( | ||||
|         SYS_RMDIR => do_rmdir(arg0 as *const i8), | ||||
|         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), | ||||
|         SYS_UNLINK => do_unlink(arg0 as *const i8), | ||||
|         SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), | ||||
| 
 | ||||
|         SYS_EXIT => do_exit(arg0 as i32), | ||||
|         SYS_SPAWN => do_spawn( | ||||
| @ -726,6 +727,11 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> { | ||||
|     let cmd = FcntlCmd::from_raw(cmd, arg)?; | ||||
|     fs::do_fcntl(fd, &cmd) | ||||
| } | ||||
| 
 | ||||
| fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { | ||||
|     let code = process::ArchPrctlCode::from_u32(code)?; | ||||
|     check_mut_ptr(addr)?; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user