diff options
author | tzlil <tzlils@protonmail.com> | 2023-02-17 13:25:23 +0200 |
---|---|---|
committer | tzlil <tzlils@protonmail.com> | 2023-02-17 13:25:23 +0200 |
commit | dd95456ec490d9119274f31e2f4fc4d1679477fc (patch) | |
tree | 77c85ed94970517f4ba0bf33bbed0c9e4a7785af |
initial commit
-rw-r--r-- | .envrc | 1 | ||||
-rw-r--r-- | .github/workflows/build_nix.yml | 13 | ||||
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | Cargo.lock | 130 | ||||
-rw-r--r-- | Cargo.toml | 12 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | default.nix | 7 | ||||
-rw-r--r-- | ext2.img | bin | 0 -> 33554432 bytes | |||
-rw-r--r-- | flake.lock | 82 | ||||
-rw-r--r-- | flake.nix | 64 | ||||
-rw-r--r-- | shell.nix | 7 | ||||
-rw-r--r-- | src/main.rs | 213 | ||||
-rw-r--r-- | src/structs.rs | 253 |
13 files changed, 792 insertions, 0 deletions
diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml new file mode 100644 index 0000000..2f684e1 --- /dev/null +++ b/.github/workflows/build_nix.yml @@ -0,0 +1,13 @@ +name: "Build legacy Nix package on Ubuntu" + +on: + push: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v12 + - name: Building package + run: nix-build . -A defaultPackage.x86_64-linux diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bb1a2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/target +.vscode/settings.json +.direnv + +# Added by cargo +# +# already existing elements were commented out + +#/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9a0d9fe --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,130 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byte-strings-proc_macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e78e8673d97234c7a07636474b02c92fad06a0f26f70581aa46aee124c508e5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "ext2" +version = "0.1.0" +dependencies = [ + "bitflags", + "null-terminated", + "uuid", + "zerocopy", +] + +[[package]] +name = "null-terminated" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3ab2c625aa6bd21571b3599f3c4318b4456ec89efc62c0b47c1a8de14e30bf" +dependencies = [ + "byte-strings-proc_macros", + "unreachable", + "utf", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8704f91734e57e97633bff5afe5c2893e5aca5bd83fac44736460deca2611a76" + +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "zerocopy" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6ac9b4c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ext2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +zerocopy = "0.6.1" +bitflags = "1.3.2" +uuid = "1.3.0" +null-terminated = "0.3.17" \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..ab18136 --- /dev/null +++ b/README @@ -0,0 +1 @@ +zerocopy ext2 parser diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..39bacff --- /dev/null +++ b/default.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).defaultNix diff --git a/ext2.img b/ext2.img new file mode 100644 index 0000000..bac35bb --- /dev/null +++ b/ext2.img Binary files differdiff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..9a2d857 --- /dev/null +++ b/flake.lock @@ -0,0 +1,82 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1676096558, + "narHash": "sha256-FRJWsgaJ45L/fPP8a7WJMiU/DxMaaKdRFCbbEPcYreg=", + "owner": "nix-community", + "repo": "fenix", + "rev": "180919967713768e37ad2def247bea41cef263b3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1659446231, + "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-21.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1676059854, + "narHash": "sha256-X3U/sewOuNVMi1k3Rt4E5cCL68TeCvFx+e/C0X39+U0=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "8011029d3a0f4014217e1ade75688c0f3c5305db", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..ff46275 --- /dev/null +++ b/flake.nix @@ -0,0 +1,64 @@ + +{ + # XXX: Change project description + description = "Rust project"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, fenix, flake-utils }: + flake-utils.lib.eachDefaultSystem + (system: + let + pkgs = nixpkgs.legacyPackages."${system}"; + + # XXX: Change target platform + rust-target = "x86_64-unknown-linux-gnu"; + rust-toolchain = with fenix.packages."${system}"; let + rust-toolchain-spec = { + # XXX: Change compiler version + # see `toolchainOf` https://github.com/nix-community/fenix + # for supported options + channel = "nightly"; + sha256 = "sha256-E4uFH1xyP6u3KhsYf3gnuqWyee61O9uoLLvBEIF1+ko="; + }; + # Toolchain for the builder + host-toolchain = toolchainOf rust-toolchain-spec; + # Toolchain for the platform where the binary will run + # target-toolchain = targets."${rust-target}".toolchainOf rust-toolchain-spec; + in + combine [ + # Build tools are taken from the host + host-toolchain.rustc + host-toolchain.cargo + host-toolchain.clippy + host-toolchain.rust-docs + # Standard library is taken from the target + host-toolchain.rust-std + host-toolchain.rust-src + ]; + in + { + devShells.default = pkgs.mkShell { + # XXX: Change to project name + name = "rust-project"; + + # Build tools + nativeBuildInputs = with pkgs; [ + rust-toolchain + rust-analyzer + rustfmt + ]; + + RUST_BACKTRACE = 1; + # CARGO_BUILD_TARGET = rust-target; + }; + devShell = self.devShells."${system}".default; + }); +} \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..77db547 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).shellNix diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e1f68ce --- /dev/null +++ b/src/main.rs @@ -0,0 +1,213 @@ +#![feature(int_roundings)] + +mod structs; +use crate::structs::{Superblock,BlockGroupDescriptor,Inode,DirectoryEntry}; +use zerocopy::{ByteSlice}; +use uuid::Uuid; + +#[repr(C)] +#[derive(Debug)] +pub struct Ext2 { + pub superblock: &'static Superblock, + pub block_groups: &'static [BlockGroupDescriptor], + pub blocks: Vec<&'static [u8]>, + pub block_size: usize, + pub uuid: Uuid, +} + + +const EXT2_MAGIC: u16 = 0xef53; +const EXT2_SUPERBLOCK_OFFSET: usize = 2048; +impl Ext2 { + pub fn new<B: ByteSlice + std::fmt::Debug>(bytes: B) -> Ext2 { + // https://wiki.osdev.org/Ext2#Superblock + // parse into Ext2 struct without copying much + + + let x = bytes.split_at(EXT2_SUPERBLOCK_OFFSET); + // let y = x.0.split_at(1024).1; + // let (prefix, superblock, suffix) = unsafe { bytes.align_to::<Superblock>() }; + // println!("{:?}", x.len()); + let superblock = unsafe { &*(x.0.split_at(1024).1.as_ptr() as *const Superblock) }; + assert_eq!(superblock.magic, EXT2_MAGIC); + // println!("{:?} {:?}", prefix, suffix); + + let block_group_count = superblock + .blocks_count + .div_ceil(superblock.blocks_per_group) as usize + - 3; + // assert!(block_igroup_count <= MAX_BLOCK_GROUPS); + // let y = x.1, + // let (prefix, block_groups, suffix) = unsafe { bytes.align_to::<BlockGroupDescriptor>() }; + // println!("{:?} {:?}", prefix, suffix); + let block_size: usize = 1024 << superblock.log_block_size; + let y = x.1.split_at(block_size); + + let block_groups = unsafe { + std::slice::from_raw_parts( + y.0.as_ptr() as *const BlockGroupDescriptor, + block_group_count, + ) + }; + + // i determined the root table to be at inode 5, but i need a better way of finding that + // let root_inode_group: usize = (5 - 1) / superblock.inodes_per_group as usize; + // let root_inode_index: usize = (5 - 1) % superblock.inodes_per_group as usize; + // let root_inode_block = (root_inode_index * superblock.inode_size as usize) as usize / block_size; + // println!("{:?}", root_inode_group); + // println!("{:?}", root_inode_index); + // println!("{:?}", root_inode_block); + + let blocks = unsafe { + std::slice::from_raw_parts( + y.1.as_ptr() as *const u8, + superblock.blocks_count as usize * block_size, + ) + } + .chunks(block_size) + .collect::<Vec<_>>(); + + // let blocks = unsafe { std::slice::from_raw_parts( + // y.1.as_ptr() as *const [u8;1024], + // superblock.blocks_count as usize) }; + + // let inodes_per_block = block_size / superblock.inode_size as usize; + // let inode_table_block_count: usize = superblock.inodes_per_group as usize / inodes_per_block; + + // let inode_table = unsafe { std::slice::from_raw_parts( + // blocks[(block_groups[root_inode_group].inode_table_block-1) as usize].as_ptr() as *const Inode, + // inode_table_block_count) }; + + // boot block + group descriptors block + inode table blocks + // let data_blocks = unsafe { std::slice::from_raw_parts( + // blocks[1 + 1 + inode_table_block_count].as_ptr() as *const Inode, + // inode_table_block_count) }; + + // let root_inode = &inode_table[root_inode_index]; + // let test_inode = &inode_table[6]; + + // println!("{:?}", unsafe { std::ffi::CStr::from_ptr(blocks[test_inode.direct_pointer[0] as usize-3].as_ptr() as *const i8) }); + + // for inode in &inode_table[0..10] { + // println!("{:?}", inode); + // } + // for data_block in root_inode.direct_pointer { + // if data_block == 0 { break } + // println!("{:?}", blocks[data_block as usize-3]); + // } + + // for ptr in root_inode.direct_pointer { + // println!("{:?}", blocks[ptr as usize - 1]); + // } + + // let block_goups = <[BlockGroupDescriptor]>::read_from_prefix(x.1).unwrap(); + // println!("{:?}", y.1.split_at(block_size * (block_groups[root_inode_group].inode_table_block-1) as usize).1.split_at(block_size).0); + + let uuid = Uuid::from_bytes(superblock.fs_id); + Ext2 { + superblock, + block_groups, + blocks, + block_size, + uuid, + } + } + + // pub fn read_dir_inode(&self, inode: usize) -> std::io::Result<Vec<(usize, &str)>> { + // for ptr in root.direct_pointer { + // println!("{:?}",ext2.blocks[ptr as usize - 4] ); + // } + // let directory = ext2.blocks[root.direct_pointer[0] as usize - 3].as_ptr() as *const DirectoryEntry; + // Ok(vec!["/"]) + // } + + // pub fn read_dir_inode(&self, inode: usize) { + // let dir = self.get_inode(inode); + + // } + + pub fn get_inode(&self, inode: usize) -> &Inode { + let group: usize = (inode - 1) / self.superblock.inodes_per_group as usize; + let index: usize = (inode - 1) % self.superblock.inodes_per_group as usize; + + let inode_table = unsafe { + std::slice::from_raw_parts( + self.blocks[(self.block_groups[group].inode_table_block - 1) as usize].as_ptr() + as *const Inode, + index + 1, + ) + }; + // dbg!(inode_table); + &inode_table[index] + } + + pub fn read_dir<'a>(&'a self, inode: &'a Inode) -> Directory<'_> { + Directory { inode, disk: self, offset: 0 } + } +} + +#[derive(Debug)] +pub struct Directory<'a> { + inode: &'a Inode, + disk: &'a Ext2, + offset: usize, +} + +impl<'a> Iterator for Directory<'a> { + type Item = &'a DirectoryEntry; + fn next(&mut self) -> Option<Self::Item> { + if self.offset > 0 && self.offset % self.disk.block_size == 0 { + return None; + } + if self.inode.direct_pointer[self.offset / self.disk.block_size] == 0 { + return None; + } + let dir = unsafe { + &*(self.disk.blocks + [self.inode.direct_pointer[self.offset / self.disk.block_size] as usize - 4] + .as_ptr() + .add(self.offset % self.disk.block_size) as *const DirectoryEntry) + }; + self.offset += dir.entry_size as usize; + + Some(dir) + } +} + +fn main() { + let disk = include_bytes!("../ext2.img"); + let ext2 = Ext2::new(&disk[..]); + println!("{:?}", ext2.uuid); + + // root inode always starts at 2 + let root = ext2.get_inode(5); + dbg!(root); + + let dir: Vec<_> = ext2.read_dir(root).collect(); + // dbg!(dir); + + dbg!(dir.clone()); + let file = ext2.get_inode(7); + + dbg!(file); + println!("{:?}", unsafe { + std::ffi::CStr::from_ptr( + ext2.blocks[file.direct_pointer[0] as usize - 3].as_ptr() as *const i8 + ) + }); + // dbg!(dir.next()); + // dbg!(dir.next()); + + // let file = ext2.get_inode(dir.next().unwrap().inode as usize - 8); + // dbg!(file); + + // for ptr in root.direct_pointer { + // println!("{:?}",ext2.blocks[ptr as usize - 4] ); + + // } + // std::vec::Vec::from_raw_parts(ext2.blocks[root.direct_pointer[0] as usize - 4].as_ptr() as *const DirectoryEntry, 5, 5) + // let directory = ext2.blocks[root.direct_pointer[0] as usize - 4].as_ptr() as *const DirectoryEntry; + // dbg!( unsafe { &*directory } ); + // println!("{:?}",ext2.blocks[root.direct_pointer[0] as usize - 3] ); + // println!("{:?}", unsafe { std::ffi::CStr::from_ptr(ext2.blocks[root.direct_pointer[0] as usize - 3].as_ptr()+ as *const i8) }); +} diff --git a/src/structs.rs b/src/structs.rs new file mode 100644 index 0000000..55f6623 --- /dev/null +++ b/src/structs.rs @@ -0,0 +1,253 @@ +use bitflags::bitflags; +use null_terminated::NulStr; +use zerocopy::FromBytes; + +#[repr(C)] +#[derive(Debug)] +// https://wiki.osdev.org/Ext2 +pub struct Superblock { + // taken from https://wiki.osdev.org/Ext2 + /// Total number of inodes in file system + pub inodes_count: u32, + /// Total number of blocks in file system + pub blocks_count: u32, + /// Number of blocks reserved for superuser (see offset 80) + pub r_blocks_count: u32, + /// Total number of unallocated blocks + pub free_blocks_count: u32, + /// Total number of unallocated inodes + pub free_inodes_count: u32, + /// Block number of the block containing the superblock + pub first_data_block: u32, + /// log2 (block size) - 10. (In other words, the number to shift 1,024 + /// to the left by to obtain the block size) + pub log_block_size: u32, + /// log2 (fragment size) - 10. (In other words, the number to shift + /// 1,024 to the left by to obtain the fragment size) + pub log_frag_size: i32, + /// Number of blocks in each block group + pub blocks_per_group: u32, + /// Number of fragments in each block group + pub frags_per_group: u32, + /// Number of inodes in each block group + pub inodes_per_group: u32, + /// Last mount time (in POSIX time) + pub mtime: u32, + /// Last written time (in POSIX time) + pub wtime: u32, + /// Number of times the volume has been mounted since its last + /// consistency check (fsck) + pub mnt_count: u16, + /// Number of mounts allowed before a consistency check (fsck) must be + /// done + pub max_mnt_count: i16, + /// Ext2 signature (0xef53), used to help confirm the presence of Ext2 + /// on a volume + pub magic: u16, + /// File system state (see `FS_CLEAN` and `FS_ERR`) + pub state: u16, + /// What to do when an error is detected (see `ERR_IGNORE`, `ERR_RONLY` and + /// `ERR_PANIC`) + pub errors: u16, + /// Minor portion of version (combine with Major portion below to + /// construct full version field) + pub rev_minor: u16, + /// POSIX time of last consistency check (fsck) + pub lastcheck: u32, + /// Interval (in POSIX time) between forced consistency checks (fsck) + pub checkinterval: u32, + /// Operating system ID from which the filesystem on this volume was + /// created + pub creator_os: u32, + /// Major portion of version (combine with Minor portion above to + /// construct full version field) + pub rev_major: u32, + /// User ID that can use reserved blocks + pub block_uid: u16, + /// Group ID that can use reserved blocks + pub block_gid: u16, + + /// First non-reserved inode in file system. + pub first_inode: u32, + /// SectorSize of each inode structure in bytes. + pub inode_size: u16, + /// Block group that this superblock is part of (if backup copy) + pub block_group: u16, + /// Optional features present (features that are not required to read + /// or write, but usually result in a performance increase) + pub features_opt: u32, + /// Required features present (features that are required to be + /// supported to read or write) + pub features_req: u32, + /// Features that if not supported, the volume must be mounted + /// read-only) + pub features_ronly: u32, + /// File system ID (what is output by blkid) + pub fs_id: [u8; 16], + /// Volume name (C-style string: characters terminated by a 0 byte) + pub volume_name: [u8; 16], + /// Path volume was last mounted to (C-style string: characters + /// terminated by a 0 byte) + pub last_mnt_path: [u8; 64], + /// Compression algorithms used (see Required features above) + pub compression: u32, + /// Number of blocks to preallocate for files + pub prealloc_blocks_files: u8, + /// Number of blocks to preallocate for directories + pub prealloc_blocks_dirs: u8, + #[doc(hidden)] + _unused: [u8; 2], + /// Journal ID (same style as the File system ID above) + pub journal_id: [u8; 16], + /// Journal inode + pub journal_inode: u32, + /// Journal device + pub journal_dev: u32, + /// Head of orphan inode list + pub journal_orphan_head: u32, +} + +#[repr(C)] +#[derive(Debug)] +pub struct BlockGroupDescriptor { + /// Block address of block usage bitmap + pub block_usage_addr: u32, + /// Block address of inode usage bitmap + pub inode_usage_addr: u32, + /// Starting block address of inode table + pub inode_table_block: u32, + /// Number of unallocated blocks in group + pub free_blocks_count: u16, + /// Number of unallocated inodes in group + pub free_inodes_count: u16, + /// Number of directories in group + pub dirs_count: u16, + + _reserved: [u8; 14], +} + +#[repr(C)] +#[derive(Debug)] +pub struct Inode { + /// Type and Permissions (see below) + pub type_perm: TypePerm, + /// User ID + pub uid: u16, + /// Lower 32 bits of size in bytes + pub size_low: u32, + /// Last Access Time (in POSIX time) + pub atime: u32, + /// Creation Time (in POSIX time) + pub ctime: u32, + /// Last Modification time (in POSIX time) + pub mtime: u32, + /// Deletion time (in POSIX time) + pub dtime: u32, + /// Group ID + pub gid: u16, + /// Count of hard links (directory entries) to this inode. When this + /// reaches 0, the data blocks are marked as unallocated. + pub hard_links: u16, + /// Count of disk sectors (not Ext2 blocks) in use by this inode, not + /// counting the actual inode structure nor directory entries linking + /// to the inode. + pub sectors_count: u32, + /// Flags + pub flags: u32, + /// Operating System Specific value #1 + pub _os_specific_1: [u8; 4], + /// Direct block pointers + pub direct_pointer: [u32; 12], + /// Singly Indirect Block Pointer (Points to a block that is a list of + /// block pointers to data) + pub indirect_pointer: u32, + /// Doubly Indirect Block Pointer (Points to a block that is a list of + /// block pointers to Singly Indirect Blocks) + pub doubly_indirect: u32, + /// Triply Indirect Block Pointer (Points to a block that is a list of + /// block pointers to Doubly Indirect Blocks) + pub triply_indirect: u32, + /// Generation number (Primarily used for NFS) + pub gen_number: u32, + /// In Ext2 version 0, this field is reserved. In version >= 1, + /// Extended attribute block (File ACL). + pub ext_attribute_block: u32, + /// In Ext2 version 0, this field is reserved. In version >= 1, Upper + /// 32 bits of file size (if feature bit set) if it's a file, + /// Directory ACL if it's a directory + pub size_high: u32, + /// Block address of fragment + pub frag_block_addr: u32, + /// Operating System Specific Value #2 + pub _os_specific_2: [u8; 12], +} + +#[repr(C)] +#[derive(Debug)] +pub struct DirectoryEntry { + /// Inode + pub inode: u32, + /// Total size of this entry (Including all subfields) + pub entry_size: u16, + /// Name Length least-significant 8 bits + pub name_length: u8, + /// Type indicator (only if the feature bit for "directory entries have file type byte" is set, else this is the most-significant 8 bits of the Name Length) + pub type_indicator: TypeIndicator, + + pub name: NulStr, +} + +#[derive(Debug)] +pub enum TypeIndicator { + Unknown, + Regular, + Directory, + Character, + Block, + Fifo, + Socket, + Symlink, +} + +bitflags! { + pub struct TypePerm: u16 { + /// FIFO + const FIFO = 0x1000; + /// Character device + const CHAR_DEVICE = 0x2000; + /// Directory + const DIRECTORY = 0x4000; + /// Block device + const BLOCK_DEVICE = 0x6000; + /// Regular file + const FILE = 0x8000; + /// Symbolic link + const SYMLINK = 0xA000; + /// Unix socket + const SOCKET = 0xC000; + /// Other—execute permission + const O_EXEC = 0x001; + /// Other—write permission + const O_WRITE = 0x002; + /// Other—read permission + const O_READ = 0x004; + /// Group—execute permission + const G_EXEC = 0x008; + /// Group—write permission + const G_WRITE = 0x010; + /// Group—read permission + const G_READ = 0x020; + /// User—execute permission + const U_EXEC = 0x040; + /// User—write permission + const U_WRITE = 0x080; + /// User—read permission + const U_READ = 0x100; + /// Sticky Bit + const STICKY = 0x200; + /// Set group ID + const SET_GID = 0x400; + /// Set user ID + const SET_UID = 0x800; + } +} |