Skip to content

Commit

Permalink
ah reading directory through inode
Browse files Browse the repository at this point in the history
  • Loading branch information
BijanRegmi committed May 8, 2023
1 parent 082ba82 commit a202767
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 34 deletions.
138 changes: 112 additions & 26 deletions src/disk.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use std::io::{Read, Seek};
use std::mem::transmute;

use dbg_hex::dbg_hex;

use crate::ext4;
use crate::ext4::LoadAble;

pub struct Disk {
file: std::fs::File,
pub super_block: ext4::structs::SuperBlock,
pub block_size: u64,
pub groups_per_flex: u32,
pub block_size: u32,
pub groups_per_flex: u16,
}

impl Disk {
Expand All @@ -16,8 +19,10 @@ impl Disk {

let sb = ext4::structs::SuperBlock::from_file_offset(&mut f, 0x400)
.expect("Failed to read superblock");
let bs: u64 = (2 as u64).pow(10 + sb.s_log_block_size);
let gpf: u32 = (1 as u32) << sb.s_log_groups_per_flex;
let bs: u32 = (2 as u32).pow(10 + sb.s_log_block_size);
let gpf: u16 = (1 as u16) << sb.s_log_groups_per_flex;

dbg!(&sb.s_log_groups_per_flex, bs, gpf);

Disk {
file: f,
Expand All @@ -31,27 +36,51 @@ impl Disk {
pub fn read_block(&mut self, block_num: u64) -> std::io::Result<Vec<u8>> {
let mut buf = vec![0u8; self.block_size as usize];
self.file
.seek(std::io::SeekFrom::Start(block_num * self.block_size))?;
.seek(std::io::SeekFrom::Start(block_num * self.block_size as u64))?;
self.file.read_exact(&mut buf)?;
Ok(buf)
}

pub fn get_group_desc(&mut self, group_num: u32) -> ext4::structs::GroupDesc {
let primary_group_in_flex = group_num - (group_num % self.groups_per_flex);
let block_no = primary_group_in_flex * self.super_block.s_blocks_per_group
+ self.super_block.s_first_data_block
+ 1;
ext4::structs::GroupDesc::from_file_offset(
&mut self.file,
(block_no as u64) * (self.block_size as u64),
)
.expect("Cannot read group desc")
pub fn get_itable_blk_num(&mut self, group_num: u32) -> u64 {
let offset_in_flex = group_num as u32 % self.groups_per_flex as u32;
let has_redundant_copy = self.block_group_has_redundant_copy(group_num);
let blk_no: u64;
if has_redundant_copy {
let gd_blk_no = group_num as u64 * self.super_block.s_blocks_per_group as u64
+ 1 // skip superblock
+ self.super_block.s_first_data_block as u64;
let blk = self.read_block(gd_blk_no).unwrap();
let gd = ext4::structs::GroupDesc::from_buffer(&blk, 0);
blk_no = ((gd.bg_inode_table_hi as u64) << 32) | gd.bg_inode_table_lo as u64;
} else {
let is_primary_bg_in_flex = offset_in_flex == 0;
if is_primary_bg_in_flex {
blk_no = (1 + 1) * self.groups_per_flex as u64
+ self.super_block.s_first_data_block as u64;
} else {
let primary_flex_grp = group_num - offset_in_flex;
if self.block_group_has_redundant_copy(primary_flex_grp) {
let gd_blk_no = primary_flex_grp as u64 * self.super_block.s_blocks_per_group as u64
+ 1 // skip superblock
+ self.super_block.s_first_data_block as u64;
let blk = self.read_block(gd_blk_no).unwrap();
let gd = ext4::structs::GroupDesc::from_buffer(&blk, 0);
blk_no = ((gd.bg_inode_table_hi as u64) << 32) | gd.bg_inode_table_lo as u64;
} else {
blk_no = (1 + 1) * self.groups_per_flex as u64
+ self.super_block.s_first_data_block as u64;
}
}
}
group_num as u64 * self.super_block.s_blocks_per_group as u64
+ blk_no
+ offset_in_flex as u64 * self.super_block.s_inodes_per_group as u64
}

#[allow(dead_code)]
pub fn block_group_has_superblock(&self, bg_num: u32) -> bool {
pub fn block_group_has_redundant_copy(&self, bg_num: u32) -> bool {
if bg_num == 0 {
return true;
true
} else if self
.super_block
.s_feature_compat
Expand Down Expand Up @@ -80,18 +109,75 @@ impl Disk {
}
}

pub fn get_inode(&mut self, inode_num: u32) -> ext4::structs::Inode {
// Block group that an inode lives in
let bg = (inode_num - 1) / self.super_block.s_inodes_per_group;
// Get group desc of bg block number
let gdesc = self.get_group_desc(bg);
let offset_within_flex = bg % self.groups_per_flex;
let inode_table_address = (gdesc.bg_inode_table_hi as u64) << 32
| (gdesc.bg_inode_table_lo as u64) + offset_within_flex as u64;
fn get_inode(&mut self, inode_num: u32) -> ext4::structs::Inode {
let inode_group_num = (inode_num - 1) / self.super_block.s_inodes_per_group;
let inode_table_blk_num = self.get_itable_blk_num(inode_group_num);

let inode_index_in_table = (inode_num - 1) % self.super_block.s_inodes_per_group;
// This is not in blocks as s_inode_size is in bytes
let inode_offset_in_table = inode_index_in_table * self.super_block.s_inode_size as u32;
let inode_address = inode_table_address * self.block_size + inode_offset_in_table as u64;

let inode_address =
inode_table_blk_num * self.block_size as u64 + inode_offset_in_table as u64;

ext4::structs::Inode::from_file_offset(&mut self.file, inode_address)
.expect("Failed to get inode")
}

pub fn read_dir(&mut self, inode_num: u32) {
let inode = self.get_inode(inode_num);
dbg!(&inode);
if inode
.i_flags
.contains(ext4::flags::inode::IFlags::Ext4IndexFl)
{
unimplemented!("Hashed Tree Directory");
}

let extents = self.get_extents(&inode);
if extents.len() > 1 {
unimplemented!();
}

let e = &extents[0];
let blk_no: u64 = ((e.ee_start_hi as u64) << 32) | e.ee_start_lo as u64;
let block = self.read_block(blk_no).unwrap();

let mut offset = 0;
let mut entries = Vec::<ext4::structs::dir::Entry2>::new();

while offset < block.len() {
let de = ext4::structs::dir::Entry2::from_buffer(&block, offset);
if de.inode == 0 {
break;
}
offset = offset + de.rec_len as usize;
entries.push(de);
}

println!("Reading dir with inode_num {inode_num}");
for ele in entries {
let s = std::str::from_utf8(&ele.name[0..ele.name_len as usize]).unwrap();
println!("{:>10}: {}", ele.inode, s);
}
}

fn get_extents(&mut self, inode: &ext4::structs::Inode) -> Vec<ext4::structs::extent::Extent> {
let buf = inode.i_block.to_vec();
let eh = ext4::structs::extent::Header::from_buffer(&buf, 0);
assert_eq!(eh.eh_magic, 0xf30a);

let mut extents = Vec::<ext4::structs::extent::Extent>::new();
if eh.eh_depth == 0 {
for i in 0..eh.eh_entries as usize {
extents.push(ext4::structs::extent::Extent::from_buffer(
&buf,
(i + 1) * 12,
));
}
} else {
unimplemented!("Internal node encountered")
}
extents
}
}
4 changes: 2 additions & 2 deletions src/ext4/directories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct DirEntry {
pub name_len: u16,

/// File name.
pub name: [char; 255],
pub name: [u8; 255],
}
impl LoadAble for DirEntry {}

Expand Down Expand Up @@ -52,7 +52,7 @@ pub struct DirEntry2 {
pub file_type: FileType,

/// File name.
pub name: [char; 255],
pub name: [u8; 255],
}
impl LoadAble for DirEntry2 {}

Expand Down
2 changes: 1 addition & 1 deletion src/ext4/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub struct Inode {
pub l_i_version: u32,

/// Block map or extent tree. See the section “The Contents of inode.i_block”.
pub i_block: [u16; 15 * 2],
pub i_block: [u8; 60],

/// File version (for NFS).
pub i_generation: u32,
Expand Down
4 changes: 2 additions & 2 deletions src/ext4/loadable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ pub trait LoadAble: Sized {
Ok(result)
}

fn from_vec(buf: Vec<u8>) -> Self {
fn from_buffer(buf: &Vec<u8>, offset: usize) -> Self {
let size = size_of::<Self>();
let mut result = unsafe { std::mem::MaybeUninit::<Self>::uninit().assume_init() };
unsafe {
memcpy(
&mut result as *mut Self as *mut c_void,
buf.as_ptr() as *const c_void,
buf[offset..].as_ptr() as *const c_void,
size,
);
}
Expand Down
17 changes: 14 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
use dbg_hex::dbg_hex;

mod disk;
mod ext4;

use ext4::LoadAble;

fn main() -> std::io::Result<()> {
let _sda1 = "../iso/sda1.img";
let _nvme = "/dev/nvme0n1p3";
let mut d = disk::Disk::new(_sda1);
let _pen = "../iso/pen.img";

let mut d = disk::Disk::new(_nvme);

let inode = match std::env::args().nth(1) {
Some(x) => x.parse().unwrap(),
None => 2,
};

d.read_dir(inode);

let i2 = d.get_inode(2);
dbg!(i2);
Ok(())
}

0 comments on commit a202767

Please sign in to comment.