Skip to main content

ahrightos_fs/
fd_table.rs

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}