|
@@ -21,27 +21,7 @@ impl Ext4 {
|
|
|
if let Ok(r) = res {
|
|
|
return Ok(r);
|
|
|
}
|
|
|
- iblock += 1
|
|
|
- }
|
|
|
- Err(Ext4Error::new(ErrCode::ENOENT))
|
|
|
- }
|
|
|
-
|
|
|
- /// Find a directory entry that matches a given name in a given block
|
|
|
- fn find_entry_in_block(block: &Block, name: &str) -> Result<DirEntry> {
|
|
|
- info!("Dir find entry {} in block {}", name, block.block_id);
|
|
|
- let mut offset = 0;
|
|
|
- while offset < BLOCK_SIZE {
|
|
|
- let de = DirEntry::from_bytes(&block.data[offset..]);
|
|
|
- debug!("Dir entry: {} {:?}", de.rec_len(), de.name());
|
|
|
- offset += de.rec_len() as usize;
|
|
|
- // Unused dir entry
|
|
|
- if de.unused() {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // Compare name
|
|
|
- if de.compare_name(name) {
|
|
|
- return Ok(de);
|
|
|
- }
|
|
|
+ iblock += 1;
|
|
|
}
|
|
|
Err(Ext4Error::new(ErrCode::ENOENT))
|
|
|
}
|
|
@@ -63,8 +43,8 @@ impl Ext4 {
|
|
|
// Try finding a block with enough space
|
|
|
let mut iblock: LBlockId = 0;
|
|
|
while iblock < total_blocks {
|
|
|
- // Get the parent physical block id, create if not exist
|
|
|
- let fblock = self.extent_get_pblock_create(parent, iblock, 1)?;
|
|
|
+ // Get the parent physical block id
|
|
|
+ let fblock = self.extent_get_pblock(parent, iblock)?;
|
|
|
// Load the parent block from disk
|
|
|
let mut block = self.block_device.read_block(fblock);
|
|
|
// Try inserting the entry to parent block
|
|
@@ -86,6 +66,62 @@ impl Ext4 {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
+ /// Remove a entry from a directory
|
|
|
+ pub(super) fn dir_remove_entry(&mut self, parent: &mut InodeRef, path: &str) -> Result<()> {
|
|
|
+ info!("Dir remove entry: parent {}, path {}", parent.id, path);
|
|
|
+ let inode_size = parent.inode.size();
|
|
|
+ let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
|
|
|
+
|
|
|
+ // Check each block
|
|
|
+ let mut iblock: LBlockId = 0;
|
|
|
+ while iblock < total_blocks {
|
|
|
+ // Get the parent physical block id
|
|
|
+ let fblock = self.extent_get_pblock(parent, iblock)?;
|
|
|
+ // Load the block from disk
|
|
|
+ let mut block = self.block_device.read_block(fblock);
|
|
|
+ // Try removing the entry
|
|
|
+ if self.remove_entry_from_block(&mut block, path) {
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+ // Current block has no enough space
|
|
|
+ iblock += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Not found the target entry
|
|
|
+ Err(Ext4Error::new(ErrCode::ENOENT))
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Find a directory entry that matches a given name in a given block
|
|
|
+ fn find_entry_in_block(block: &Block, name: &str) -> Result<DirEntry> {
|
|
|
+ info!("Dir find entry {} in block {}", name, block.block_id);
|
|
|
+ let mut offset = 0;
|
|
|
+ while offset < BLOCK_SIZE {
|
|
|
+ let de: DirEntry = block.read_offset_as(offset);
|
|
|
+ debug!("Dir entry: {} {:?}", de.rec_len(), de.name());
|
|
|
+ offset += de.rec_len() as usize;
|
|
|
+ if !de.unused() && de.compare_name(name) {
|
|
|
+ return Ok(de);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Err(Ext4Error::new(ErrCode::ENOENT))
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Remove a directory entry that matches a given name from a given block
|
|
|
+ fn remove_entry_from_block(&self, block: &mut Block, name: &str) -> bool {
|
|
|
+ info!("Dir remove entry {} from block {}", name, block.block_id);
|
|
|
+ let mut offset = 0;
|
|
|
+ while offset < BLOCK_SIZE {
|
|
|
+ let mut de: DirEntry = block.read_offset_as(offset);
|
|
|
+ offset += de.rec_len() as usize;
|
|
|
+ if !de.unused() && de.compare_name(name) {
|
|
|
+ // Mark the target entry as unused
|
|
|
+ de.set_unused();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ false
|
|
|
+ }
|
|
|
+
|
|
|
/// Insert a directory entry of a child inode into a new parent block.
|
|
|
/// A new block must have enough space
|
|
|
fn insert_entry_to_new_block(&self, dst_blk: &mut Block, child: &InodeRef, name: &str) {
|
|
@@ -98,7 +134,7 @@ impl Ext4 {
|
|
|
inode_mode2file_type(child.inode.mode()),
|
|
|
);
|
|
|
// Write entry to block
|
|
|
- new_entry.copy_to_byte_slice(&mut dst_blk.data, 0);
|
|
|
+ dst_blk.write_offset_as(0, &new_entry);
|
|
|
|
|
|
// Set tail
|
|
|
let mut tail = DirEntryTail::default();
|
|
@@ -120,7 +156,7 @@ impl Ext4 {
|
|
|
let mut offset = 0;
|
|
|
|
|
|
while offset < dst_blk.data.len() {
|
|
|
- let mut de = DirEntry::from_bytes(&dst_blk.data[offset..]);
|
|
|
+ let mut de: DirEntry = dst_blk.read_offset_as(offset);
|
|
|
let rec_len = de.rec_len() as usize;
|
|
|
|
|
|
// Try splitting dir entry
|
|
@@ -128,7 +164,7 @@ impl Ext4 {
|
|
|
let used_size = de.used_size();
|
|
|
// The rest size
|
|
|
let free_size = rec_len - used_size;
|
|
|
-
|
|
|
+
|
|
|
// Compare size
|
|
|
if free_size < required_size {
|
|
|
// No enough space, try next dir ent
|
|
@@ -138,7 +174,7 @@ impl Ext4 {
|
|
|
// Has enough space
|
|
|
// Update the old entry
|
|
|
de.set_rec_len(used_size as u16);
|
|
|
- de.copy_to_byte_slice(&mut dst_blk.data, offset);
|
|
|
+ dst_blk.write_offset_as(offset, &de);
|
|
|
// Insert the new entry
|
|
|
let new_entry = DirEntry::new(
|
|
|
child.id,
|
|
@@ -146,7 +182,7 @@ impl Ext4 {
|
|
|
name,
|
|
|
inode_mode2file_type(child.inode.mode()),
|
|
|
);
|
|
|
- new_entry.copy_to_byte_slice(&mut dst_blk.data, offset + used_size);
|
|
|
+ dst_blk.write_offset_as(offset + used_size, &new_entry);
|
|
|
|
|
|
// Set tail csum
|
|
|
let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
|