stat.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. use system_error::SystemError;
  2. use crate::{
  3. arch::filesystem::stat::PosixStat,
  4. driver::base::device::device_number::DeviceNumber,
  5. filesystem::vfs::{mount::is_mountpoint_root, vcore::do_file_lookup_at},
  6. process::ProcessManager,
  7. syscall::user_access::UserBufferWriter,
  8. time::PosixTimeSpec,
  9. };
  10. use alloc::sync::Arc;
  11. use super::{
  12. fcntl::AtFlags,
  13. syscall::{ModeType, PosixStatx, PosixStatxMask, StxAttributes},
  14. IndexNode,
  15. };
  16. #[derive(Clone)]
  17. pub struct KStat {
  18. pub result_mask: PosixStatxMask, // What fields the user got
  19. pub mode: ModeType, // umode_t
  20. pub nlink: u32,
  21. pub blksize: u32, // Preferred I/O size
  22. pub attributes: StxAttributes,
  23. pub attributes_mask: StxAttributes,
  24. pub ino: u64,
  25. pub dev: DeviceNumber, // dev_t
  26. pub rdev: DeviceNumber, // dev_t
  27. pub uid: u32, // kuid_t
  28. pub gid: u32, // kgid_t
  29. pub size: usize, // loff_t
  30. pub atime: PosixTimeSpec, // struct timespec64
  31. pub mtime: PosixTimeSpec, // struct timespec64
  32. pub ctime: PosixTimeSpec, // struct timespec64
  33. pub btime: PosixTimeSpec, // File creation time
  34. pub blocks: u64,
  35. pub mnt_id: u64,
  36. pub dio_mem_align: u32,
  37. pub dio_offset_align: u32,
  38. }
  39. impl Default for KStat {
  40. fn default() -> Self {
  41. Self {
  42. result_mask: PosixStatxMask::empty(),
  43. mode: ModeType::empty(),
  44. nlink: Default::default(),
  45. blksize: Default::default(),
  46. attributes: StxAttributes::empty(),
  47. attributes_mask: StxAttributes::empty(),
  48. ino: Default::default(),
  49. dev: Default::default(),
  50. rdev: Default::default(),
  51. uid: Default::default(),
  52. gid: Default::default(),
  53. size: Default::default(),
  54. atime: Default::default(),
  55. mtime: Default::default(),
  56. ctime: Default::default(),
  57. btime: Default::default(),
  58. blocks: Default::default(),
  59. mnt_id: Default::default(),
  60. dio_mem_align: Default::default(),
  61. dio_offset_align: Default::default(),
  62. }
  63. }
  64. }
  65. bitflags! {
  66. /// https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/namei.h?fi=LOOKUP_FOLLOW#21
  67. pub struct LookUpFlags: u32 {
  68. /// follow links at the end
  69. const FOLLOW = 0x0001;
  70. /// require a directory
  71. const DIRECTORY = 0x0002;
  72. /// force terminal automount
  73. const AUTOMOUNT = 0x0004;
  74. /// accept empty path [user_... only]
  75. const EMPTY = 0x4000;
  76. /// follow mounts in the starting point
  77. const DOWN = 0x8000;
  78. /// follow mounts in the end
  79. const MOUNTPOINT = 0x0080;
  80. /// tell ->d_revalidate() to trust no cache
  81. const REVAL = 0x0020;
  82. /// RCU pathwalk mode; semi-internal
  83. const RCU = 0x0040;
  84. /// ... in open
  85. const OPEN = 0x0100;
  86. /// ... in object creation
  87. const CREATE = 0x0200;
  88. /// ... in exclusive creation
  89. const EXCL = 0x0400;
  90. /// ... in destination of rename()
  91. const RENAME_TARGET = 0x0800;
  92. /// internal use only
  93. const PARENT = 0x0010;
  94. /// No symlink crossing
  95. const NO_SYMLINKS = 0x010000;
  96. /// No nd_jump_link() crossing
  97. const NO_MAGICLINKS = 0x020000;
  98. /// No mountpoint crossing
  99. const NO_XDEV = 0x040000;
  100. /// No escaping from starting point
  101. const BENEATH = 0x080000;
  102. /// Treat dirfd as fs root
  103. const IN_ROOT = 0x100000;
  104. /// Only do cached lookup
  105. const CACHED = 0x200000;
  106. /// LOOKUP_* flags which do scope-related checks based on the dirfd.
  107. const IS_SCOPED = LookUpFlags::BENEATH.bits | LookUpFlags::IN_ROOT.bits;
  108. }
  109. }
  110. impl From<AtFlags> for LookUpFlags {
  111. fn from(value: AtFlags) -> Self {
  112. let mut lookup_flags = LookUpFlags::empty();
  113. if !value.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
  114. lookup_flags |= LookUpFlags::FOLLOW;
  115. }
  116. if !value.contains(AtFlags::AT_NO_AUTOMOUNT) {
  117. lookup_flags |= LookUpFlags::AUTOMOUNT;
  118. }
  119. if value.contains(AtFlags::AT_EMPTY_PATH) {
  120. lookup_flags |= LookUpFlags::EMPTY;
  121. }
  122. lookup_flags
  123. }
  124. }
  125. /// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#232
  126. #[inline(never)]
  127. pub fn vfs_statx(
  128. dfd: i32,
  129. filename: &str,
  130. flags: AtFlags,
  131. request_mask: PosixStatxMask,
  132. ) -> Result<KStat, SystemError> {
  133. let lookup_flags: LookUpFlags = flags.into();
  134. // Validate flags - only allowed flags are AT_SYMLINK_NOFOLLOW, AT_NO_AUTOMOUNT, AT_EMPTY_PATH, AT_STATX_SYNC_TYPE
  135. if flags.intersects(
  136. !(AtFlags::AT_SYMLINK_NOFOLLOW
  137. | AtFlags::AT_NO_AUTOMOUNT
  138. | AtFlags::AT_EMPTY_PATH
  139. | AtFlags::AT_STATX_SYNC_TYPE),
  140. ) {
  141. return Err(SystemError::EINVAL);
  142. }
  143. let inode = do_file_lookup_at(dfd, filename, lookup_flags)?;
  144. let mut kstat = vfs_getattr(&inode, request_mask, flags)?;
  145. if is_mountpoint_root(&inode) {
  146. kstat
  147. .attributes
  148. .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
  149. }
  150. kstat
  151. .attributes_mask
  152. .insert(StxAttributes::STATX_ATTR_MOUNT_ROOT);
  153. // todo: 添加 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#266 这里的逻辑
  154. Ok(kstat)
  155. }
  156. /// 获取文件的增强基本属性
  157. ///
  158. /// # 参数
  159. /// - `path`: 目标文件路径
  160. /// - `stat`: 用于返回统计信息的结构体
  161. /// - `request_mask`: PosixStatxMask标志位,指示调用者需要哪些属性
  162. /// - `query_flags`: 查询模式(AT_STATX_SYNC_TYPE)
  163. ///
  164. /// # 描述
  165. /// 向文件系统请求文件的属性。调用者必须通过request_mask和query_flags指定需要的信息。
  166. ///
  167. /// 如果文件是远程的:
  168. /// - 可以通过传递AT_STATX_FORCE_SYNC强制文件系统从后端存储更新属性
  169. /// - 可以通过传递AT_STATX_DONT_SYNC禁止更新
  170. ///
  171. /// request_mask中必须设置相应的位来指示调用者需要检索哪些属性。
  172. /// 未请求的属性也可能被返回,但其值可能是近似的,如果是远程文件,
  173. /// 可能没有与服务器同步。
  174. ///
  175. /// # 返回值
  176. /// 成功时返回0,失败时返回负的错误码
  177. ///
  178. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#165
  179. #[inline(never)]
  180. pub fn vfs_getattr(
  181. inode: &Arc<dyn IndexNode>,
  182. request_mask: PosixStatxMask,
  183. mut at_flags: AtFlags,
  184. ) -> Result<KStat, SystemError> {
  185. if at_flags.contains(AtFlags::AT_GETATTR_NOSEC) {
  186. return Err(SystemError::EPERM);
  187. }
  188. let mut kstat = KStat::default();
  189. kstat.result_mask |= PosixStatxMask::STATX_BASIC_STATS;
  190. at_flags &= AtFlags::AT_STATX_SYNC_TYPE;
  191. let metadata = inode.metadata()?;
  192. if metadata.atime.is_empty() {
  193. kstat.result_mask.remove(PosixStatxMask::STATX_ATIME);
  194. }
  195. // todo: 添加automount和dax属性
  196. kstat.blksize = metadata.blk_size as u32;
  197. if request_mask.contains(PosixStatxMask::STATX_MODE)
  198. || request_mask.contains(PosixStatxMask::STATX_TYPE)
  199. {
  200. kstat.mode = metadata.mode;
  201. }
  202. if request_mask.contains(PosixStatxMask::STATX_NLINK) {
  203. kstat.nlink = metadata.nlinks as u32;
  204. }
  205. if request_mask.contains(PosixStatxMask::STATX_UID) {
  206. kstat.uid = metadata.uid as u32;
  207. }
  208. if request_mask.contains(PosixStatxMask::STATX_GID) {
  209. kstat.gid = metadata.gid as u32;
  210. }
  211. if request_mask.contains(PosixStatxMask::STATX_ATIME) {
  212. kstat.atime.tv_sec = metadata.atime.tv_sec;
  213. kstat.atime.tv_nsec = metadata.atime.tv_nsec;
  214. }
  215. if request_mask.contains(PosixStatxMask::STATX_MTIME) {
  216. kstat.mtime.tv_sec = metadata.mtime.tv_sec;
  217. kstat.mtime.tv_nsec = metadata.mtime.tv_nsec;
  218. }
  219. if request_mask.contains(PosixStatxMask::STATX_CTIME) {
  220. // ctime是文件上次修改状态的时间
  221. kstat.ctime.tv_sec = metadata.ctime.tv_sec;
  222. kstat.ctime.tv_nsec = metadata.ctime.tv_nsec;
  223. }
  224. if request_mask.contains(PosixStatxMask::STATX_INO) {
  225. kstat.ino = metadata.inode_id.into() as u64;
  226. }
  227. if request_mask.contains(PosixStatxMask::STATX_SIZE) {
  228. kstat.size = metadata.size as usize;
  229. }
  230. if request_mask.contains(PosixStatxMask::STATX_BLOCKS) {
  231. kstat.blocks = metadata.blocks as u64;
  232. }
  233. if request_mask.contains(PosixStatxMask::STATX_BTIME) {
  234. // btime是文件创建时间
  235. kstat.btime.tv_sec = metadata.btime.tv_sec;
  236. kstat.btime.tv_nsec = metadata.btime.tv_nsec;
  237. }
  238. if request_mask.contains(PosixStatxMask::STATX_ALL) {
  239. kstat.attributes = StxAttributes::STATX_ATTR_APPEND;
  240. kstat.attributes_mask |=
  241. StxAttributes::STATX_ATTR_AUTOMOUNT | StxAttributes::STATX_ATTR_DAX;
  242. kstat.dev = DeviceNumber::from(metadata.dev_id as u32);
  243. kstat.rdev = metadata.raw_dev;
  244. }
  245. // 把文件类型加入mode里面 (todo: 在具体的文件系统里面去实现这个操作。这里只是权宜之计)
  246. kstat.mode |= metadata.file_type.into();
  247. return Ok(kstat);
  248. }
  249. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#274
  250. #[inline(never)]
  251. pub fn vfs_fstatat(dfd: i32, filename: &str, flags: AtFlags) -> Result<KStat, SystemError> {
  252. let statx_flags = flags | AtFlags::AT_NO_AUTOMOUNT;
  253. if dfd >= 0 && flags == AtFlags::AT_EMPTY_PATH {
  254. return vfs_fstat(dfd);
  255. }
  256. return vfs_statx(
  257. dfd,
  258. filename,
  259. statx_flags,
  260. PosixStatxMask::STATX_BASIC_STATS,
  261. );
  262. }
  263. /// vfs_fstat - Get the basic attributes by file descriptor
  264. ///
  265. /// # Arguments
  266. /// - fd: The file descriptor referring to the file of interest
  267. ///
  268. /// This function is a wrapper around vfs_getattr(). The main difference is
  269. /// that it uses a file descriptor to determine the file location.
  270. ///
  271. /// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#190
  272. pub fn vfs_fstat(dfd: i32) -> Result<KStat, SystemError> {
  273. // Get the file from the file descriptor
  274. let pcb = ProcessManager::current_pcb();
  275. let fd_table = pcb.fd_table();
  276. let file = fd_table
  277. .read()
  278. .get_file_by_fd(dfd)
  279. .ok_or(SystemError::EBADF)?;
  280. let inode = file.inode();
  281. // Get attributes using vfs_getattr with basic stats mask
  282. vfs_getattr(&inode, PosixStatxMask::STATX_BASIC_STATS, AtFlags::empty())
  283. }
  284. pub(super) fn do_newfstatat(
  285. dfd: i32,
  286. filename: &str,
  287. user_stat_buf_ptr: usize,
  288. flags: u32,
  289. ) -> Result<(), SystemError> {
  290. let kstat = vfs_fstatat(dfd, filename, AtFlags::from_bits_truncate(flags as i32))?;
  291. cp_new_stat(kstat, user_stat_buf_ptr)
  292. }
  293. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#393
  294. #[inline(never)]
  295. fn cp_new_stat(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> {
  296. let posix_stat = PosixStat::try_from(kstat)?;
  297. let mut ubuf_writer =
  298. UserBufferWriter::new(user_buf_ptr as *mut PosixStat, size_of::<PosixStat>(), true)?;
  299. ubuf_writer
  300. .copy_one_to_user(&posix_stat, 0)
  301. .map_err(|_| SystemError::EFAULT)
  302. }
  303. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#660
  304. pub(super) fn do_statx(
  305. dfd: i32,
  306. filename: &str,
  307. flags: u32,
  308. mask: u32,
  309. user_kstat_ptr: usize,
  310. ) -> Result<(), SystemError> {
  311. let mask = PosixStatxMask::from_bits_truncate(mask);
  312. if mask.contains(PosixStatxMask::STATX_RESERVED) {
  313. return Err(SystemError::EINVAL);
  314. }
  315. let flags = AtFlags::from_bits_truncate(flags as i32);
  316. if flags.contains(AtFlags::AT_STATX_SYNC_TYPE) {
  317. return Err(SystemError::EINVAL);
  318. }
  319. let kstat = vfs_statx(dfd, filename, flags, mask)?;
  320. cp_statx(kstat, user_kstat_ptr)
  321. }
  322. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/fs/stat.c#622
  323. #[inline(never)]
  324. fn cp_statx(kstat: KStat, user_buf_ptr: usize) -> Result<(), SystemError> {
  325. let mut userbuf = UserBufferWriter::new(
  326. user_buf_ptr as *mut PosixStatx,
  327. size_of::<PosixStatx>(),
  328. true,
  329. )?;
  330. let mut statx: PosixStatx = PosixStatx::new();
  331. // Copy fields from KStat to PosixStatx
  332. statx.stx_mask = kstat.result_mask & !PosixStatxMask::STATX_CHANGE_COOKIE;
  333. statx.stx_blksize = kstat.blksize;
  334. statx.stx_attributes = kstat.attributes & !StxAttributes::STATX_ATTR_CHANGE_MONOTONIC;
  335. statx.stx_nlink = kstat.nlink;
  336. statx.stx_uid = kstat.uid;
  337. statx.stx_gid = kstat.gid;
  338. statx.stx_mode = kstat.mode;
  339. statx.stx_inode = kstat.ino;
  340. statx.stx_size = kstat.size as i64;
  341. statx.stx_blocks = kstat.blocks;
  342. statx.stx_attributes_mask = kstat.attributes_mask;
  343. // Copy time fields
  344. statx.stx_atime = kstat.atime;
  345. statx.stx_btime = kstat.btime;
  346. statx.stx_ctime = kstat.ctime;
  347. statx.stx_mtime = kstat.mtime;
  348. // Convert device numbers
  349. statx.stx_rdev_major = kstat.rdev.major().data();
  350. statx.stx_rdev_minor = kstat.rdev.minor();
  351. statx.stx_dev_major = kstat.dev.major().data();
  352. statx.stx_dev_minor = kstat.dev.minor();
  353. statx.stx_mnt_id = kstat.mnt_id;
  354. statx.stx_dio_mem_align = kstat.dio_mem_align;
  355. statx.stx_dio_offset_align = kstat.dio_offset_align;
  356. // Write to user space
  357. userbuf.copy_one_to_user(&statx, 0)?;
  358. Ok(())
  359. }
  360. // 注意!这个结构体定义的貌似不太对,需要修改!
  361. #[repr(C)]
  362. #[derive(Clone, Copy)]
  363. /// # 文件信息结构体
  364. pub struct PosixKstat {
  365. /// 硬件设备ID
  366. pub dev_id: u64,
  367. /// inode号
  368. pub inode: u64,
  369. /// 硬链接数
  370. pub nlink: u64,
  371. /// 文件权限
  372. pub mode: ModeType,
  373. /// 所有者用户ID
  374. pub uid: i32,
  375. /// 所有者组ID
  376. pub gid: i32,
  377. /// 设备ID
  378. pub rdev: i64,
  379. /// 文件大小
  380. pub size: i64,
  381. /// 文件系统块大小
  382. pub blcok_size: i64,
  383. /// 分配的512B块数
  384. pub blocks: u64,
  385. /// 最后访问时间
  386. pub atime: PosixTimeSpec,
  387. /// 最后修改时间
  388. pub mtime: PosixTimeSpec,
  389. /// 最后状态变化时间
  390. pub ctime: PosixTimeSpec,
  391. /// 用于填充结构体大小的空白数据
  392. pub _pad: [i8; 24],
  393. }
  394. impl PosixKstat {
  395. pub(super) fn new() -> Self {
  396. Self {
  397. inode: 0,
  398. dev_id: 0,
  399. mode: ModeType::empty(),
  400. nlink: 0,
  401. uid: 0,
  402. gid: 0,
  403. rdev: 0,
  404. size: 0,
  405. atime: PosixTimeSpec {
  406. tv_sec: 0,
  407. tv_nsec: 0,
  408. },
  409. mtime: PosixTimeSpec {
  410. tv_sec: 0,
  411. tv_nsec: 0,
  412. },
  413. ctime: PosixTimeSpec {
  414. tv_sec: 0,
  415. tv_nsec: 0,
  416. },
  417. blcok_size: 0,
  418. blocks: 0,
  419. _pad: Default::default(),
  420. }
  421. }
  422. }