1 use alloc::sync::Arc;
2 use log::warn;
3 use system_error::SystemError;
4
5 use super::{
6 fcntl::AtFlags,
7 file::{File, FileMode},
8 syscall::{ModeType, OpenHow, OpenHowResolve},
9 utils::{rsplit_path, user_path_at},
10 FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
11 };
12 use crate::filesystem::vfs::syscall::UtimensFlags;
13 use crate::time::{syscall::PosixTimeval, PosixTimeSpec};
14 use crate::{
15 driver::base::block::SeekFrom, process::ProcessManager,
16 syscall::user_access::check_and_clone_cstr,
17 };
18 use alloc::string::String;
19
do_faccessat( dirfd: i32, path: *const u8, mode: ModeType, flags: u32, ) -> Result<usize, SystemError>20 pub(super) fn do_faccessat(
21 dirfd: i32,
22 path: *const u8,
23 mode: ModeType,
24 flags: u32,
25 ) -> Result<usize, SystemError> {
26 if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
27 return Err(SystemError::EINVAL);
28 }
29
30 if (flags
31 & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
32 as u32)))
33 != 0
34 {
35 return Err(SystemError::EINVAL);
36 }
37
38 // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
39
40 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
41 let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
42
43 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
44
45 // 如果找不到文件,则返回错误码ENOENT
46 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
47
48 // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
49 return Ok(0);
50 }
51
do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError>52 pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
53 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
54 let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
55
56 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
57
58 // 如果找不到文件,则返回错误码ENOENT
59 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
60
61 warn!("do_fchmodat: not implemented yet\n");
62 // todo: 真正去改变文件的权限
63
64 return Ok(0);
65 }
66
do_sys_open( dfd: i32, path: &str, o_flags: FileMode, mode: ModeType, follow_symlink: bool, ) -> Result<usize, SystemError>67 pub(super) fn do_sys_open(
68 dfd: i32,
69 path: &str,
70 o_flags: FileMode,
71 mode: ModeType,
72 follow_symlink: bool,
73 ) -> Result<usize, SystemError> {
74 let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
75 return do_sys_openat2(dfd, path, how, follow_symlink);
76 }
77
do_sys_openat2( dirfd: i32, path: &str, how: OpenHow, follow_symlink: bool, ) -> Result<usize, SystemError>78 fn do_sys_openat2(
79 dirfd: i32,
80 path: &str,
81 how: OpenHow,
82 follow_symlink: bool,
83 ) -> Result<usize, SystemError> {
84 // debug!("open path: {}, how: {:?}", path, how);
85 let path = path.trim();
86
87 let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
88 let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
89 &path,
90 if follow_symlink {
91 VFS_MAX_FOLLOW_SYMLINK_TIMES
92 } else {
93 0
94 },
95 );
96
97 let inode: Arc<dyn IndexNode> = match inode {
98 Ok(inode) => inode,
99 Err(errno) => {
100 // 文件不存在,且需要创建
101 if how.o_flags.contains(FileMode::O_CREAT)
102 && !how.o_flags.contains(FileMode::O_DIRECTORY)
103 && errno == SystemError::ENOENT
104 {
105 let (filename, parent_path) = rsplit_path(&path);
106 // 查找父目录
107 let parent_inode: Arc<dyn IndexNode> =
108 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
109 // 创建文件
110 let inode: Arc<dyn IndexNode> = parent_inode.create(
111 filename,
112 FileType::File,
113 ModeType::from_bits_truncate(0o755),
114 )?;
115 inode
116 } else {
117 // 不需要创建文件,因此返回错误码
118 return Err(errno);
119 }
120 }
121 };
122
123 let file_type: FileType = inode.metadata()?.file_type;
124 // 如果要打开的是文件夹,而目标不是文件夹
125 if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
126 return Err(SystemError::ENOTDIR);
127 }
128
129 // 创建文件对象
130
131 let file: File = File::new(inode, how.o_flags)?;
132
133 // 打开模式为“追加”
134 if how.o_flags.contains(FileMode::O_APPEND) {
135 file.lseek(SeekFrom::SeekEnd(0))?;
136 }
137
138 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
139 if how.o_flags.contains(FileMode::O_TRUNC)
140 && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
141 && file_type == FileType::File
142 {
143 file.ftruncate(0)?;
144 }
145 // 把文件对象存入pcb
146 let r = ProcessManager::current_pcb()
147 .fd_table()
148 .write()
149 .alloc_fd(file, None)
150 .map(|fd| fd as usize);
151
152 return r;
153 }
154
155 /// On Linux, futimens() is a library function implemented on top of
156 /// the utimensat() system call. To support this, the Linux
157 /// utimensat() system call implements a nonstandard feature: if
158 /// pathname is NULL, then the call modifies the timestamps of the
159 /// file referred to by the file descriptor dirfd (which may refer to
160 /// any type of file).
do_utimensat( dirfd: i32, pathname: Option<String>, times: Option<[PosixTimeSpec; 2]>, flags: UtimensFlags, ) -> Result<usize, SystemError>161 pub fn do_utimensat(
162 dirfd: i32,
163 pathname: Option<String>,
164 times: Option<[PosixTimeSpec; 2]>,
165 flags: UtimensFlags,
166 ) -> Result<usize, SystemError> {
167 const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
168 const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
169 // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
170 let inode = match pathname {
171 Some(path) => {
172 let (inode_begin, path) =
173 user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
174 let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
175 inode_begin.lookup(path.as_str())?
176 } else {
177 inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
178 };
179 inode
180 }
181 None => {
182 let binding = ProcessManager::current_pcb().fd_table();
183 let fd_table_guard = binding.write();
184 let file = fd_table_guard
185 .get_file_by_fd(dirfd)
186 .ok_or(SystemError::EBADF)?;
187 file.inode()
188 }
189 };
190 let now = PosixTimeSpec::now();
191 let mut meta = inode.metadata()?;
192
193 if let Some([atime, mtime]) = times {
194 if atime.tv_nsec == UTIME_NOW {
195 meta.atime = now;
196 } else if atime.tv_nsec != UTIME_OMIT {
197 meta.atime = atime;
198 }
199 if mtime.tv_nsec == UTIME_NOW {
200 meta.mtime = now;
201 } else if mtime.tv_nsec != UTIME_OMIT {
202 meta.mtime = mtime;
203 }
204 inode.set_metadata(&meta).unwrap();
205 } else {
206 meta.atime = now;
207 meta.mtime = now;
208 inode.set_metadata(&meta).unwrap();
209 }
210 return Ok(0);
211 }
212
do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError>213 pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
214 // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
215 let (inode_begin, path) = user_path_at(
216 &ProcessManager::current_pcb(),
217 AtFlags::AT_FDCWD.bits(),
218 path,
219 )?;
220 let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
221 let mut meta = inode.metadata()?;
222
223 if let Some([atime, mtime]) = times {
224 meta.atime = PosixTimeSpec::from(atime);
225 meta.mtime = PosixTimeSpec::from(mtime);
226 inode.set_metadata(&meta)?;
227 } else {
228 let now = PosixTimeSpec::now();
229 meta.atime = now;
230 meta.mtime = now;
231 inode.set_metadata(&meta)?;
232 }
233 return Ok(0);
234 }
235