xref: /DragonOS/kernel/src/filesystem/vfs/open.rs (revision c75089286e9d49cef8d039446bf570c1bd4d2550)
1 use alloc::sync::Arc;
2 
3 use crate::{
4     driver::base::block::SeekFrom,
5     process::ProcessManager,
6     syscall::{user_access::check_and_clone_cstr, SystemError},
7 };
8 
9 use super::{
10     fcntl::AtFlags,
11     file::{File, FileMode},
12     syscall::{ModeType, OpenHow, OpenHowResolve},
13     utils::{rsplit_path, user_path_at},
14     FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
15 };
16 
17 pub(super) fn do_faccessat(
18     dirfd: i32,
19     path: *const u8,
20     mode: ModeType,
21     flags: u32,
22 ) -> Result<usize, SystemError> {
23     if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
24         return Err(SystemError::EINVAL);
25     }
26 
27     if (flags
28         & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
29             as u32)))
30         != 0
31     {
32         return Err(SystemError::EINVAL);
33     }
34 
35     // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
36 
37     let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
38 
39     if path.len() == 0 {
40         return Err(SystemError::EINVAL);
41     }
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 
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 
55     if path.len() == 0 {
56         return Err(SystemError::EINVAL);
57     }
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     kwarn!("do_fchmodat: not implemented yet\n");
65     // todo: 真正去改变文件的权限
66 
67     return Ok(0);
68 }
69 
70 pub(super) fn do_sys_open(
71     dfd: i32,
72     path: &str,
73     o_flags: FileMode,
74     mode: ModeType,
75     follow_symlink: bool,
76 ) -> Result<usize, SystemError> {
77     let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
78     return do_sys_openat2(dfd, path, how, follow_symlink);
79 }
80 
81 fn do_sys_openat2(
82     dirfd: i32,
83     path: &str,
84     how: OpenHow,
85     follow_symlink: bool,
86 ) -> Result<usize, SystemError> {
87     // kdebug!("open: path: {}, mode: {:?}", path, mode);
88     // 文件名过长
89     if path.len() > MAX_PATHLEN as usize {
90         return Err(SystemError::ENAMETOOLONG);
91     }
92     let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
93     let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
94         &path,
95         if follow_symlink {
96             VFS_MAX_FOLLOW_SYMLINK_TIMES
97         } else {
98             0
99         },
100     );
101 
102     let inode: Arc<dyn IndexNode> = if inode.is_err() {
103         let errno = inode.unwrap_err();
104         // 文件不存在,且需要创建
105         if how.o_flags.contains(FileMode::O_CREAT)
106             && !how.o_flags.contains(FileMode::O_DIRECTORY)
107             && errno == SystemError::ENOENT
108         {
109             let (filename, parent_path) = rsplit_path(&path);
110             // 查找父目录
111             let parent_inode: Arc<dyn IndexNode> =
112                 ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
113             // 创建文件
114             let inode: Arc<dyn IndexNode> = parent_inode.create(
115                 filename,
116                 FileType::File,
117                 ModeType::from_bits_truncate(0o755),
118             )?;
119             inode
120         } else {
121             // 不需要创建文件,因此返回错误码
122             return Err(errno);
123         }
124     } else {
125         inode.unwrap()
126     };
127 
128     let file_type: FileType = inode.metadata()?.file_type;
129     // 如果要打开的是文件夹,而目标不是文件夹
130     if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
131         return Err(SystemError::ENOTDIR);
132     }
133 
134     // 创建文件对象
135 
136     let mut file: File = File::new(inode, how.o_flags)?;
137 
138     // 打开模式为“追加”
139     if how.o_flags.contains(FileMode::O_APPEND) {
140         file.lseek(SeekFrom::SeekEnd(0))?;
141     }
142 
143     // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
144     if how.o_flags.contains(FileMode::O_TRUNC)
145         && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
146         && file_type == FileType::File
147     {
148         file.ftruncate(0)?;
149     }
150     // 把文件对象存入pcb
151     let r = ProcessManager::current_pcb()
152         .fd_table()
153         .write()
154         .alloc_fd(file, None)
155         .map(|fd| fd as usize);
156 
157     return r;
158 }
159