potentially correct infinite indirect read
This commit is contained in:
parent
ca82cdb4d4
commit
2e5a154895
2 changed files with 76 additions and 0 deletions
74
src/lib.rs
74
src/lib.rs
|
@ -295,6 +295,80 @@ pub fn next_journal_position(sb: &Superblock, bd: &mut dyn BlockDevice) -> Optio
|
|||
}
|
||||
}
|
||||
|
||||
/// Reads an indirect datablock from a list of 3 indirect datablocks.
|
||||
pub fn read_indirect_datablock(sb: &Superblock, bd: &mut dyn BlockDevice, dbas: [Index; 12], address: Index) -> Vec<u8> {
|
||||
if address < 12 {
|
||||
return read_datablock(dbas[address as usize], sb, bd);
|
||||
} else {
|
||||
let mut n = address - 12;
|
||||
let mut blocks_left = n / (sb.block_size as u64 - 8);
|
||||
let mut indexes_left = n % (sb.block_size as u64 - 8);
|
||||
let mut current_block = dbas[9]; // first indirect block
|
||||
let mut visited = vec![];
|
||||
loop {
|
||||
if visited.contains(¤t_block) {
|
||||
return vec![]; // we've looped around
|
||||
}
|
||||
visited.push(current_block);
|
||||
let mut head = 0;
|
||||
let buf = read_datablock(current_block, sb, bd);
|
||||
let count = u64::from_be_bytes(buf[0..8].try_into().unwrap());
|
||||
head += 8;
|
||||
// if blocks_left == 0, we're in the right block (either that or we're in the right block to recurse downwards into)
|
||||
if blocks_left == 0 {
|
||||
for _ in 0..count.min(indexes_left) {
|
||||
let isdata_depth = &buf[head..head + 8];
|
||||
head += 8;
|
||||
let ptr_data = &buf[head..head + 8];
|
||||
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
|
||||
let is_data = isdata_depth[1] != 0;
|
||||
// if not data, we need to recurse
|
||||
if !is_data {
|
||||
current_block = ptr;
|
||||
break; // skip the rest of the loop
|
||||
} else {
|
||||
// if indexes_left == 0, we found the correct index
|
||||
if indexes_left == 0 {
|
||||
return read_datablock(ptr, sb, bd);
|
||||
} else {
|
||||
indexes_left -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _ in 0..count {
|
||||
let isdata_depth = &buf[head..head + 8];
|
||||
head += 8;
|
||||
let ptr_data = &buf[head..head + 8];
|
||||
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
|
||||
let is_data = isdata_depth[1] != 0;
|
||||
let mut depth = isdata_depth.to_vec();
|
||||
depth[0] = 0;
|
||||
let depth = u64::from_be_bytes(depth.try_into().unwrap());
|
||||
// if blocks_left is less than the depth, we are at the correct block
|
||||
if !is_data {
|
||||
if blocks_left < depth {
|
||||
// if not data, we need to recurse
|
||||
blocks_left = 0;
|
||||
current_block = ptr;
|
||||
break; // skip the rest of the loop
|
||||
} else {
|
||||
blocks_left -= depth;
|
||||
}
|
||||
} else {
|
||||
// if indexes_left == 0, we found the correct index
|
||||
if indexes_left == 0 {
|
||||
return read_datablock(ptr, sb, bd);
|
||||
} else {
|
||||
indexes_left -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a journal entry for a single block write operation.
|
||||
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
|
||||
/// Returns None if the journal is full, or if the block device cannot be written to.
|
||||
|
|
|
@ -221,6 +221,8 @@ pub struct Inode {
|
|||
/// // read block, if not data then check depth,
|
||||
/// // if depth implies that this indirect block could contain the nth data block, then recurse
|
||||
/// // otherwise, subtract the depth from n, and continue
|
||||
/// ====
|
||||
/// ideally, this should not take up too much storage space, while allowing for a large number of blocks to be addressed with minimal performance impact
|
||||
pub direct_block_addresses: [Index; 12],
|
||||
/// CRC32 checksum of this inode
|
||||
pub checksum: u32,
|
||||
|
|
Loading…
Add table
Reference in a new issue