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