low_level.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. //! Low-level operations of Ext4 filesystem.
  2. //!
  3. //! These interfaces are designed and arranged coresponding to FUSE low-level ops.
  4. //! Ref: https://libfuse.github.io/doxygen/structfuse__lowlevel__ops.html
  5. use super::Ext4;
  6. use crate::constants::*;
  7. use crate::ext4_defs::*;
  8. use crate::prelude::*;
  9. use crate::return_error;
  10. use core::cmp::min;
  11. impl Ext4 {
  12. /// Read an indoe
  13. ///
  14. /// # Params
  15. ///
  16. /// * `id` - inode id
  17. ///
  18. /// # Return
  19. ///
  20. /// An inode reference, combing id and the inode itself
  21. pub fn inode(&self, id: InodeId) -> InodeRef {
  22. self.read_inode(id)
  23. }
  24. /// Create and open a file. This function will not check the existence
  25. /// of the file. Call `lookup` to check beforehand.
  26. ///
  27. /// # Params
  28. ///
  29. /// * `parent` - parent directory inode id
  30. /// * `name` - file name
  31. /// * `mode` - file type and mode with which to create the new file
  32. /// * `flags` - open flags
  33. ///
  34. /// # Return
  35. ///
  36. /// `Ok(inode)` - Inode id of the new file
  37. ///
  38. /// # Error
  39. ///
  40. /// * `ENOTDIR` - `parent` is not a directory
  41. /// * `ENOSPC` - No space left on device
  42. pub fn create(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
  43. let mut parent = self.read_inode(parent);
  44. // Can only create a file in a directory
  45. if !parent.inode.is_dir() {
  46. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  47. }
  48. // Create child inode and link it to parent directory
  49. let mut child = self.create_inode(mode)?;
  50. self.link_inode(&mut parent, &mut child, name)?;
  51. // Create file handler
  52. Ok(child.id)
  53. }
  54. /// Read data from a file. This function will read exactly `buf.len()`
  55. /// bytes unless the end of the file is reached.
  56. ///
  57. /// # Params
  58. ///
  59. /// * `file` - the file handler, acquired by `open` or `create`
  60. /// * `offset` - offset to read from
  61. /// * `buf` - the buffer to store the data
  62. ///
  63. /// # Return
  64. ///
  65. /// `Ok(usize)` - the actual number of bytes read
  66. ///
  67. /// # Error
  68. ///
  69. /// * `EISDIR` - `file` is not a regular file
  70. ///
  71. /// TODO: handle EOF
  72. pub fn read(&mut self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
  73. // Get the inode of the file
  74. let mut inode_ref = self.read_inode(file);
  75. if !inode_ref.inode.is_file() {
  76. return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
  77. }
  78. let read_size = buf.len();
  79. // Read no bytes
  80. if read_size == 0 {
  81. return Ok(0);
  82. }
  83. // Get file size
  84. let fsize = inode_ref.inode.size();
  85. // Calc the actual size to read
  86. let size_to_read = min(read_size, fsize as usize - offset);
  87. // Calc the start block of reading
  88. let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
  89. // Calc the length that is not aligned to the block size
  90. let misaligned = offset % BLOCK_SIZE;
  91. let mut cursor = 0;
  92. let mut iblock = start_iblock;
  93. // Read first block
  94. if misaligned > 0 {
  95. let read_len = min(BLOCK_SIZE - misaligned, size_to_read);
  96. let fblock = self
  97. .extent_get_pblock(&mut inode_ref, start_iblock)
  98. .unwrap();
  99. let block = self.read_block(fblock);
  100. // Copy data from block to the user buffer
  101. buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(misaligned, read_len));
  102. cursor += read_len;
  103. iblock += 1;
  104. }
  105. // Continue with full block reads
  106. while cursor < size_to_read {
  107. let read_len = min(BLOCK_SIZE, size_to_read - cursor);
  108. let fblock = self.extent_get_pblock(&mut inode_ref, iblock).unwrap();
  109. let block = self.read_block(fblock);
  110. // Copy data from block to the user buffer
  111. buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(0, read_len));
  112. cursor += read_len;
  113. iblock += 1;
  114. }
  115. Ok(cursor)
  116. }
  117. /// Write data to a file. This function will write exactly `data.len()` bytes.
  118. ///
  119. /// # Params
  120. ///
  121. /// * `file` - the file handler, acquired by `open` or `create`
  122. /// * `offset` - offset to write to
  123. /// * `data` - the data to write
  124. ///
  125. /// # Return
  126. ///
  127. /// `Ok(usize)` - the actual number of bytes written
  128. ///
  129. /// # Error
  130. ///
  131. /// * `EISDIR` - `file` is not a regular file
  132. /// `ENOSPC` - no space left on device
  133. ///
  134. /// TODO: handle EOF
  135. pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
  136. // Get the inode of the file
  137. let mut inode_ref = self.read_inode(file);
  138. if !inode_ref.inode.is_file() {
  139. return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
  140. }
  141. let write_size = data.len();
  142. // Calc the start and end block of reading
  143. let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
  144. let end_iblock = ((offset + write_size) / BLOCK_SIZE) as LBlockId;
  145. // Calc the block count of the file
  146. let block_count = (offset as usize + BLOCK_SIZE - 1) / BLOCK_SIZE;
  147. // Append enough block for writing
  148. let append_block_count = end_iblock + 1 - block_count as LBlockId;
  149. for _ in 0..append_block_count {
  150. self.inode_append_block(&mut inode_ref)?;
  151. }
  152. // Write data
  153. let mut cursor = 0;
  154. let mut iblock = start_iblock;
  155. while cursor < write_size {
  156. let write_len = min(BLOCK_SIZE, write_size - cursor);
  157. let fblock = self.extent_get_pblock(&mut inode_ref, iblock)?;
  158. let mut block = self.read_block(fblock);
  159. block.write_offset(
  160. (offset + cursor) % BLOCK_SIZE,
  161. &data[cursor..cursor + write_len],
  162. );
  163. self.write_block(&block);
  164. cursor += write_len;
  165. iblock += 1;
  166. }
  167. Ok(cursor)
  168. }
  169. /// Create a hard link. This function will not check name conflict.
  170. /// Call `lookup` to check beforehand.
  171. ///
  172. /// # Params
  173. ///
  174. /// * `child` - the inode of the file to link
  175. /// * `parent` - the inode of the directory to link to
  176. ///
  177. /// # Return
  178. ///
  179. /// `Ok(child)` - An inode reference to the child inode.
  180. ///
  181. /// # Error
  182. ///
  183. /// * `ENOTDIR` - `parent` is not a directory
  184. /// * `ENOSPC` - no space left on device
  185. pub fn link(&mut self, child: InodeId, parent: InodeId, name: &str) -> Result<InodeRef> {
  186. let mut parent = self.read_inode(parent);
  187. // Can only link to a directory
  188. if !parent.inode.is_dir() {
  189. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  190. }
  191. let mut child = self.read_inode(child);
  192. self.link_inode(&mut parent, &mut child, name)?;
  193. Ok(child)
  194. }
  195. /// Unlink a file.
  196. ///
  197. /// # Params
  198. ///
  199. /// * `parent` - the inode of the directory to unlink from
  200. /// * `name` - the name of the file to unlink
  201. ///
  202. /// # Error
  203. ///
  204. /// * `ENOTDIR` - `parent` is not a directory
  205. /// * `ENOENT` - `name` does not exist in `parent`
  206. pub fn unlink(&mut self, parent: InodeId, name: &str) -> Result<()> {
  207. let mut parent = self.read_inode(parent);
  208. // Can only unlink from a directory
  209. if !parent.inode.is_dir() {
  210. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  211. }
  212. let child_id = self.dir_find_entry(&parent, name)?.inode();
  213. let mut child = self.read_inode(child_id);
  214. self.unlink_inode(&mut parent, &mut child, name)
  215. }
  216. /// Move a file. This function will not check name conflict.
  217. /// Call `lookup` to check beforehand.
  218. ///
  219. /// # Params
  220. ///
  221. /// * `parent` - the inode of the directory to move from
  222. /// * `name` - the name of the file to move
  223. /// * `new_parent` - the inode of the directory to move to
  224. /// * `new_name` - the new name of the file
  225. ///
  226. /// # Error
  227. ///
  228. /// * `ENOTDIR` - `parent` or `new_parent` is not a directory
  229. /// * `ENOENT` - `name` does not exist in `parent`
  230. /// * `ENOSPC` - no space left on device
  231. pub fn rename(
  232. &mut self,
  233. parent: InodeId,
  234. name: &str,
  235. new_parent: InodeId,
  236. new_name: &str,
  237. ) -> Result<()> {
  238. let mut parent = self.read_inode(parent);
  239. if !parent.inode.is_dir() {
  240. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  241. }
  242. let mut new_parent = self.read_inode(new_parent);
  243. if !new_parent.inode.is_dir() {
  244. return_error!(
  245. ErrCode::ENOTDIR,
  246. "Inode {} is not a directory",
  247. new_parent.id
  248. );
  249. }
  250. let child_id = self.dir_find_entry(&parent, name)?;
  251. let mut child = self.read_inode(child_id.inode());
  252. self.link_inode(&mut new_parent, &mut child, new_name)?;
  253. self.unlink_inode(&mut parent, &mut child, name)
  254. }
  255. /// Create a directory. This function will not check name conflict.
  256. /// Call `lookup` to check beforehand.
  257. ///
  258. /// # Params
  259. ///
  260. /// * `parent` - the inode of the directory to create in
  261. /// * `name` - the name of the directory to create
  262. /// * `mode` - the mode of the directory to create, type field will be ignored
  263. ///
  264. /// # Return
  265. ///
  266. /// `Ok(child)` - An inode reference to the new directory.
  267. ///
  268. /// # Error
  269. ///
  270. /// * `ENOTDIR` - `parent` is not a directory
  271. /// * `ENOSPC` - no space left on device
  272. pub fn mkdir(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeRef> {
  273. let mut parent = self.read_inode(parent);
  274. // Can only create a directory in a directory
  275. if !parent.inode.is_dir() {
  276. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  277. }
  278. // Create file/directory
  279. let mode = mode & InodeMode::PERM_MASK | InodeMode::DIRECTORY;
  280. let mut child = self.create_inode(mode)?;
  281. // Link the new inode
  282. self.link_inode(&mut parent, &mut child, name)?;
  283. Ok(child)
  284. }
  285. /// Look up a directory entry by name.
  286. ///
  287. /// # Params
  288. ///
  289. /// * `parent` - the inode of the directory to look in
  290. /// * `name` - the name of the entry to look for
  291. ///
  292. /// # Return
  293. ///
  294. /// `Ok(child)`: The inode id to which the directory entry points.
  295. ///
  296. /// # Error
  297. ///
  298. /// * `ENOTDIR` - `parent` is not a directory
  299. /// * `ENOENT` - `name` does not exist in `parent`
  300. pub fn lookup(&mut self, parent: InodeId, name: &str) -> Result<InodeId> {
  301. let parent = self.read_inode(parent);
  302. // Can only lookup in a directory
  303. if !parent.inode.is_dir() {
  304. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  305. }
  306. self.dir_find_entry(&parent, name)
  307. .map(|entry| entry.inode())
  308. }
  309. /// List all directory entries in a directory.
  310. ///
  311. /// # Params
  312. ///
  313. /// * `inode` - the inode of the directory to list
  314. ///
  315. /// # Return
  316. ///
  317. /// `Ok(entries)` - A vector of directory entries in the directory.
  318. ///
  319. /// # Error
  320. ///
  321. /// `ENOTDIR` - `inode` is not a directory
  322. pub fn list(&self, inode: InodeId) -> Result<Vec<DirEntry>> {
  323. let inode_ref = self.read_inode(inode);
  324. // Can only list a directory
  325. if inode_ref.inode.file_type() != FileType::Directory {
  326. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", inode);
  327. }
  328. Ok(self.dir_get_all_entries(&inode_ref))
  329. }
  330. /// Remove an empty directory.
  331. ///
  332. /// # Params
  333. ///
  334. /// * `parent` - the parent directory where the directory is located
  335. /// * `name` - the name of the directory to remove
  336. ///
  337. /// # Error
  338. ///
  339. /// * `ENOTDIR` - `parent` or `child` is not a directory
  340. /// * `ENOENT` - `name` does not exist in `parent`
  341. /// * `ENOTEMPTY` - `child` is not empty
  342. pub fn rmdir(&mut self, parent: InodeId, name: &str) -> Result<()> {
  343. let mut parent = self.read_inode(parent);
  344. // Can only remove a directory in a directory
  345. if !parent.inode.is_dir() {
  346. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  347. }
  348. let mut child = self.read_inode(self.dir_find_entry(&parent, name)?.inode());
  349. // Child must be a directory
  350. if !child.inode.is_dir() {
  351. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", child.id);
  352. }
  353. // Child must be empty
  354. if self.dir_get_all_entries(&child).len() > 2 {
  355. return_error!(ErrCode::ENOTEMPTY, "Directory {} is not empty", child.id);
  356. }
  357. // Remove directory entry
  358. self.unlink_inode(&mut parent, &mut child, name)
  359. }
  360. }