open.rs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. use alloc::sync::Arc;
  2. use log::warn;
  3. use system_error::SystemError;
  4. use super::{
  5. fcntl::AtFlags,
  6. file::{File, FileMode},
  7. syscall::{ModeType, OpenHow, OpenHowResolve},
  8. utils::{rsplit_path, user_path_at},
  9. FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
  10. };
  11. use crate::{
  12. driver::base::block::SeekFrom, process::ProcessManager,
  13. syscall::user_access::check_and_clone_cstr,
  14. };
  15. use crate::{filesystem::vfs::syscall::UtimensFlags, process::cred::Kgid};
  16. use crate::{
  17. process::cred::GroupInfo,
  18. time::{syscall::PosixTimeval, PosixTimeSpec},
  19. };
  20. use alloc::string::String;
  21. pub(super) fn do_faccessat(
  22. dirfd: i32,
  23. path: *const u8,
  24. mode: ModeType,
  25. flags: u32,
  26. ) -> Result<usize, SystemError> {
  27. if (mode.bits() & (!ModeType::S_IRWXO.bits())) != 0 {
  28. return Err(SystemError::EINVAL);
  29. }
  30. if (flags
  31. & (!((AtFlags::AT_EACCESS | AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH).bits()
  32. as u32)))
  33. != 0
  34. {
  35. return Err(SystemError::EINVAL);
  36. }
  37. // let follow_symlink = flags & AtFlags::AT_SYMLINK_NOFOLLOW.bits() as u32 == 0;
  38. let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
  39. let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
  40. let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
  41. // 如果找不到文件,则返回错误码ENOENT
  42. let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
  43. // todo: 接着完善(可以借鉴linux 6.1.9的do_faccessat)
  44. return Ok(0);
  45. }
  46. pub fn do_fchmodat(dirfd: i32, path: *const u8, _mode: ModeType) -> Result<usize, SystemError> {
  47. let path = check_and_clone_cstr(path, Some(MAX_PATHLEN))?;
  48. let path = path.to_str().map_err(|_| SystemError::EINVAL)?;
  49. let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
  50. // 如果找不到文件,则返回错误码ENOENT
  51. let _inode = inode.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
  52. warn!("do_fchmodat: not implemented yet\n");
  53. // todo: 真正去改变文件的权限
  54. return Ok(0);
  55. }
  56. pub fn do_fchownat(
  57. dirfd: i32,
  58. path: &str,
  59. uid: usize,
  60. gid: usize,
  61. flag: AtFlags,
  62. ) -> Result<usize, SystemError> {
  63. // 检查flag是否合法
  64. if flag.contains(!(AtFlags::AT_SYMLINK_NOFOLLOW | AtFlags::AT_EMPTY_PATH)) {
  65. return Err(SystemError::EINVAL);
  66. }
  67. let follow_symlink = flag.contains(!AtFlags::AT_SYMLINK_NOFOLLOW);
  68. let (inode, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
  69. // 如果找不到文件,则返回错误码ENOENT
  70. let inode = if follow_symlink {
  71. inode.lookup_follow_symlink2(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES, false)
  72. } else {
  73. inode.lookup(path.as_str())
  74. };
  75. if inode.is_err() {
  76. let errno = inode.clone().unwrap_err();
  77. // 文件不存在
  78. if errno == SystemError::ENOENT {
  79. return Err(SystemError::ENOENT);
  80. }
  81. }
  82. let inode = inode.unwrap();
  83. return chown_common(inode, uid, gid);
  84. }
  85. fn chown_common(inode: Arc<dyn IndexNode>, uid: usize, gid: usize) -> Result<usize, SystemError> {
  86. let mut meta = inode.metadata()?;
  87. let cred = ProcessManager::current_pcb().cred();
  88. let current_uid = cred.uid.data();
  89. let current_gid = cred.gid.data();
  90. let mut group_info = GroupInfo::default();
  91. if let Some(info) = cred.group_info.as_ref() {
  92. group_info = info.clone();
  93. }
  94. // 检查权限
  95. match current_uid {
  96. 0 => {
  97. meta.uid = uid;
  98. meta.gid = gid;
  99. }
  100. _ => {
  101. // 非文件所有者不能更改信息,且不能更改uid
  102. if current_uid != meta.uid || uid != meta.uid {
  103. return Err(SystemError::EPERM);
  104. }
  105. if gid != current_gid && !group_info.gids.contains(&Kgid::from(gid)) {
  106. return Err(SystemError::EPERM);
  107. }
  108. meta.gid = gid;
  109. }
  110. }
  111. meta.mode.remove(ModeType::S_ISUID | ModeType::S_ISGID);
  112. inode.set_metadata(&meta)?;
  113. return Ok(0);
  114. }
  115. pub fn ksys_fchown(fd: i32, uid: usize, gid: usize) -> Result<usize, SystemError> {
  116. let fd_table = &ProcessManager::current_pcb().fd_table();
  117. let fd_table = fd_table.read();
  118. let inode = fd_table.get_file_by_fd(fd).unwrap().inode();
  119. let result = chown_common(inode, uid, gid);
  120. drop(fd_table);
  121. return result;
  122. }
  123. pub(super) fn do_sys_open(
  124. dfd: i32,
  125. path: &str,
  126. o_flags: FileMode,
  127. mode: ModeType,
  128. follow_symlink: bool,
  129. ) -> Result<usize, SystemError> {
  130. let how = OpenHow::new(o_flags, mode, OpenHowResolve::empty());
  131. return do_sys_openat2(dfd, path, how, follow_symlink);
  132. }
  133. fn do_sys_openat2(
  134. dirfd: i32,
  135. path: &str,
  136. how: OpenHow,
  137. follow_symlink: bool,
  138. ) -> Result<usize, SystemError> {
  139. // debug!("open path: {}, how: {:?}", path, how);
  140. let path = path.trim();
  141. let (inode_begin, path) = user_path_at(&ProcessManager::current_pcb(), dirfd, path)?;
  142. let inode: Result<Arc<dyn IndexNode>, SystemError> = inode_begin.lookup_follow_symlink(
  143. &path,
  144. if follow_symlink {
  145. VFS_MAX_FOLLOW_SYMLINK_TIMES
  146. } else {
  147. 0
  148. },
  149. );
  150. let inode: Arc<dyn IndexNode> = match inode {
  151. Ok(inode) => inode,
  152. Err(errno) => {
  153. // 文件不存在,且需要创建
  154. if how.o_flags.contains(FileMode::O_CREAT)
  155. && !how.o_flags.contains(FileMode::O_DIRECTORY)
  156. && errno == SystemError::ENOENT
  157. {
  158. let (filename, parent_path) = rsplit_path(&path);
  159. // 查找父目录
  160. let parent_inode: Arc<dyn IndexNode> =
  161. ROOT_INODE().lookup(parent_path.unwrap_or("/"))?;
  162. // 创建文件
  163. let inode: Arc<dyn IndexNode> = parent_inode.create(
  164. filename,
  165. FileType::File,
  166. ModeType::from_bits_truncate(0o755),
  167. )?;
  168. inode
  169. } else {
  170. // 不需要创建文件,因此返回错误码
  171. return Err(errno);
  172. }
  173. }
  174. };
  175. let file_type: FileType = inode.metadata()?.file_type;
  176. // 如果要打开的是文件夹,而目标不是文件夹
  177. if how.o_flags.contains(FileMode::O_DIRECTORY) && file_type != FileType::Dir {
  178. return Err(SystemError::ENOTDIR);
  179. }
  180. // 创建文件对象
  181. let file: File = File::new(inode, how.o_flags)?;
  182. // 打开模式为“追加”
  183. if how.o_flags.contains(FileMode::O_APPEND) {
  184. file.lseek(SeekFrom::SeekEnd(0))?;
  185. }
  186. // 如果O_TRUNC,并且,打开模式包含O_RDWR或O_WRONLY,清空文件
  187. if how.o_flags.contains(FileMode::O_TRUNC)
  188. && (how.o_flags.contains(FileMode::O_RDWR) || how.o_flags.contains(FileMode::O_WRONLY))
  189. && file_type == FileType::File
  190. {
  191. file.ftruncate(0)?;
  192. }
  193. // 把文件对象存入pcb
  194. let r = ProcessManager::current_pcb()
  195. .fd_table()
  196. .write()
  197. .alloc_fd(file, None)
  198. .map(|fd| fd as usize);
  199. return r;
  200. }
  201. /// On Linux, futimens() is a library function implemented on top of
  202. /// the utimensat() system call. To support this, the Linux
  203. /// utimensat() system call implements a nonstandard feature: if
  204. /// pathname is NULL, then the call modifies the timestamps of the
  205. /// file referred to by the file descriptor dirfd (which may refer to
  206. /// any type of file).
  207. pub fn do_utimensat(
  208. dirfd: i32,
  209. pathname: Option<String>,
  210. times: Option<[PosixTimeSpec; 2]>,
  211. flags: UtimensFlags,
  212. ) -> Result<usize, SystemError> {
  213. const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
  214. const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
  215. // log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
  216. let inode = match pathname {
  217. Some(path) => {
  218. let (inode_begin, path) =
  219. user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
  220. let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
  221. inode_begin.lookup(path.as_str())?
  222. } else {
  223. inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
  224. };
  225. inode
  226. }
  227. None => {
  228. let binding = ProcessManager::current_pcb().fd_table();
  229. let fd_table_guard = binding.write();
  230. let file = fd_table_guard
  231. .get_file_by_fd(dirfd)
  232. .ok_or(SystemError::EBADF)?;
  233. file.inode()
  234. }
  235. };
  236. let now = PosixTimeSpec::now();
  237. let mut meta = inode.metadata()?;
  238. if let Some([atime, mtime]) = times {
  239. if atime.tv_nsec == UTIME_NOW {
  240. meta.atime = now;
  241. } else if atime.tv_nsec != UTIME_OMIT {
  242. meta.atime = atime;
  243. }
  244. if mtime.tv_nsec == UTIME_NOW {
  245. meta.mtime = now;
  246. } else if mtime.tv_nsec != UTIME_OMIT {
  247. meta.mtime = mtime;
  248. }
  249. inode.set_metadata(&meta).unwrap();
  250. } else {
  251. meta.atime = now;
  252. meta.mtime = now;
  253. inode.set_metadata(&meta).unwrap();
  254. }
  255. return Ok(0);
  256. }
  257. pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
  258. // log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
  259. let (inode_begin, path) = user_path_at(
  260. &ProcessManager::current_pcb(),
  261. AtFlags::AT_FDCWD.bits(),
  262. path,
  263. )?;
  264. let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
  265. let mut meta = inode.metadata()?;
  266. if let Some([atime, mtime]) = times {
  267. meta.atime = PosixTimeSpec::from(atime);
  268. meta.mtime = PosixTimeSpec::from(mtime);
  269. inode.set_metadata(&meta)?;
  270. } else {
  271. let now = PosixTimeSpec::now();
  272. meta.atime = now;
  273. meta.mtime = now;
  274. inode.set_metadata(&meta)?;
  275. }
  276. return Ok(0);
  277. }