low_level.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  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::format_error;
  9. use crate::prelude::*;
  10. use crate::return_error;
  11. use core::cmp::min;
  12. impl Ext4 {
  13. /// Get file attributes.
  14. ///
  15. /// # Params
  16. ///
  17. /// * `id` - inode id
  18. ///
  19. /// # Return
  20. ///
  21. /// A file attribute struct.
  22. ///
  23. /// # Error
  24. ///
  25. /// `EINVAL` if the inode is invalid (link count == 0).
  26. pub fn getattr(&self, id: InodeId) -> Result<FileAttr> {
  27. let inode = self.read_inode(id);
  28. if inode.inode.link_count() == 0 {
  29. return_error!(ErrCode::EINVAL, "Invalid inode {}", id);
  30. }
  31. Ok(FileAttr {
  32. ino: id,
  33. size: inode.inode.size(),
  34. blocks: inode.inode.block_count(),
  35. atime: inode.inode.atime(),
  36. mtime: inode.inode.mtime(),
  37. ctime: inode.inode.ctime(),
  38. crtime: inode.inode.crtime(),
  39. ftype: inode.inode.file_type(),
  40. perm: inode.inode.perm(),
  41. links: inode.inode.link_count(),
  42. uid: inode.inode.uid(),
  43. gid: inode.inode.gid(),
  44. })
  45. }
  46. /// Set file attributes.
  47. ///
  48. /// # Params
  49. ///
  50. /// * `id` - inode id
  51. /// * `mode` - file mode
  52. /// * `uid` - 32-bit user id
  53. /// * `gid` - 32-bit group id
  54. /// * `size` - 64-bit file size
  55. /// * `atime` - 32-bit access time in seconds
  56. /// * `mtime` - 32-bit modify time in seconds
  57. /// * `ctime` - 32-bit change time in seconds
  58. /// * `crtime` - 32-bit create time in seconds
  59. ///
  60. /// # Error
  61. ///
  62. /// `EINVAL` if the inode is invalid (mode == 0).
  63. pub fn setattr(
  64. &self,
  65. id: InodeId,
  66. mode: Option<InodeMode>,
  67. uid: Option<u32>,
  68. gid: Option<u32>,
  69. size: Option<u64>,
  70. atime: Option<u32>,
  71. mtime: Option<u32>,
  72. ctime: Option<u32>,
  73. crtime: Option<u32>,
  74. ) -> Result<()> {
  75. let mut inode = self.read_inode(id);
  76. if inode.inode.mode().bits() == 0 {
  77. return_error!(ErrCode::EINVAL, "Invalid inode {}", id);
  78. }
  79. if let Some(mode) = mode {
  80. inode.inode.set_mode(mode);
  81. }
  82. if let Some(uid) = uid {
  83. inode.inode.set_uid(uid);
  84. }
  85. if let Some(gid) = gid {
  86. inode.inode.set_gid(gid);
  87. }
  88. if let Some(size) = size {
  89. // If size increases, allocate new blocks if needed.
  90. let required_blocks = (size as usize + INODE_BLOCK_SIZE - 1) / INODE_BLOCK_SIZE;
  91. for _ in inode.inode.block_count()..required_blocks as u64 {
  92. self.inode_append_block(&mut inode)?;
  93. }
  94. inode.inode.set_size(size);
  95. }
  96. if let Some(atime) = atime {
  97. inode.inode.set_atime(atime);
  98. }
  99. if let Some(mtime) = mtime {
  100. inode.inode.set_mtime(mtime);
  101. }
  102. if let Some(ctime) = ctime {
  103. inode.inode.set_ctime(ctime);
  104. }
  105. if let Some(crtime) = crtime {
  106. inode.inode.set_crtime(crtime);
  107. }
  108. self.write_inode_with_csum(&mut inode);
  109. Ok(())
  110. }
  111. /// Create a file. This function will not check the existence of
  112. /// the file, call `lookup` to check beforehand.
  113. ///
  114. /// # Params
  115. ///
  116. /// * `parent` - parent directory inode id
  117. /// * `name` - file name
  118. /// * `mode` - file type and mode with which to create the new file
  119. /// * `flags` - open flags
  120. ///
  121. /// # Return
  122. ///
  123. /// `Ok(inode)` - Inode id of the new file
  124. ///
  125. /// # Error
  126. ///
  127. /// * `ENOTDIR` - `parent` is not a directory
  128. /// * `ENOSPC` - No space left on device
  129. pub fn create(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
  130. let mut parent = self.read_inode(parent);
  131. // Can only create a file in a directory
  132. if !parent.inode.is_dir() {
  133. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  134. }
  135. // Create child inode and link it to parent directory
  136. let mut child = self.create_inode(mode)?;
  137. self.link_inode(&mut parent, &mut child, name)?;
  138. // Create file handler
  139. Ok(child.id)
  140. }
  141. /// Read data from a file. This function will read exactly `buf.len()`
  142. /// bytes unless the end of the file is reached.
  143. ///
  144. /// # Params
  145. ///
  146. /// * `file` - the file handler, acquired by `open` or `create`
  147. /// * `offset` - offset to read from
  148. /// * `buf` - the buffer to store the data
  149. ///
  150. /// # Return
  151. ///
  152. /// `Ok(usize)` - the actual number of bytes read
  153. ///
  154. /// # Error
  155. ///
  156. /// * `EISDIR` - `file` is not a regular file
  157. pub fn read(&self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
  158. // Get the inode of the file
  159. let mut file = self.read_inode(file);
  160. if !file.inode.is_file() {
  161. return_error!(ErrCode::EISDIR, "Inode {} is not a file", file.id);
  162. }
  163. // Read no bytes
  164. if buf.len() == 0 {
  165. return Ok(0);
  166. }
  167. // Calc the actual size to read
  168. let read_size = min(buf.len(), file.inode.size() as usize - offset);
  169. // Calc the start block of reading
  170. let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
  171. // Calc the length that is not aligned to the block size
  172. let misaligned = offset % BLOCK_SIZE;
  173. let mut cursor = 0;
  174. let mut iblock = start_iblock;
  175. // Read first block
  176. if misaligned > 0 {
  177. let read_len = min(BLOCK_SIZE - misaligned, read_size);
  178. let fblock = self.extent_query(&mut file, start_iblock).unwrap();
  179. let block = self.read_block(fblock);
  180. // Copy data from block to the user buffer
  181. buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(misaligned, read_len));
  182. cursor += read_len;
  183. iblock += 1;
  184. }
  185. // Continue with full block reads
  186. while cursor < read_size {
  187. let read_len = min(BLOCK_SIZE, read_size - cursor);
  188. let fblock = self.extent_query(&mut file, iblock).unwrap();
  189. let block = self.read_block(fblock);
  190. // Copy data from block to the user buffer
  191. buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(0, read_len));
  192. cursor += read_len;
  193. iblock += 1;
  194. }
  195. Ok(cursor)
  196. }
  197. /// Write data to a file. This function will write exactly `data.len()` bytes.
  198. ///
  199. /// # Params
  200. ///
  201. /// * `file` - the file handler, acquired by `open` or `create`
  202. /// * `offset` - offset to write to
  203. /// * `data` - the data to write
  204. ///
  205. /// # Return
  206. ///
  207. /// `Ok(usize)` - the actual number of bytes written
  208. ///
  209. /// # Error
  210. ///
  211. /// * `EISDIR` - `file` is not a regular file
  212. /// * `ENOSPC` - no space left on device
  213. pub fn write(&self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
  214. // Get the inode of the file
  215. let mut file = self.read_inode(file);
  216. if !file.inode.is_file() {
  217. return_error!(ErrCode::EISDIR, "Inode {} is not a file", file.id);
  218. }
  219. let write_size = data.len();
  220. // Calc the start and end block of writing
  221. let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
  222. let end_iblock = ((offset + write_size) / BLOCK_SIZE) as LBlockId;
  223. // Append enough block for writing
  224. let append_block_count = end_iblock as i64 + 1 - file.inode.fs_block_count() as i64;
  225. for _ in 0..append_block_count {
  226. self.inode_append_block(&mut file)?;
  227. }
  228. // Write data
  229. let mut cursor = 0;
  230. let mut iblock = start_iblock;
  231. while cursor < write_size {
  232. let write_len = min(BLOCK_SIZE, write_size - cursor);
  233. let fblock = self.extent_query(&mut file, iblock)?;
  234. let mut block = self.read_block(fblock);
  235. block.write_offset(
  236. (offset + cursor) % BLOCK_SIZE,
  237. &data[cursor..cursor + write_len],
  238. );
  239. self.write_block(&block);
  240. cursor += write_len;
  241. iblock += 1;
  242. }
  243. if offset + cursor > file.inode.size() as usize {
  244. file.inode.set_size((offset + cursor) as u64);
  245. }
  246. self.write_inode_with_csum(&mut file);
  247. Ok(cursor)
  248. }
  249. /// Create a hard link. This function will not check name conflict,
  250. /// call `lookup` to check beforehand.
  251. ///
  252. /// # Params
  253. ///
  254. /// * `child` - the inode of the file to link
  255. /// * `parent` - the inode of the directory to link to
  256. ///
  257. /// # Error
  258. ///
  259. /// * `ENOTDIR` - `parent` is not a directory
  260. /// * `ENOSPC` - no space left on device
  261. pub fn link(&self, child: InodeId, parent: InodeId, name: &str) -> Result<()> {
  262. let mut parent = self.read_inode(parent);
  263. // Can only link to a directory
  264. if !parent.inode.is_dir() {
  265. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  266. }
  267. let mut child = self.read_inode(child);
  268. // Cannot link a directory
  269. if child.inode.is_dir() {
  270. return_error!(ErrCode::EISDIR, "Cannot link a directory");
  271. }
  272. self.link_inode(&mut parent, &mut child, name)?;
  273. Ok(())
  274. }
  275. /// Unlink a file.
  276. ///
  277. /// # Params
  278. ///
  279. /// * `parent` - the inode of the directory to unlink from
  280. /// * `name` - the name of the file to unlink
  281. ///
  282. /// # Error
  283. ///
  284. /// * `ENOTDIR` - `parent` is not a directory
  285. /// * `ENOENT` - `name` does not exist in `parent`
  286. /// * `EISDIR` - `parent/name` is a directory
  287. pub fn unlink(&self, parent: InodeId, name: &str) -> Result<()> {
  288. let mut parent = self.read_inode(parent);
  289. // Can only unlink from a directory
  290. if !parent.inode.is_dir() {
  291. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  292. }
  293. // Cannot unlink directory
  294. let child_id = self.dir_find_entry(&parent, name)?;
  295. let mut child = self.read_inode(child_id);
  296. if child.inode.is_dir() {
  297. return_error!(ErrCode::EISDIR, "Cannot unlink a directory");
  298. }
  299. self.unlink_inode(&mut parent, &mut child, name, true)
  300. }
  301. /// Move a file.
  302. ///
  303. /// # Params
  304. ///
  305. /// * `parent` - the inode of the directory to move from
  306. /// * `name` - the name of the file to move
  307. /// * `new_parent` - the inode of the directory to move to
  308. /// * `new_name` - the new name of the file
  309. ///
  310. /// # Error
  311. ///
  312. /// * `ENOTDIR` - `parent` or `new_parent` is not a directory
  313. /// * `ENOENT` - `name` does not exist in `parent`
  314. /// * `EEXIST` - `new_parent/new_name` already exists
  315. /// * `ENOSPC` - no space left on device
  316. pub fn rename(
  317. &self,
  318. parent: InodeId,
  319. name: &str,
  320. new_parent: InodeId,
  321. new_name: &str,
  322. ) -> Result<()> {
  323. // Check parent
  324. let mut parent = self.read_inode(parent);
  325. if !parent.inode.is_dir() {
  326. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  327. }
  328. // Check new parent
  329. let mut new_parent = self.read_inode(new_parent);
  330. if !new_parent.inode.is_dir() {
  331. return_error!(
  332. ErrCode::ENOTDIR,
  333. "Inode {} is not a directory",
  334. new_parent.id
  335. );
  336. }
  337. // Check child existence
  338. let child_id = self.dir_find_entry(&parent, name)?;
  339. let mut child = self.read_inode(child_id);
  340. // Check name conflict
  341. if self.dir_find_entry(&new_parent, new_name).is_ok() {
  342. return_error!(ErrCode::EEXIST, "Dest name {} already exists", new_name);
  343. }
  344. // Move
  345. self.unlink_inode(&mut parent, &mut child, name, false)?;
  346. self.link_inode(&mut new_parent, &mut child, new_name)
  347. }
  348. /// Create a directory. This function will not check name conflict,
  349. /// call `lookup` to check beforehand.
  350. ///
  351. /// # Params
  352. ///
  353. /// * `parent` - the inode of the directory to create in
  354. /// * `name` - the name of the directory to create
  355. /// * `mode` - the mode of the directory to create, type field will be ignored
  356. ///
  357. /// # Return
  358. ///
  359. /// `Ok(child)` - the inode id of the created directory
  360. ///
  361. /// # Error
  362. ///
  363. /// * `ENOTDIR` - `parent` is not a directory
  364. /// * `ENOSPC` - no space left on device
  365. pub fn mkdir(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
  366. let mut parent = self.read_inode(parent);
  367. // Can only create a directory in a directory
  368. if !parent.inode.is_dir() {
  369. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  370. }
  371. // Create file/directory
  372. let mode = mode & InodeMode::PERM_MASK | InodeMode::DIRECTORY;
  373. let mut child = self.create_inode(mode)?;
  374. // Add "." entry
  375. let child_self = child.clone();
  376. self.dir_add_entry(&mut child, &child_self, ".")?;
  377. child.inode.set_link_count(1);
  378. // Link the new inode
  379. self.link_inode(&mut parent, &mut child, name)?;
  380. Ok(child.id)
  381. }
  382. /// Look up a directory entry by name.
  383. ///
  384. /// # Params
  385. ///
  386. /// * `parent` - the inode of the directory to look in
  387. /// * `name` - the name of the entry to look for
  388. ///
  389. /// # Return
  390. ///
  391. /// `Ok(child)`- the inode id to which the directory entry points.
  392. ///
  393. /// # Error
  394. ///
  395. /// * `ENOTDIR` - `parent` is not a directory
  396. /// * `ENOENT` - `name` does not exist in `parent`
  397. pub fn lookup(&self, parent: InodeId, name: &str) -> Result<InodeId> {
  398. let parent = self.read_inode(parent);
  399. // Can only lookup in a directory
  400. if !parent.inode.is_dir() {
  401. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  402. }
  403. self.dir_find_entry(&parent, name)
  404. }
  405. /// List all directory entries in a directory.
  406. ///
  407. /// # Params
  408. ///
  409. /// * `inode` - the inode of the directory to list
  410. ///
  411. /// # Return
  412. ///
  413. /// `Ok(entries)` - a vector of directory entries in the directory.
  414. ///
  415. /// # Error
  416. ///
  417. /// `ENOTDIR` - `inode` is not a directory
  418. pub fn listdir(&self, inode: InodeId) -> Result<Vec<DirEntry>> {
  419. let inode_ref = self.read_inode(inode);
  420. // Can only list a directory
  421. if inode_ref.inode.file_type() != FileType::Directory {
  422. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", inode);
  423. }
  424. Ok(self.dir_list_entries(&inode_ref))
  425. }
  426. /// Remove an empty directory.
  427. ///
  428. /// # Params
  429. ///
  430. /// * `parent` - the parent directory where the directory is located
  431. /// * `name` - the name of the directory to remove
  432. ///
  433. /// # Error
  434. ///
  435. /// * `ENOTDIR` - `parent` or `child` is not a directory
  436. /// * `ENOENT` - `name` does not exist in `parent`
  437. /// * `ENOTEMPTY` - `child` is not empty
  438. pub fn rmdir(&self, parent: InodeId, name: &str) -> Result<()> {
  439. let mut parent = self.read_inode(parent);
  440. // Can only remove a directory in a directory
  441. if !parent.inode.is_dir() {
  442. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
  443. }
  444. let mut child = self.read_inode(self.dir_find_entry(&parent, name)?);
  445. // Child must be a directory
  446. if !child.inode.is_dir() {
  447. return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", child.id);
  448. }
  449. // Child must be empty
  450. if self.dir_list_entries(&child).len() > 2 {
  451. return_error!(ErrCode::ENOTEMPTY, "Directory {} is not empty", child.id);
  452. }
  453. // Remove directory entry
  454. self.unlink_inode(&mut parent, &mut child, name, true)
  455. }
  456. /// Get extended attribute of a file.
  457. ///
  458. /// # Params
  459. ///
  460. /// * `inode` - the inode of the file
  461. /// * `name` - the name of the attribute
  462. ///
  463. /// # Return
  464. ///
  465. /// `Ok(value)` - the value of the attribute
  466. ///
  467. /// # Error
  468. ///
  469. /// `ENODATA` - the attribute does not exist
  470. pub fn getxattr(&self, inode: InodeId, name: &str) -> Result<Vec<u8>> {
  471. let inode_ref = self.read_inode(inode);
  472. let xattr_block_id = inode_ref.inode.xattr_block();
  473. if xattr_block_id == 0 {
  474. return_error!(ErrCode::ENODATA, "Xattr {} does not exist", name);
  475. }
  476. let xattr_block = XattrBlock::new(self.read_block(xattr_block_id));
  477. match xattr_block.get(name) {
  478. Some(value) => Ok(value.to_owned()),
  479. None => Err(format_error!(
  480. ErrCode::ENODATA,
  481. "Xattr {} does not exist",
  482. name
  483. )),
  484. }
  485. }
  486. /// Set extended attribute of a file. This function will not check name conflict,
  487. /// call `getxattr` to check beforehand.
  488. ///
  489. /// # Params
  490. ///
  491. /// * `inode` - the inode of the file
  492. /// * `name` - the name of the attribute
  493. /// * `value` - the value of the attribute
  494. ///
  495. /// # Error
  496. ///
  497. /// `ENOSPC` - xattr block does not have enough space
  498. pub fn setxattr(&self, inode: InodeId, name: &str, value: &[u8]) -> Result<()> {
  499. let mut inode_ref = self.read_inode(inode);
  500. let xattr_block_id = inode_ref.inode.xattr_block();
  501. if xattr_block_id == 0 {
  502. // lazy allocate xattr block
  503. let pblock = self.alloc_block(&mut inode_ref)?;
  504. inode_ref.inode.set_xattr_block(pblock);
  505. self.write_inode_with_csum(&mut inode_ref);
  506. }
  507. let mut xattr_block = XattrBlock::new(self.read_block(inode_ref.inode.xattr_block()));
  508. if xattr_block_id == 0 {
  509. xattr_block.init();
  510. }
  511. if xattr_block.insert(name, value) {
  512. self.write_block(&xattr_block.block());
  513. Ok(())
  514. } else {
  515. return_error!(
  516. ErrCode::ENOSPC,
  517. "Xattr block of Inode {} does not have enough space",
  518. inode
  519. );
  520. }
  521. }
  522. /// Remove extended attribute of a file.
  523. ///
  524. /// # Params
  525. ///
  526. /// * `inode` - the inode of the file
  527. /// * `name` - the name of the attribute
  528. ///
  529. /// # Error
  530. ///
  531. /// `ENODATA` - the attribute does not exist
  532. pub fn removexattr(&self, inode: InodeId, name: &str) -> Result<()> {
  533. let inode_ref = self.read_inode(inode);
  534. let xattr_block_id = inode_ref.inode.xattr_block();
  535. if xattr_block_id == 0 {
  536. return_error!(ErrCode::ENODATA, "Xattr {} does not exist", name);
  537. }
  538. let mut xattr_block = XattrBlock::new(self.read_block(xattr_block_id));
  539. if xattr_block.remove(name) {
  540. self.write_block(&xattr_block.block());
  541. Ok(())
  542. } else {
  543. return_error!(ErrCode::ENODATA, "Xattr {} does not exist", name);
  544. }
  545. }
  546. /// List extended attributes of a file.
  547. ///
  548. /// # Params
  549. ///
  550. /// * `inode` - the inode of the file
  551. ///
  552. /// # Returns
  553. ///
  554. /// A list of extended attributes of the file.
  555. pub fn listxattr(&self, inode: InodeId) -> Result<Vec<String>> {
  556. let inode_ref = self.read_inode(inode);
  557. let xattr_block_id = inode_ref.inode.xattr_block();
  558. if xattr_block_id == 0 {
  559. return Ok(Vec::new());
  560. }
  561. let xattr_block = XattrBlock::new(self.read_block(xattr_block_id));
  562. Ok(xattr_block.list())
  563. }
  564. /// Flush all dirty blocks in cache to disk.
  565. ///
  566. /// This always succeeds.
  567. pub fn flush_all(&self) {
  568. #[cfg(feature = "block_cache")]
  569. {
  570. self.block_cache.flush_all();
  571. }
  572. }
  573. }