open.rs 10 KB

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