xref: /DragonOS/kernel/src/filesystem/vfs/open.rs (revision 4b0170bd6bb374d0e9699a0076cc23b976ad6db7)
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: {}, how: {:?}", path, how);
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> = match inode {
93         Ok(inode) => inode,
94         Err(errno) => {
95             // 文件不存在,且需要创建
96             if how.o_flags.contains(FileMode::O_CREAT)
97                 && !how.o_flags.contains(FileMode::O_DIRECTORY)
98                 && errno == SystemError::ENOENT
99             {
100                 let (filename, parent_path) = rsplit_path(&path);
101                 // 查找父目录
102                 let parent_inode: Arc<dyn IndexNode> =
103                     ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
104                 // 创建文件
105                 let inode: Arc<dyn IndexNode> = parent_inode.create(
106                     filename,
107                     FileType::File,
108                     ModeType::from_bits_truncate(0o755),
109                 )?;
110                 inode
111             } else {
112                 // 不需要创建文件,因此返回错误码
113                 return Err(errno);
114             }
115         }
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 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