xref: /DragonOS/kernel/src/filesystem/vfs/open.rs (revision 6f189d2743e9b1ab790c58fc2d3a8d0c41cf61e1)
10fb515b0SLoGin use alloc::sync::Arc;
22eab6dd7S曾俊 use log::warn;
391e9d4abSLoGin use system_error::SystemError;
40fb515b0SLoGin 
5bf4a4899SLoGin use super::{
60fb515b0SLoGin     fcntl::AtFlags,
70fb515b0SLoGin     file::{File, FileMode},
80fb515b0SLoGin     syscall::{ModeType, OpenHow, OpenHowResolve},
90fb515b0SLoGin     utils::{rsplit_path, user_path_at},
100fb515b0SLoGin     FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
11bf4a4899SLoGin };
12*6f189d27Slinfeng use crate::filesystem::vfs::syscall::UtimensFlags;
13*6f189d27Slinfeng use crate::time::{syscall::PosixTimeval, PosixTimeSpec};
14*6f189d27Slinfeng use crate::{
15*6f189d27Slinfeng     driver::base::block::SeekFrom, process::ProcessManager,
16*6f189d27Slinfeng     syscall::user_access::check_and_clone_cstr,
17*6f189d27Slinfeng };
18*6f189d27Slinfeng use alloc::string::String;
199b0abe6dSLoGin 
209b0abe6dSLoGin pub(super) fn do_faccessat(
21bf4a4899SLoGin     dirfd: i32,
22bf4a4899SLoGin     path: *const u8,
239b0abe6dSLoGin     mode: ModeType,
249b0abe6dSLoGin     flags: u32,
259b0abe6dSLoGin ) -> Result<usize, SystemError> {
26bf4a4899SLoGin     if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
279b0abe6dSLoGin         return Err(SystemError::EINVAL);
289b0abe6dSLoGin     }
299b0abe6dSLoGin 
309b0abe6dSLoGin     if (flags
319b0abe6dSLoGin         & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
329b0abe6dSLoGin             as u32)))
339b0abe6dSLoGin         != 0
349b0abe6dSLoGin     {
359b0abe6dSLoGin         return Err(SystemError::EINVAL);
369b0abe6dSLoGin     }
379b0abe6dSLoGin 
389b0abe6dSLoGin     // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
399b0abe6dSLoGin 
40bf4a4899SLoGin     let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
41bf4a4899SLoGin 
420fb515b0SLoGin     let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?;
43bf4a4899SLoGin 
44bf4a4899SLoGin     // 如果找不到文件,则返回错误码ENOENT
45bf4a4899SLoGin     let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
46bf4a4899SLoGin 
479b0abe6dSLoGin     // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
489b0abe6dSLoGin     return Ok(0);
499b0abe6dSLoGin }
50bf4a4899SLoGin 
51bf4a4899SLoGin pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
52bf4a4899SLoGin     let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
53bf4a4899SLoGin 
540fb515b0SLoGin     let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, &path)?;
55bf4a4899SLoGin 
56bf4a4899SLoGin     // 如果找不到文件,则返回错误码ENOENT
57bf4a4899SLoGin     let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
58bf4a4899SLoGin 
592eab6dd7S曾俊     warn!("do_fchmodat: not implemented yet\n");
60bf4a4899SLoGin     // todo: 真正去改变文件的权限
61bf4a4899SLoGin 
62bf4a4899SLoGin     return Ok(0);
63bf4a4899SLoGin }
640fb515b0SLoGin 
650fb515b0SLoGin pub(super) fn do_sys_open(
660fb515b0SLoGin     dfd: i32,
670fb515b0SLoGin     path: &str,
680fb515b0SLoGin     o_flags: FileMode,
690fb515b0SLoGin     mode: ModeType,
700fb515b0SLoGin     follow_symlink: bool,
710fb515b0SLoGin ) -> Result<usize, SystemError> {
720fb515b0SLoGin     let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
730fb515b0SLoGin     return do_sys_openat2(dfd, path, how, follow_symlink);
740fb515b0SLoGin }
750fb515b0SLoGin 
760fb515b0SLoGin fn do_sys_openat2(
770fb515b0SLoGin     dirfd: i32,
780fb515b0SLoGin     path: &str,
790fb515b0SLoGin     how: OpenHow,
800fb515b0SLoGin     follow_symlink: bool,
810fb515b0SLoGin ) -> Result<usize, SystemError> {
822eab6dd7S曾俊     // debug!("open path: {}, how: {:?}", path, how);
8382df0a13Shmt     let path = path.trim();
8482df0a13Shmt 
850fb515b0SLoGin     let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
860fb515b0SLoGin     let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
870fb515b0SLoGin         &path,
880fb515b0SLoGin         if follow_symlink {
890fb515b0SLoGin             VFS_MAX_FOLLOW_SYMLINK_TIMES
900fb515b0SLoGin         } else {
910fb515b0SLoGin             0
920fb515b0SLoGin         },
930fb515b0SLoGin     );
940fb515b0SLoGin 
95b5b571e0SLoGin     let inode: Arc<dyn IndexNode> = match inode {
96b5b571e0SLoGin         Ok(inode) => inode,
97b5b571e0SLoGin         Err(errno) => {
980fb515b0SLoGin             // 文件不存在,且需要创建
990fb515b0SLoGin             if how.o_flags.contains(FileMode::O_CREAT)
1000fb515b0SLoGin                 && !how.o_flags.contains(FileMode::O_DIRECTORY)
1010fb515b0SLoGin                 && errno == SystemError::ENOENT
1020fb515b0SLoGin             {
1030fb515b0SLoGin                 let (filename, parent_path) = rsplit_path(&path);
1040fb515b0SLoGin                 // 查找父目录
1050fb515b0SLoGin                 let parent_inode: Arc<dyn IndexNode> =
1060fb515b0SLoGin                     ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
1070fb515b0SLoGin                 // 创建文件
1080fb515b0SLoGin                 let inode: Arc<dyn IndexNode> = parent_inode.create(
1090fb515b0SLoGin                     filename,
1100fb515b0SLoGin                     FileType::File,
1110fb515b0SLoGin                     ModeType::from_bits_truncate(0o755),
1120fb515b0SLoGin                 )?;
1130fb515b0SLoGin                 inode
1140fb515b0SLoGin             } else {
1150fb515b0SLoGin                 // 不需要创建文件,因此返回错误码
1160fb515b0SLoGin                 return Err(errno);
1170fb515b0SLoGin             }
118b5b571e0SLoGin         }
1190fb515b0SLoGin     };
1200fb515b0SLoGin 
1210fb515b0SLoGin     let file_type: FileType = inode.metadata()?.file_type;
1220fb515b0SLoGin     // 如果要打开的是文件夹,而目标不是文件夹
1230fb515b0SLoGin     if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
1240fb515b0SLoGin         return Err(SystemError::ENOTDIR);
1250fb515b0SLoGin     }
1260fb515b0SLoGin 
1270fb515b0SLoGin     // 创建文件对象
1280fb515b0SLoGin 
129dfe53cf0SGnoCiYeH     let file: File = File::new(inode, how.o_flags)?;
1300fb515b0SLoGin 
1310fb515b0SLoGin     // 打开模式为“追加”
1320fb515b0SLoGin     if how.o_flags.contains(FileMode::O_APPEND) {
1330fb515b0SLoGin         file.lseek(SeekFrom::SeekEnd(0))?;
1340fb515b0SLoGin     }
1350fb515b0SLoGin 
1360fb515b0SLoGin     // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
1370fb515b0SLoGin     if how.o_flags.contains(FileMode::O_TRUNC)
1380fb515b0SLoGin         && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
1390fb515b0SLoGin         && file_type == FileType::File
1400fb515b0SLoGin     {
1410fb515b0SLoGin         file.ftruncate(0)?;
1420fb515b0SLoGin     }
1430fb515b0SLoGin     // 把文件对象存入pcb
1440fb515b0SLoGin     let r = ProcessManager::current_pcb()
1450fb515b0SLoGin         .fd_table()
1460fb515b0SLoGin         .write()
1470fb515b0SLoGin         .alloc_fd(file, None)
1480fb515b0SLoGin         .map(|fd| fd as usize);
1490fb515b0SLoGin 
1500fb515b0SLoGin     return r;
1510fb515b0SLoGin }
152*6f189d27Slinfeng 
153*6f189d27Slinfeng /// On Linux, futimens() is a library function implemented on top of
154*6f189d27Slinfeng /// the utimensat() system call.  To support this, the Linux
155*6f189d27Slinfeng /// utimensat() system call implements a nonstandard feature: if
156*6f189d27Slinfeng /// pathname is NULL, then the call modifies the timestamps of the
157*6f189d27Slinfeng /// file referred to by the file descriptor dirfd (which may refer to
158*6f189d27Slinfeng /// any type of file).
159*6f189d27Slinfeng pub fn do_utimensat(
160*6f189d27Slinfeng     dirfd: i32,
161*6f189d27Slinfeng     pathname: Option<String>,
162*6f189d27Slinfeng     times: Option<[PosixTimeSpec; 2]>,
163*6f189d27Slinfeng     flags: UtimensFlags,
164*6f189d27Slinfeng ) -> Result<usize, SystemError> {
165*6f189d27Slinfeng     const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
166*6f189d27Slinfeng     const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
167*6f189d27Slinfeng     // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
168*6f189d27Slinfeng     let inode = match pathname {
169*6f189d27Slinfeng         Some(path) => {
170*6f189d27Slinfeng             let (inode_begin, path) =
171*6f189d27Slinfeng                 user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
172*6f189d27Slinfeng             let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
173*6f189d27Slinfeng                 inode_begin.lookup(path.as_str())?
174*6f189d27Slinfeng             } else {
175*6f189d27Slinfeng                 inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
176*6f189d27Slinfeng             };
177*6f189d27Slinfeng             inode
178*6f189d27Slinfeng         }
179*6f189d27Slinfeng         None => {
180*6f189d27Slinfeng             let binding = ProcessManager::current_pcb().fd_table();
181*6f189d27Slinfeng             let fd_table_guard = binding.write();
182*6f189d27Slinfeng             let file = fd_table_guard
183*6f189d27Slinfeng                 .get_file_by_fd(dirfd)
184*6f189d27Slinfeng                 .ok_or(SystemError::EBADF)?;
185*6f189d27Slinfeng             file.inode()
186*6f189d27Slinfeng         }
187*6f189d27Slinfeng     };
188*6f189d27Slinfeng     let now = PosixTimeSpec::now();
189*6f189d27Slinfeng     let mut meta = inode.metadata()?;
190*6f189d27Slinfeng 
191*6f189d27Slinfeng     if let Some([atime, mtime]) = times {
192*6f189d27Slinfeng         if atime.tv_nsec == UTIME_NOW {
193*6f189d27Slinfeng             meta.atime = now;
194*6f189d27Slinfeng         } else if atime.tv_nsec != UTIME_OMIT {
195*6f189d27Slinfeng             meta.atime = atime;
196*6f189d27Slinfeng         }
197*6f189d27Slinfeng         if mtime.tv_nsec == UTIME_NOW {
198*6f189d27Slinfeng             meta.mtime = now;
199*6f189d27Slinfeng         } else if mtime.tv_nsec != UTIME_OMIT {
200*6f189d27Slinfeng             meta.mtime = mtime;
201*6f189d27Slinfeng         }
202*6f189d27Slinfeng         inode.set_metadata(&meta).unwrap();
203*6f189d27Slinfeng     } else {
204*6f189d27Slinfeng         meta.atime = now;
205*6f189d27Slinfeng         meta.mtime = now;
206*6f189d27Slinfeng         inode.set_metadata(&meta).unwrap();
207*6f189d27Slinfeng     }
208*6f189d27Slinfeng     return Ok(0);
209*6f189d27Slinfeng }
210*6f189d27Slinfeng 
211*6f189d27Slinfeng pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
212*6f189d27Slinfeng     // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
213*6f189d27Slinfeng     let (inode_begin, path) = user_path_at(
214*6f189d27Slinfeng         &ProcessManager::current_pcb(),
215*6f189d27Slinfeng         AtFlags::AT_FDCWD.bits(),
216*6f189d27Slinfeng         path,
217*6f189d27Slinfeng     )?;
218*6f189d27Slinfeng     let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
219*6f189d27Slinfeng     let mut meta = inode.metadata()?;
220*6f189d27Slinfeng 
221*6f189d27Slinfeng     if let Some([atime, mtime]) = times {
222*6f189d27Slinfeng         meta.atime = PosixTimeSpec::from(atime);
223*6f189d27Slinfeng         meta.mtime = PosixTimeSpec::from(mtime);
224*6f189d27Slinfeng         inode.set_metadata(&meta)?;
225*6f189d27Slinfeng     } else {
226*6f189d27Slinfeng         let now = PosixTimeSpec::now();
227*6f189d27Slinfeng         meta.atime = now;
228*6f189d27Slinfeng         meta.mtime = now;
229*6f189d27Slinfeng         inode.set_metadata(&meta)?;
230*6f189d27Slinfeng     }
231*6f189d27Slinfeng     return Ok(0);
232*6f189d27Slinfeng }
233