1use crate::file::File;
2use alloc::sync::Arc;
3use alloc::vec::Vec;
4use spin::Mutex;
5
6pub type FileDescriptor = usize;
7
8pub const STDIN: FileDescriptor = 0;
9pub const STDOUT: FileDescriptor = 1;
10pub const STDERR: FileDescriptor = 2;
11pub const FILE_DESCRIPTOR_LIMIT: usize = 1024;
12
13pub struct FdEntry {
14 file: Arc<Mutex<dyn File>>,
15 flags: u32,
16}
17
18impl FdEntry {
19 pub fn new(file: Arc<Mutex<dyn File>>) -> Self {
20 Self { file, flags: 0 }
21 }
22
23 pub fn file(&self) -> Arc<Mutex<dyn File>> {
24 self.file.clone()
25 }
26
27 pub fn flags(&self) -> u32 {
28 self.flags
29 }
30}
31
32pub struct FileDescriptorTable {
33 entries: Vec<Option<FdEntry>>,
34 next_fd: FileDescriptor,
35}
36
37impl FileDescriptorTable {
38 pub fn new() -> Self {
39 let entries = alloc::vec![None, None, None];
40 Self {
41 entries,
42 next_fd: 3,
43 }
44 }
45
46 pub fn with_stdio(
47 stdin: Arc<Mutex<dyn File>>,
48 stdout: Arc<Mutex<dyn File>>,
49 stderr: Arc<Mutex<dyn File>>,
50 ) -> Self {
51 let mut table = Self {
52 entries: Vec::with_capacity(16),
53 next_fd: 3,
54 };
55 table.entries.push(Some(FdEntry::new(stdin)));
56 table.entries.push(Some(FdEntry::new(stdout)));
57 table.entries.push(Some(FdEntry::new(stderr)));
58 table
59 }
60
61 pub fn alloc(&mut self, file: Arc<Mutex<dyn File>>) -> Option<FileDescriptor> {
62 for (i, slot) in self.entries.iter_mut().enumerate() {
63 if slot.is_none() && i >= 3 {
64 *slot = Some(FdEntry::new(file));
65 self.next_fd = i + 1;
66 return Some(i);
67 }
68 }
69 if self.entries.len() >= FILE_DESCRIPTOR_LIMIT {
70 return None;
71 }
72 let fd = self.entries.len();
73 self.entries.push(Some(FdEntry::new(file)));
74 self.next_fd = fd + 1;
75 Some(fd)
76 }
77
78 pub fn dealloc(&mut self, fd: FileDescriptor) -> bool {
79 if fd >= 3 && fd < self.entries.len() && self.entries[fd].is_some() {
80 self.entries[fd] = None;
81 if fd < self.next_fd {
82 self.next_fd = fd;
83 }
84 return true;
85 }
86 false
87 }
88
89 pub fn get(&self, fd: FileDescriptor) -> Option<Arc<Mutex<dyn File>>> {
90 self.entries.get(fd)?.as_ref().map(|entry| entry.file())
91 }
92
93 pub fn is_valid(&self, fd: FileDescriptor) -> bool {
94 self.get(fd).is_some()
95 }
96
97 pub fn dup2(
98 &mut self,
99 old_fd: FileDescriptor,
100 new_fd: FileDescriptor,
101 ) -> Option<FileDescriptor> {
102 if old_fd == new_fd {
103 return if self.is_valid(old_fd) {
104 Some(new_fd)
105 } else {
106 None
107 };
108 }
109 if new_fd >= FILE_DESCRIPTOR_LIMIT {
110 return None;
111 }
112 let file = self.get(old_fd)?;
113 while self.entries.len() <= new_fd {
114 self.entries.push(None);
115 }
116 self.entries[new_fd] = Some(FdEntry { file, flags: 0 });
117 Some(new_fd)
118 }
119
120 pub fn count(&self) -> usize {
121 self.entries.iter().filter(|entry| entry.is_some()).count()
122 }
123
124 pub fn capacity(&self) -> usize {
125 self.entries.len()
126 }
127}
128
129impl Default for FileDescriptorTable {
130 fn default() -> Self {
131 Self::new()
132 }
133}