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