file.rs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. use super::utils::*;
  2. use super::Ext4;
  3. use crate::constants::*;
  4. use crate::ext4_defs::*;
  5. use crate::prelude::*;
  6. use crate::return_errno_with_message;
  7. impl Ext4 {
  8. pub fn ext4_generic_open(
  9. &self,
  10. file: &mut Ext4File,
  11. path: &str,
  12. iflags: u32,
  13. ftype: FileType,
  14. parent_inode: &mut Ext4InodeRef,
  15. ) -> Result<usize> {
  16. let mut is_goal = false;
  17. let mut data: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
  18. let ext4_blk = Ext4Block {
  19. logical_block_id: 0,
  20. disk_block_id: 0,
  21. block_data: &mut data,
  22. dirty: true,
  23. };
  24. let de = Ext4DirEntry::default();
  25. let mut dir_search_result = Ext4DirSearchResult::new(ext4_blk, de);
  26. file.flags = iflags;
  27. // load root inode
  28. let root_inode_ref = self.get_root_inode_ref();
  29. // if !parent_inode.is_none() {
  30. // parent_inode.unwrap().inode_num = root_inode_ref.inode_num;
  31. // }
  32. // search dir
  33. let mut search_parent = root_inode_ref;
  34. let mut search_path = ext4_path_skip(&path, ".");
  35. let mut len;
  36. loop {
  37. search_path = ext4_path_skip(search_path, "/");
  38. len = ext4_path_check(search_path, &mut is_goal);
  39. let r = self.dir_find_entry(
  40. &mut search_parent,
  41. &search_path[..len as usize],
  42. &mut dir_search_result,
  43. );
  44. // log::info!("dir_search_result.dentry {:?} r {:?}", dir_search_result.dentry, r);
  45. if r != EOK {
  46. // ext4_dir_destroy_result(&mut root_inode_ref, &mut dir_search_result);
  47. if r != ENOENT {
  48. // dir search failed with error other than ENOENT
  49. return_errno_with_message!(Errnum::ENOTSUP, "dir search failed");
  50. }
  51. if !((iflags & O_CREAT) != 0) {
  52. return_errno_with_message!(Errnum::ENOENT, "file not found");
  53. }
  54. let mut child_inode_ref = Ext4InodeRef::default();
  55. let r = if is_goal {
  56. self.ext4_fs_alloc_inode(&mut child_inode_ref, ftype)
  57. } else {
  58. self.ext4_fs_alloc_inode(&mut child_inode_ref, FileType::Directory)
  59. };
  60. if r != EOK {
  61. return_errno_with_message!(Errnum::EALLOCFIAL, "alloc inode fail");
  62. // break;
  63. }
  64. Self::ext4_fs_inode_blocks_init(&mut child_inode_ref);
  65. let r = self.ext4_link(
  66. &mut search_parent,
  67. &mut child_inode_ref,
  68. &search_path[..len as usize],
  69. );
  70. if r != EOK {
  71. /*Fail. Free new inode.*/
  72. return_errno_with_message!(Errnum::ELINKFIAL, "link fail");
  73. }
  74. self.write_back_inode_with_csum(&mut search_parent);
  75. self.write_back_inode_with_csum(&mut child_inode_ref);
  76. self.write_back_inode_with_csum(parent_inode);
  77. continue;
  78. }
  79. // log::info!("find de name{:?} de inode {:x?}", name, dir_search_result.dentry.inode);
  80. if is_goal {
  81. file.inode = dir_search_result.dentry.inode();
  82. return Ok(EOK);
  83. } else {
  84. search_parent = self.get_inode_ref(dir_search_result.dentry.inode());
  85. search_path = &search_path[len..];
  86. }
  87. }
  88. }
  89. pub fn ext4_open(
  90. &self,
  91. file: &mut Ext4File,
  92. path: &str,
  93. flags: &str,
  94. file_expect: bool,
  95. ) -> Result<usize> {
  96. // get open flags
  97. let iflags = ext4_parse_flags(flags).unwrap();
  98. // get mount point
  99. let mut ptr = Box::new(self.mount_point.clone());
  100. file.mp = Box::as_mut(&mut ptr) as *mut Ext4MountPoint;
  101. // file for dir
  102. let filetype = if file_expect {
  103. FileType::RegularFile
  104. } else {
  105. FileType::Directory
  106. };
  107. if iflags & O_CREAT != 0 {
  108. self.ext4_trans_start();
  109. }
  110. let mut root_inode_ref = self.get_root_inode_ref();
  111. let r = self.ext4_generic_open(file, path, iflags, filetype, &mut root_inode_ref);
  112. r
  113. }
  114. #[allow(unused)]
  115. pub fn ext4_file_read(
  116. &self,
  117. ext4_file: &mut Ext4File,
  118. read_buf: &mut [u8],
  119. size: usize,
  120. read_cnt: &mut usize,
  121. ) -> Result<usize> {
  122. if size == 0 {
  123. return Ok(EOK);
  124. }
  125. let mut inode_ref = self.get_inode_ref(ext4_file.inode);
  126. // sync file size
  127. ext4_file.fsize = inode_ref.inode.size();
  128. let is_softlink =
  129. inode_ref.inode.inode_type(&self.super_block) == EXT4_INODE_MODE_SOFTLINK as u32;
  130. if is_softlink {
  131. log::debug!("ext4_read unsupported softlink");
  132. }
  133. let block_size = BLOCK_SIZE;
  134. // 计算读取大小
  135. let size_to_read = if size > (ext4_file.fsize as usize - ext4_file.fpos) {
  136. ext4_file.fsize as usize - ext4_file.fpos
  137. } else {
  138. size
  139. };
  140. let mut iblock_idx = (ext4_file.fpos / block_size) as u32;
  141. let iblock_last = ((ext4_file.fpos + size_to_read) / block_size) as u32;
  142. let mut unalg = (ext4_file.fpos % block_size) as u32;
  143. let mut offset = 0;
  144. let mut total_bytes_read = 0;
  145. if unalg > 0 {
  146. let first_block_read_len = core::cmp::min(block_size - unalg as usize, size_to_read);
  147. let mut fblock = 0;
  148. self.ext4_fs_get_inode_dblk_idx(&mut inode_ref, &mut iblock_idx, &mut fblock, false);
  149. // if r != EOK {
  150. // return Err(Ext4Error::new(r));
  151. // }
  152. if fblock != 0 {
  153. let block_offset = fblock * block_size as u64 + unalg as u64;
  154. let block_data = self.block_device.read_offset(block_offset as usize);
  155. // Copy data from block to the user buffer
  156. read_buf[offset..offset + first_block_read_len]
  157. .copy_from_slice(&block_data[0..first_block_read_len]);
  158. } else {
  159. // Handle the unwritten block by zeroing out the respective part of the buffer
  160. for x in &mut read_buf[offset..offset + first_block_read_len] {
  161. *x = 0;
  162. }
  163. }
  164. offset += first_block_read_len;
  165. total_bytes_read += first_block_read_len;
  166. ext4_file.fpos += first_block_read_len;
  167. *read_cnt += first_block_read_len;
  168. iblock_idx += 1;
  169. }
  170. // Continue with full block reads
  171. while total_bytes_read < size_to_read {
  172. let read_length = core::cmp::min(block_size, size_to_read - total_bytes_read);
  173. let mut fblock = 0;
  174. self.ext4_fs_get_inode_dblk_idx(&mut inode_ref, &mut iblock_idx, &mut fblock, false);
  175. // if r != EOK {
  176. // return Err(Ext4Error::new(r));
  177. // }
  178. if fblock != 0 {
  179. let block_data = self
  180. .block_device
  181. .read_offset((fblock * block_size as u64) as usize);
  182. read_buf[offset..offset + read_length].copy_from_slice(&block_data[0..read_length]);
  183. } else {
  184. // Handle the unwritten block by zeroing out the respective part of the buffer
  185. for x in &mut read_buf[offset..offset + read_length] {
  186. *x = 0;
  187. }
  188. }
  189. offset += read_length;
  190. total_bytes_read += read_length;
  191. ext4_file.fpos += read_length;
  192. *read_cnt += read_length;
  193. iblock_idx += 1;
  194. }
  195. return Ok(EOK);
  196. }
  197. pub fn ext4_file_write(&self, ext4_file: &mut Ext4File, data: &[u8], size: usize) {
  198. let super_block_data = self.block_device.read_offset(BASE_OFFSET);
  199. let super_block = Ext4Superblock::try_from(super_block_data).unwrap();
  200. let mut inode_ref = self.get_inode_ref(ext4_file.inode);
  201. let block_size = super_block.block_size() as usize;
  202. let iblock_last = ext4_file.fpos as usize + size / block_size;
  203. let mut iblk_idx = ext4_file.fpos as usize / block_size;
  204. let ifile_blocks = ext4_file.fsize as usize + block_size - 1 / block_size;
  205. let mut fblk = 0;
  206. let mut fblock_start = 0;
  207. let mut fblock_count = 0;
  208. let mut size = size;
  209. while size >= block_size {
  210. while iblk_idx < iblock_last {
  211. if iblk_idx < ifile_blocks {
  212. self.ext4_fs_append_inode_dblk(
  213. &mut inode_ref,
  214. &mut (iblk_idx as u32),
  215. &mut fblk,
  216. );
  217. }
  218. iblk_idx += 1;
  219. if fblock_start == 0 {
  220. fblock_start = fblk;
  221. }
  222. fblock_count += 1;
  223. }
  224. size -= block_size;
  225. }
  226. for i in 0..fblock_count {
  227. let idx = i * BLOCK_SIZE as usize;
  228. let offset = (fblock_start as usize + i as usize) * BLOCK_SIZE;
  229. self.block_device
  230. .write_offset(offset, &data[idx..(idx + BLOCK_SIZE as usize)]);
  231. }
  232. // inode_ref.inner.inode.size = fblock_count as u32 * BLOCK_SIZE as u32;
  233. self.write_back_inode_with_csum(&mut inode_ref);
  234. // let mut inode_ref = Ext4InodeRef::get_inode_ref(self.self_ref.clone(), ext4_file.inode);
  235. let mut root_inode_ref = self.get_root_inode_ref();
  236. self.write_back_inode_with_csum(&mut root_inode_ref);
  237. }
  238. pub fn ext4_file_remove(&self, _path: &str) -> Result<usize> {
  239. return_errno_with_message!(Errnum::ENOTSUP, "not support");
  240. }
  241. }