filearray.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. use core::sync::atomic::Ordering;
  2. use crate::{
  3. kernel::{
  4. console::CONSOLE,
  5. constants::ENXIO,
  6. task::Thread,
  7. vfs::{dentry::Dentry, file::Pipe, s_isdir, s_isreg},
  8. CharDevice,
  9. },
  10. path::Path,
  11. prelude::*,
  12. };
  13. use alloc::{
  14. collections::btree_map::{BTreeMap, Entry},
  15. sync::Arc,
  16. };
  17. use bindings::{
  18. EBADF, EISDIR, ENOTDIR, FD_CLOEXEC, F_DUPFD, F_DUPFD_CLOEXEC, F_GETFD, F_SETFD, O_APPEND,
  19. O_CLOEXEC, O_DIRECTORY, O_RDWR, O_TRUNC, O_WRONLY,
  20. };
  21. use itertools::{
  22. FoldWhile::{Continue, Done},
  23. Itertools,
  24. };
  25. use super::{
  26. file::{File, InodeFile, TerminalFile},
  27. inode::Mode,
  28. s_ischr, FsContext, Spin,
  29. };
  30. type FD = u32;
  31. #[derive(Clone)]
  32. struct OpenFile {
  33. /// File descriptor flags, only for `FD_CLOEXEC`.
  34. flags: u64,
  35. file: Arc<File>,
  36. }
  37. #[derive(Clone)]
  38. struct FileArrayInner {
  39. files: BTreeMap<FD, OpenFile>,
  40. fd_min_avail: FD,
  41. }
  42. pub struct FileArray {
  43. inner: Spin<FileArrayInner>,
  44. }
  45. impl OpenFile {
  46. pub fn close_on_exec(&self) -> bool {
  47. self.flags & O_CLOEXEC as u64 != 0
  48. }
  49. }
  50. impl FileArray {
  51. pub fn get_current<'lt>() -> &'lt Arc<Self> {
  52. &Thread::current().borrow().files
  53. }
  54. pub fn new() -> Arc<Self> {
  55. Arc::new(FileArray {
  56. inner: Spin::new(FileArrayInner {
  57. files: BTreeMap::new(),
  58. fd_min_avail: 0,
  59. }),
  60. })
  61. }
  62. #[allow(dead_code)]
  63. pub fn new_shared(other: &Arc<Self>) -> Arc<Self> {
  64. other.clone()
  65. }
  66. pub fn new_cloned(other: &Self) -> Arc<Self> {
  67. Arc::new(Self {
  68. inner: Spin::clone(&other.inner),
  69. })
  70. }
  71. /// Acquires the file array lock.
  72. pub fn get(&self, fd: FD) -> Option<Arc<File>> {
  73. self.inner.lock().get(fd)
  74. }
  75. pub fn close_all(&self) {
  76. let mut inner = self.inner.lock();
  77. inner.fd_min_avail = 0;
  78. inner.files.clear();
  79. }
  80. pub fn close(&self, fd: FD) -> KResult<()> {
  81. let mut inner = self.inner.lock();
  82. inner.files.remove(&fd).ok_or(EBADF)?;
  83. inner.release_fd(fd);
  84. Ok(())
  85. }
  86. pub fn on_exec(&self) -> () {
  87. let mut inner = self.inner.lock();
  88. // TODO: This is not efficient. We should avoid cloning.
  89. let fds_to_close = inner
  90. .files
  91. .iter()
  92. .filter(|(_, ofile)| ofile.close_on_exec())
  93. .map(|(&fd, _)| fd)
  94. .collect::<Vec<_>>();
  95. inner.files.retain(|_, ofile| !ofile.close_on_exec());
  96. fds_to_close.into_iter().for_each(|fd| inner.release_fd(fd));
  97. }
  98. }
  99. impl FileArray {
  100. pub fn dup(&self, old_fd: FD) -> KResult<FD> {
  101. let mut inner = self.inner.lock();
  102. let old_file = inner.files.get(&old_fd).ok_or(EBADF)?;
  103. let new_file_data = old_file.file.clone();
  104. let new_file_flags = old_file.flags;
  105. let new_fd = inner.next_fd();
  106. inner.do_insert(new_fd, new_file_flags, new_file_data);
  107. Ok(new_fd)
  108. }
  109. pub fn dup_to(&self, old_fd: FD, new_fd: FD, flags: u64) -> KResult<FD> {
  110. let mut inner = self.inner.lock();
  111. let old_file = inner.files.get(&old_fd).ok_or(EBADF)?;
  112. let new_file_data = old_file.file.clone();
  113. match inner.files.entry(new_fd) {
  114. Entry::Vacant(_) => {}
  115. Entry::Occupied(entry) => {
  116. let new_file = entry.into_mut();
  117. new_file.flags = flags;
  118. new_file.file = new_file_data;
  119. return Ok(new_fd);
  120. }
  121. }
  122. assert_eq!(new_fd, inner.allocate_fd(new_fd));
  123. inner.do_insert(new_fd, flags, new_file_data);
  124. Ok(new_fd)
  125. }
  126. /// # Return
  127. /// `(read_fd, write_fd)`
  128. pub fn pipe(&self, flags: u32) -> KResult<(FD, FD)> {
  129. let mut inner = self.inner.lock();
  130. let read_fd = inner.next_fd();
  131. let write_fd = inner.next_fd();
  132. let fdflag = if flags & O_CLOEXEC != 0 { FD_CLOEXEC } else { 0 };
  133. let pipe = Pipe::new();
  134. let (read_end, write_end) = pipe.split();
  135. inner.do_insert(read_fd, fdflag as u64, read_end);
  136. inner.do_insert(write_fd, fdflag as u64, write_end);
  137. Ok((read_fd, write_fd))
  138. }
  139. pub fn open(&self, fs_context: &FsContext, path: Path, flags: u32, mode: Mode) -> KResult<FD> {
  140. let dentry = Dentry::open(fs_context, path, true)?;
  141. dentry.open_check(flags, mode)?;
  142. let fdflag = if flags & O_CLOEXEC != 0 { FD_CLOEXEC } else { 0 };
  143. let can_read = flags & O_WRONLY == 0;
  144. let can_write = flags & (O_WRONLY | O_RDWR) != 0;
  145. let append = flags & O_APPEND != 0;
  146. let inode = dentry.get_inode()?;
  147. let filemode = inode.mode.load(Ordering::Relaxed);
  148. if flags & O_DIRECTORY != 0 {
  149. if !s_isdir(filemode) {
  150. return Err(ENOTDIR);
  151. }
  152. } else {
  153. if s_isdir(filemode) && can_write {
  154. return Err(EISDIR);
  155. }
  156. }
  157. if flags & O_TRUNC != 0 {
  158. if can_write && s_isreg(filemode) {
  159. inode.truncate(0)?;
  160. }
  161. }
  162. let mut inner = self.inner.lock();
  163. let fd = inner.next_fd();
  164. if s_ischr(filemode) {
  165. let device = CharDevice::get(inode.devid()?).ok_or(ENXIO)?;
  166. let file = device.open()?;
  167. inner.do_insert(fd, fdflag as u64, file);
  168. } else {
  169. inner.do_insert(
  170. fd,
  171. fdflag as u64,
  172. InodeFile::new(dentry, (can_read, can_write, append)),
  173. );
  174. }
  175. Ok(fd)
  176. }
  177. pub fn fcntl(&self, fd: FD, cmd: u32, arg: usize) -> KResult<usize> {
  178. let mut inner = self.inner.lock();
  179. let ofile = inner.files.get_mut(&fd).ok_or(EBADF)?;
  180. match cmd {
  181. F_DUPFD | F_DUPFD_CLOEXEC => {
  182. let cloexec = cmd == F_DUPFD_CLOEXEC || (ofile.flags & FD_CLOEXEC as u64 != 0);
  183. let flags = if cloexec { O_CLOEXEC } else { 0 };
  184. let new_file_data = ofile.file.clone();
  185. let new_fd = inner.allocate_fd(arg as FD);
  186. inner.do_insert(new_fd, flags as u64, new_file_data);
  187. Ok(new_fd as usize)
  188. }
  189. F_GETFD => Ok(ofile.flags as usize),
  190. F_SETFD => {
  191. ofile.flags = arg as u64;
  192. Ok(0)
  193. }
  194. _ => unimplemented!("fcntl: cmd={}", cmd),
  195. }
  196. }
  197. /// Only used for init process.
  198. pub fn open_console(&self) {
  199. let mut inner = self.inner.lock();
  200. let (stdin, stdout, stderr) = (inner.next_fd(), inner.next_fd(), inner.next_fd());
  201. let console_terminal = CONSOLE.lock_irq().get_terminal().unwrap();
  202. inner.do_insert(
  203. stdin,
  204. O_CLOEXEC as u64,
  205. TerminalFile::new(console_terminal.clone()),
  206. );
  207. inner.do_insert(
  208. stdout,
  209. O_CLOEXEC as u64,
  210. TerminalFile::new(console_terminal.clone()),
  211. );
  212. inner.do_insert(
  213. stderr,
  214. O_CLOEXEC as u64,
  215. TerminalFile::new(console_terminal.clone()),
  216. );
  217. }
  218. }
  219. impl FileArrayInner {
  220. fn get(&mut self, fd: FD) -> Option<Arc<File>> {
  221. self.files.get(&fd).map(|f| f.file.clone())
  222. }
  223. fn find_available(&mut self, from: FD) -> FD {
  224. self.files
  225. .range(&from..)
  226. .fold_while(from, |current, (&key, _)| {
  227. if current == key {
  228. Continue(current + 1)
  229. } else {
  230. Done(current)
  231. }
  232. })
  233. .into_inner()
  234. }
  235. /// Allocate a new file descriptor starting from `from`.
  236. ///
  237. /// Returned file descriptor should be used immediately.
  238. ///
  239. fn allocate_fd(&mut self, from: FD) -> FD {
  240. let from = FD::max(from, self.fd_min_avail);
  241. if from == self.fd_min_avail {
  242. let next_min_avail = self.find_available(from + 1);
  243. let allocated = self.fd_min_avail;
  244. self.fd_min_avail = next_min_avail;
  245. allocated
  246. } else {
  247. self.find_available(from)
  248. }
  249. }
  250. fn release_fd(&mut self, fd: FD) {
  251. if fd < self.fd_min_avail {
  252. self.fd_min_avail = fd;
  253. }
  254. }
  255. fn next_fd(&mut self) -> FD {
  256. self.allocate_fd(self.fd_min_avail)
  257. }
  258. /// Insert a file description to the file array.
  259. fn do_insert(&mut self, fd: FD, flags: u64, file: Arc<File>) {
  260. assert!(self.files.insert(fd, OpenFile { flags, file }).is_none());
  261. }
  262. }