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::{
13 driver::base::block::SeekFrom, process::ProcessManager,
14 syscall::user_access::check_and_clone_cstr,
15 };
16 use crate::{filesystem::vfs::syscall::UtimensFlags, process::cred::Kgid};
17 use crate::{
18 process::cred::GroupInfo,
19 time::{syscall::PosixTimeval, PosixTimeSpec},
20 };
21 use alloc::string::String;
22
do_faccessat( dirfd: i32, path: *const u8, mode: ModeType, flags: u32, ) -> Result<usize, SystemError>23 pub(super) fn do_faccessat(
24 dirfd: i32,
25 path: *const u8,
26 mode: ModeType,
27 flags: u32,
28 ) -> Result<usize, SystemError> {
29 if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
30 return Err(SystemError::EINVAL);
31 }
32
33 if (flags
34 & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
35 as u32)))
36 != 0
37 {
38 return Err(SystemError::EINVAL);
39 }
40
41 // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
42
43 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
44 let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
45
46 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
47
48 // 如果找不到文件,则返回错误码ENOENT
49 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
50
51 // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
52 return Ok(0);
53 }
54
do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError>55 pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
56 let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
57 let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
58
59 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
60
61 // 如果找不到文件,则返回错误码ENOENT
62 let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
63
64 warn!("do_fchmodat: not implemented yet\n");
65 // todo: 真正去改变文件的权限
66
67 return Ok(0);
68 }
69
do_fchownat( dirfd: i32, path: &str, uid: usize, gid: usize, flag: AtFlags, ) -> Result<usize, SystemError>70 pub fn do_fchownat(
71 dirfd: i32,
72 path: &str,
73 uid: usize,
74 gid: usize,
75 flag: AtFlags,
76 ) -> Result<usize, SystemError> {
77 // 检查flag是否合法
78 if flag.contains(!(AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH)) {
79 return Err(SystemError::EINVAL);
80 }
81
82 let follow_symlink = flag.contains(!AtFlags::AT_SYMLINK_NOFOLLOW);
83 let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
84
85 // 如果找不到文件,则返回错误码ENOENT
86 let inode = if follow_symlink {
87 inode.lookup_follow_symlink2(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES, false)
88 } else {
89 inode.lookup(path.as_str())
90 };
91
92 if inode.is_err() {
93 let errno = inode.clone().unwrap_err();
94 // 文件不存在
95 if errno == SystemError::ENOENT {
96 return Err(SystemError::ENOENT);
97 }
98 }
99
100 let inode = inode.unwrap();
101
102 return chown_common(inode, uid, gid);
103 }
104
chown_common(inode: Arc<dyn IndexNode>, uid: usize, gid: usize) -> Result<usize, SystemError>105 fn chown_common(inode: Arc<dyn IndexNode>, uid: usize, gid: usize) -> Result<usize, SystemError> {
106 let mut meta = inode.metadata()?;
107 let cred = ProcessManager::current_pcb().cred();
108 let current_uid = cred.uid.data();
109 let current_gid = cred.gid.data();
110 let mut group_info = GroupInfo::default();
111 if let Some(info) = cred.group_info.as_ref() {
112 group_info = info.clone();
113 }
114
115 // 检查权限
116 match current_uid {
117 0 => {
118 meta.uid = uid;
119 meta.gid = gid;
120 }
121 _ => {
122 // 非文件所有者不能更改信息,且不能更改uid
123 if current_uid != meta.uid || uid != meta.uid {
124 return Err(SystemError::EPERM);
125 }
126 if gid != current_gid && !group_info.gids.contains(&Kgid::from(gid)) {
127 return Err(SystemError::EPERM);
128 }
129 meta.gid = gid;
130 }
131 }
132
133 meta.mode.remove(ModeType::S_ISUID | ModeType::S_ISGID);
134 inode.set_metadata(&meta)?;
135
136 return Ok(0);
137 }
138
ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError>139 pub fn ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError> {
140 let fd_table = &ProcessManager::current_pcb().fd_table();
141 let fd_table = fd_table.read();
142
143 let inode = fd_table.get_file_by_fd(fd).unwrap().inode();
144
145 let result = chown_common(inode, uid, gid);
146
147 drop(fd_table);
148
149 return result;
150 }
151
do_sys_open( dfd: i32, path: &str, o_flags: FileMode, mode: ModeType, follow_symlink: bool, ) -> Result<usize, SystemError>152 pub(super) fn do_sys_open(
153 dfd: i32,
154 path: &str,
155 o_flags: FileMode,
156 mode: ModeType,
157 follow_symlink: bool,
158 ) -> Result<usize, SystemError> {
159 let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
160 return do_sys_openat2(dfd, path, how, follow_symlink);
161 }
162
do_sys_openat2( dirfd: i32, path: &str, how: OpenHow, follow_symlink: bool, ) -> Result<usize, SystemError>163 fn do_sys_openat2(
164 dirfd: i32,
165 path: &str,
166 how: OpenHow,
167 follow_symlink: bool,
168 ) -> Result<usize, SystemError> {
169 // debug!("open path: {}, how: {:?}", path, how);
170 let path = path.trim();
171
172 let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
173 let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
174 &path,
175 if follow_symlink {
176 VFS_MAX_FOLLOW_SYMLINK_TIMES
177 } else {
178 0
179 },
180 );
181
182 let inode: Arc<dyn IndexNode> = match inode {
183 Ok(inode) => inode,
184 Err(errno) => {
185 // 文件不存在,且需要创建
186 if how.o_flags.contains(FileMode::O_CREAT)
187 && !how.o_flags.contains(FileMode::O_DIRECTORY)
188 && errno == SystemError::ENOENT
189 {
190 let (filename, parent_path) = rsplit_path(&path);
191 // 查找父目录
192 let parent_inode: Arc<dyn IndexNode> =
193 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
194 // 创建文件
195 let inode: Arc<dyn IndexNode> = parent_inode.create(
196 filename,
197 FileType::File,
198 ModeType::from_bits_truncate(0o755),
199 )?;
200 inode
201 } else {
202 // 不需要创建文件,因此返回错误码
203 return Err(errno);
204 }
205 }
206 };
207
208 let file_type: FileType = inode.metadata()?.file_type;
209 // 如果要打开的是文件夹,而目标不是文件夹
210 if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
211 return Err(SystemError::ENOTDIR);
212 }
213
214 // 创建文件对象
215
216 let file: File = File::new(inode, how.o_flags)?;
217
218 // 打开模式为“追加”
219 if how.o_flags.contains(FileMode::O_APPEND) {
220 file.lseek(SeekFrom::SeekEnd(0))?;
221 }
222
223 // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
224 if how.o_flags.contains(FileMode::O_TRUNC)
225 && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
226 && file_type == FileType::File
227 {
228 file.ftruncate(0)?;
229 }
230 // 把文件对象存入pcb
231 let r = ProcessManager::current_pcb()
232 .fd_table()
233 .write()
234 .alloc_fd(file, None)
235 .map(|fd| fd as usize);
236
237 return r;
238 }
239
240 /// On Linux, futimens() is a library function implemented on top of
241 /// the utimensat() system call. To support this, the Linux
242 /// utimensat() system call implements a nonstandard feature: if
243 /// pathname is NULL, then the call modifies the timestamps of the
244 /// file referred to by the file descriptor dirfd (which may refer to
245 /// any type of file).
do_utimensat( dirfd: i32, pathname: Option<String>, times: Option<[PosixTimeSpec; 2]>, flags: UtimensFlags, ) -> Result<usize, SystemError>246 pub fn do_utimensat(
247 dirfd: i32,
248 pathname: Option<String>,
249 times: Option<[PosixTimeSpec; 2]>,
250 flags: UtimensFlags,
251 ) -> Result<usize, SystemError> {
252 const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
253 const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
254 // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
255 let inode = match pathname {
256 Some(path) => {
257 let (inode_begin, path) =
258 user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
259 let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
260 inode_begin.lookup(path.as_str())?
261 } else {
262 inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
263 };
264 inode
265 }
266 None => {
267 let binding = ProcessManager::current_pcb().fd_table();
268 let fd_table_guard = binding.write();
269 let file = fd_table_guard
270 .get_file_by_fd(dirfd)
271 .ok_or(SystemError::EBADF)?;
272 file.inode()
273 }
274 };
275 let now = PosixTimeSpec::now();
276 let mut meta = inode.metadata()?;
277
278 if let Some([atime, mtime]) = times {
279 if atime.tv_nsec == UTIME_NOW {
280 meta.atime = now;
281 } else if atime.tv_nsec != UTIME_OMIT {
282 meta.atime = atime;
283 }
284 if mtime.tv_nsec == UTIME_NOW {
285 meta.mtime = now;
286 } else if mtime.tv_nsec != UTIME_OMIT {
287 meta.mtime = mtime;
288 }
289 inode.set_metadata(&meta).unwrap();
290 } else {
291 meta.atime = now;
292 meta.mtime = now;
293 inode.set_metadata(&meta).unwrap();
294 }
295 return Ok(0);
296 }
297
do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError>298 pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
299 // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
300 let (inode_begin, path) = user_path_at(
301 &ProcessManager::current_pcb(),
302 AtFlags::AT_FDCWD.bits(),
303 path,
304 )?;
305 let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
306 let mut meta = inode.metadata()?;
307
308 if let Some([atime, mtime]) = times {
309 meta.atime = PosixTimeSpec::from(atime);
310 meta.mtime = PosixTimeSpec::from(mtime);
311 inode.set_metadata(&meta)?;
312 } else {
313 let now = PosixTimeSpec::now();
314 meta.atime = now;
315 meta.mtime = now;
316 inode.set_metadata(&meta)?;
317 }
318 return Ok(0);
319 }
320