Add fcntl
This commit is contained in:
		
							parent
							
								
									785d3237b9
								
							
						
					
					
						commit
						44ef19726f
					
				| @ -11,12 +11,6 @@ pub struct FileTable { | |||||||
|     num_fds: usize, |     num_fds: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| struct FileTableEntry { |  | ||||||
|     file: FileRef, |  | ||||||
|     close_on_spawn: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl FileTable { | impl FileTable { | ||||||
|     pub fn new() -> FileTable { |     pub fn new() -> FileTable { | ||||||
|         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 { |     pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { | ||||||
|         let mut table = &mut self.table; |         let mut table = &mut self.table; | ||||||
| 
 | 
 | ||||||
|         let min_free_fd = if self.num_fds < table.len() { |         let min_free_fd = if self.num_fds < table.len() { | ||||||
|             table |             table.iter() | ||||||
|                 .iter() |  | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|                 .find(|&(idx, opt)| opt.is_none()) |                 .find(|&(idx, opt)| opt.is_none()) | ||||||
|                 .unwrap() |                 .unwrap() | ||||||
| @ -59,13 +79,30 @@ impl FileTable { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { |     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() { |         if fd as usize >= self.table.len() { | ||||||
|             return errno!(EBADF, "Invalid file descriptor"); |             return errno!(EBADF, "Invalid file descriptor"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let table = &self.table; |         let table = &self.table; | ||||||
|         match table[fd as usize].as_ref() { |         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"), |             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 { | impl FileTableEntry { | ||||||
|     fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { |     pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||||
|         FileTableEntry { |         FileTableEntry { | ||||||
|             file, |             file, | ||||||
|             close_on_spawn, |             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! { | bitflags! { | ||||||
|     struct OpenFlags: u32 { |     pub struct OpenFlags: u32 { | ||||||
|         /// read only
 |         /// read only
 | ||||||
|         const RDONLY = 0; |         const RDONLY = 0; | ||||||
|         /// write only
 |         /// 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.copy_from(s.as_ptr(), s.len()); | ||||||
|     ptr.add(s.len()).write(0); |     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, 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 prelude::*; | ||||||
| use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | ||||||
| use std::ffi::{CStr, CString}; | use std::ffi::{CStr, CString}; | ||||||
| @ -72,6 +72,7 @@ pub extern "C" fn dispatch_syscall( | |||||||
|         SYS_RMDIR => do_rmdir(arg0 as *const i8), |         SYS_RMDIR => do_rmdir(arg0 as *const i8), | ||||||
|         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), |         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), | ||||||
|         SYS_UNLINK => do_unlink(arg0 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_EXIT => do_exit(arg0 as i32), | ||||||
|         SYS_SPAWN => do_spawn( |         SYS_SPAWN => do_spawn( | ||||||
| @ -726,6 +727,11 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> { | |||||||
|     Ok(0) |     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> { | fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { | ||||||
|     let code = process::ArchPrctlCode::from_u32(code)?; |     let code = process::ArchPrctlCode::from_u32(code)?; | ||||||
|     check_mut_ptr(addr)?; |     check_mut_ptr(addr)?; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user