inode_file.rs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. use super::{File, FileType, SeekOption};
  2. use crate::{
  3. io::{Buffer, BufferFill, Stream},
  4. kernel::{
  5. constants::{EBADF, EFAULT, ENOTDIR, EOVERFLOW, ESPIPE},
  6. vfs::{
  7. dentry::Dentry,
  8. inode::{Inode, InodeUse, WriteOffset},
  9. types::Format,
  10. },
  11. },
  12. prelude::KResult,
  13. };
  14. use alloc::sync::Arc;
  15. use eonix_sync::Mutex;
  16. use posix_types::{
  17. getdent::{UserDirent, UserDirent64},
  18. open::OpenFlags,
  19. stat::StatX,
  20. };
  21. pub struct InodeFile {
  22. pub r: bool,
  23. pub w: bool,
  24. pub a: bool,
  25. /// Only a few modes those won't possibly change are cached here to speed up file operations.
  26. /// Specifically, `S_IFMT` masked bits.
  27. pub format: Format,
  28. cursor: Mutex<usize>,
  29. dentry: Arc<Dentry>,
  30. }
  31. impl InodeFile {
  32. pub fn new(dentry: Arc<Dentry>, flags: OpenFlags) -> File {
  33. // SAFETY: `dentry` used to create `InodeFile` is valid.
  34. // SAFETY: `mode` should never change with respect to the `S_IFMT` fields.
  35. let format = dentry.inode().expect("dentry should be invalid").format();
  36. let (r, w, a) = flags.as_rwa();
  37. File::new(
  38. flags,
  39. FileType::Inode(InodeFile {
  40. dentry,
  41. r,
  42. w,
  43. a,
  44. format,
  45. cursor: Mutex::new(0),
  46. }),
  47. )
  48. }
  49. pub fn sendfile_check(&self) -> KResult<()> {
  50. match self.format {
  51. Format::REG | Format::BLK => Ok(()),
  52. _ => Err(EBADF),
  53. }
  54. }
  55. pub async fn write(&self, stream: &mut dyn Stream, offset: Option<usize>) -> KResult<usize> {
  56. if !self.w {
  57. return Err(EBADF);
  58. }
  59. let mut cursor = self.cursor.lock().await;
  60. let (offset, update_offset) = match (self.a, offset) {
  61. (true, _) => (WriteOffset::End(&mut cursor), None),
  62. (false, Some(offset)) => (WriteOffset::Position(offset), None),
  63. (false, None) => (WriteOffset::Position(*cursor), Some(&mut *cursor)),
  64. };
  65. let nr_write = self.dentry.write(stream, offset).await?;
  66. if let Some(update_offset) = update_offset {
  67. *update_offset += nr_write;
  68. }
  69. Ok(nr_write)
  70. }
  71. pub async fn read(&self, buffer: &mut dyn Buffer, offset: Option<usize>) -> KResult<usize> {
  72. if !self.r {
  73. return Err(EBADF);
  74. }
  75. if let Some(offset) = offset {
  76. return Ok(self.dentry.read(buffer, offset).await?);
  77. }
  78. let mut cursor = self.cursor.lock().await;
  79. let nread = self.dentry.read(buffer, *cursor).await?;
  80. *cursor += nread;
  81. Ok(nread)
  82. }
  83. }
  84. impl File {
  85. pub fn get_inode(&self) -> KResult<Option<InodeUse<dyn Inode>>> {
  86. if let FileType::Inode(inode_file) = &**self {
  87. Ok(Some(inode_file.dentry.get_inode()?))
  88. } else {
  89. Ok(None)
  90. }
  91. }
  92. pub async fn getdents(&self, buffer: &mut dyn Buffer) -> KResult<()> {
  93. let FileType::Inode(inode_file) = &**self else {
  94. return Err(ENOTDIR);
  95. };
  96. let mut cursor = inode_file.cursor.lock().await;
  97. let nread = inode_file
  98. .dentry
  99. .readdir(*cursor, |filename, ino| {
  100. // + 1 for filename length padding '\0', + 1 for d_type.
  101. let real_record_len = core::mem::size_of::<UserDirent>() + filename.len() + 2;
  102. if buffer.available() < real_record_len {
  103. return Ok(false);
  104. }
  105. let record = UserDirent {
  106. d_ino: ino.as_raw() as u32,
  107. d_off: 0,
  108. d_reclen: real_record_len as u16,
  109. d_name: [0; 0],
  110. };
  111. buffer.copy(&record)?.ok_or(EFAULT)?;
  112. buffer.fill(filename)?.ok_or(EFAULT)?;
  113. buffer.fill(&[0, 0])?.ok_or(EFAULT)?;
  114. Ok(true)
  115. })
  116. .await??;
  117. *cursor += nread;
  118. Ok(())
  119. }
  120. pub async fn getdents64(&self, buffer: &mut dyn Buffer) -> KResult<()> {
  121. let FileType::Inode(inode_file) = &**self else {
  122. return Err(ENOTDIR);
  123. };
  124. let mut cursor = inode_file.cursor.lock().await;
  125. let nread = inode_file
  126. .dentry
  127. .readdir(*cursor, |filename, ino| {
  128. // Filename length + 1 for padding '\0'
  129. let real_record_len = core::mem::size_of::<UserDirent64>() + filename.len() + 1;
  130. if buffer.available() < real_record_len {
  131. return Ok(false);
  132. }
  133. let record = UserDirent64 {
  134. d_ino: ino.as_raw(),
  135. d_off: 0,
  136. d_reclen: real_record_len as u16,
  137. d_type: 0,
  138. d_name: [0; 0],
  139. };
  140. buffer.copy(&record)?.ok_or(EFAULT)?;
  141. buffer.fill(filename)?.ok_or(EFAULT)?;
  142. buffer.fill(&[0])?.ok_or(EFAULT)?;
  143. Ok(true)
  144. })
  145. .await??;
  146. *cursor += nread;
  147. Ok(())
  148. }
  149. pub async fn seek(&self, option: SeekOption) -> KResult<usize> {
  150. let FileType::Inode(inode_file) = &**self else {
  151. return Err(ESPIPE);
  152. };
  153. let mut cursor = inode_file.cursor.lock().await;
  154. let new_cursor = match option {
  155. SeekOption::Current(off) => cursor.checked_add_signed(off).ok_or(EOVERFLOW)?,
  156. SeekOption::Set(n) => n,
  157. SeekOption::End(off) => {
  158. let inode = inode_file.dentry.get_inode()?;
  159. let size = inode.info().lock().size as usize;
  160. size.checked_add_signed(off).ok_or(EOVERFLOW)?
  161. }
  162. };
  163. *cursor = new_cursor;
  164. Ok(new_cursor)
  165. }
  166. pub fn statx(&self, buffer: &mut StatX, mask: u32) -> KResult<()> {
  167. if let FileType::Inode(inode) = &**self {
  168. inode.dentry.statx(buffer, mask)
  169. } else {
  170. Err(EBADF)
  171. }
  172. }
  173. pub fn as_path(&self) -> Option<&Arc<Dentry>> {
  174. if let FileType::Inode(inode_file) = &**self {
  175. Some(&inode_file.dentry)
  176. } else {
  177. None
  178. }
  179. }
  180. }