611 lines
No EOL
24 KiB
Rust
611 lines
No EOL
24 KiB
Rust
use vapfs::{Index, Timestamp};
|
|
use crate::crc32;
|
|
|
|
/// # Magic
|
|
/// Constant value that identifies the Superblock as a valid VapUFS filesystem
|
|
pub const MAGIC: u64 = 0x766170554653;
|
|
|
|
/// # Superblock
|
|
/// The primary struct of a VapUFS filesystem, contains metadata about the filesystem.
|
|
/// Located at block 1 of the block device.
|
|
/// All values are big-endian unless otherwise specified.
|
|
/// Directly after (i.e. the next block after) the Superblock are the free data blocks bitmap and the free inodes bitmap.
|
|
/// Free data blocks bitmap is data_block_count / 8 bytes long (rounded up).
|
|
/// Free inodes bitmap is inode_count / 8 bytes long (rounded up).
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct Superblock {
|
|
/// magic number that identifies the Superblock as a valid VapUFS filesystem
|
|
pub magic: u64,
|
|
/// size of each block in bytes, must be *at least* 2048 bytes
|
|
pub block_size: u32,
|
|
/// location of first data block in blocks
|
|
pub first_data_block: Index,
|
|
/// location of first inode block in blocks
|
|
pub first_inode_block: Index,
|
|
/// location of first journal block in blocks
|
|
pub first_journal_block: Index,
|
|
/// total count of inodes, including unused inodes
|
|
pub inode_count: Index,
|
|
/// total count of data blocks, including unused blocks
|
|
pub data_block_count: Index,
|
|
/// total count of blocks dedicated to journal
|
|
pub journal_block_count: Index,
|
|
/// timestamp of creation
|
|
pub creation_time: Timestamp,
|
|
/// timestamp of last modification
|
|
pub last_modification_time: Timestamp,
|
|
/// crc32 checksum of this Superblock
|
|
pub checksum: u32,
|
|
/// index of the current journal entry being processed
|
|
/// incremented after a journal entry is committed, set to 0 if past max
|
|
pub journal_position: u32,
|
|
/// reserved values for expansion
|
|
pub reserved: [u64; 7],
|
|
// 156 bytes used so far
|
|
// next block is used by the free data blocks bitmap and the free inodes bitmap
|
|
}
|
|
|
|
impl Superblock {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.magic = u64::from_be(self.magic);
|
|
self.block_size = u32::from_be(self.block_size);
|
|
self.first_data_block = u64::from_be(self.first_data_block);
|
|
self.first_inode_block = u64::from_be(self.first_inode_block);
|
|
self.first_journal_block = u64::from_be(self.first_journal_block);
|
|
self.inode_count = u64::from_be(self.inode_count);
|
|
self.data_block_count = u64::from_be(self.data_block_count);
|
|
self.journal_block_count = u64::from_be(self.journal_block_count);
|
|
self.creation_time = u64::from_be(self.creation_time);
|
|
self.last_modification_time = u64::from_be(self.last_modification_time);
|
|
for i in 0..8 {
|
|
self.reserved[i] = u64::from_be(self.reserved[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.magic = u64::to_be(self.magic);
|
|
self.block_size = u32::to_be(self.block_size);
|
|
self.first_data_block = u64::to_be(self.first_data_block);
|
|
self.first_inode_block = u64::to_be(self.first_inode_block);
|
|
self.first_journal_block = u64::to_be(self.first_journal_block);
|
|
self.inode_count = u64::to_be(self.inode_count);
|
|
self.data_block_count = u64::to_be(self.data_block_count);
|
|
self.journal_block_count = u64::to_be(self.journal_block_count);
|
|
self.creation_time = u64::to_be(self.creation_time);
|
|
self.last_modification_time = u64::to_be(self.last_modification_time);
|
|
for i in 0..8 {
|
|
self.reserved[i] = u64::to_be(self.reserved[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// returns true if the crc32 checksum is currently valid
|
|
/// returns false otherwise
|
|
pub fn is_checksum_valid(&self) -> bool {
|
|
let mut buf = [0; core::mem::size_of::<Self>() - (8 * 8)]; // don't hash last 7 u64s, the reserved u32, or the checksum
|
|
unsafe {
|
|
core::ptr::copy(self as *const Self as *const u8, buf.as_mut_ptr(), buf.len());
|
|
}
|
|
let checksum = crc32::crc32(&buf);
|
|
|
|
checksum == self.checksum
|
|
}
|
|
|
|
/// updates the crc32 checksum
|
|
pub fn recalculate_checksum(&mut self) {
|
|
let mut buf = [0; core::mem::size_of::<Self>() - (8 * 8)]; // don't hash last 7 u64s, the reserved u32, or the checksum
|
|
unsafe {
|
|
core::ptr::copy(self as *const Self as *const u8, buf.as_mut_ptr(), buf.len());
|
|
}
|
|
let checksum = crc32::crc32(&buf);
|
|
|
|
self.checksum = checksum;
|
|
}
|
|
}
|
|
|
|
/// # UNIXPermissions
|
|
/// UNIX permissions
|
|
#[repr(u16)]
|
|
pub enum UNIXMode {
|
|
/// Read, Other
|
|
Read = 1 << 0,
|
|
/// Write, Other
|
|
Write = 1 << 1,
|
|
/// Execute, Other
|
|
Execute = 1 << 2,
|
|
/// Read, Group
|
|
ReadGroup = 1 << 3,
|
|
/// Write, Group
|
|
WriteGroup = 1 << 4,
|
|
/// Execute, Group
|
|
ExecuteGroup = 1 << 5,
|
|
/// Read, Owner
|
|
ReadOwner = 1 << 6,
|
|
/// Write, Owner
|
|
WriteOwner = 1 << 7,
|
|
/// Execute, Owner
|
|
ExecuteOwner = 1 << 8,
|
|
/// Sticky bit
|
|
Sticky = 1 << 9,
|
|
/// Set GID
|
|
SetGID = 1 << 10,
|
|
/// Set UID
|
|
SetUID = 1 << 11,
|
|
}
|
|
|
|
/// # Filetype
|
|
/// Represents a file's type in the last 4 bits of the mode field of an inode.
|
|
#[repr(u16)]
|
|
pub enum Filetype {
|
|
/// Named FIFO pipe
|
|
FIFO = 0b0001 << 12,
|
|
/// Character device
|
|
CharDevice = 0b0010 << 12,
|
|
/// Directory
|
|
Directory = 0b0011 << 12,
|
|
/// Block device
|
|
BlockDevice = 0b0100 << 12,
|
|
/// Regular file
|
|
RegularFile = 0b0101 << 12,
|
|
/// Symbolic link
|
|
SymbolicLink = 0b0110 << 12,
|
|
/// Socket
|
|
Socket = 0b0111 << 12,
|
|
}
|
|
|
|
/// # Inode
|
|
/// Usually represents a file or directory, used to store metadata and locations of data blocks.
|
|
#[repr(C)]
|
|
pub struct Inode {
|
|
/// UNIX permissions / mode and filetype
|
|
pub mode: u16,
|
|
/// Number of links to this inode
|
|
pub link_count: u16,
|
|
/// User ID of owner
|
|
pub uid: u32,
|
|
/// Group ID of owner
|
|
pub gid: u32,
|
|
/// Size in bytes
|
|
pub size: Index,
|
|
/// Size in blocks
|
|
pub block_count: Index,
|
|
/// Timestamp of creation
|
|
pub creation_time: Timestamp,
|
|
/// Timestamp of last access
|
|
pub last_access_time: Timestamp,
|
|
/// Timestamp of last modification
|
|
pub last_modification_time: Timestamp,
|
|
/// Timestamp of last Inode modification
|
|
pub last_inode_modification_time: Timestamp,
|
|
/// Timestamp of deletion
|
|
pub deletion_time: Timestamp,
|
|
/// Flags field, see `InodeFlags`
|
|
pub flags: u32,
|
|
/// listblock for storing data block addresses
|
|
pub listblock: ListBlock,
|
|
/// CRC32 checksum of this inode
|
|
pub checksum: u32,
|
|
}
|
|
|
|
impl Inode {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.mode = u16::from_be(self.mode);
|
|
self.link_count = u16::from_be(self.link_count);
|
|
self.uid = u32::from_be(self.uid);
|
|
self.gid = u32::from_be(self.gid);
|
|
self.size = u64::from_be(self.size);
|
|
self.block_count = u64::from_be(self.block_count);
|
|
self.creation_time = u64::from_be(self.creation_time);
|
|
self.last_access_time = u64::from_be(self.last_access_time);
|
|
self.last_modification_time = u64::from_be(self.last_modification_time);
|
|
self.last_inode_modification_time = u64::from_be(self.last_inode_modification_time);
|
|
self.deletion_time = u64::from_be(self.deletion_time);
|
|
self.flags = u32::from_be(self.flags);
|
|
self.listblock.convert_big_endian_to_native();
|
|
self.checksum = u32::from_be(self.checksum);
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.mode = u16::to_be(self.mode);
|
|
self.link_count = u16::to_be(self.link_count);
|
|
self.uid = u32::to_be(self.uid);
|
|
self.gid = u32::to_be(self.gid);
|
|
self.size = u64::to_be(self.size);
|
|
self.block_count = u64::to_be(self.block_count);
|
|
self.creation_time = u64::to_be(self.creation_time);
|
|
self.last_access_time = u64::to_be(self.last_access_time);
|
|
self.last_modification_time = u64::to_be(self.last_modification_time);
|
|
self.last_inode_modification_time = u64::to_be(self.last_inode_modification_time);
|
|
self.deletion_time = u64::to_be(self.deletion_time);
|
|
self.flags = u32::to_be(self.flags);
|
|
self.listblock.convert_native_to_big_endian();
|
|
self.checksum = u32::to_be(self.checksum);
|
|
}
|
|
}
|
|
|
|
/// returns true if the crc32 checksum is currently valid
|
|
/// returns false otherwise
|
|
pub fn is_checksum_valid(&self) -> bool {
|
|
let mut buf = [0; core::mem::size_of::<Self>() - 4]; // don't hash the checksum
|
|
unsafe {
|
|
core::ptr::copy(self as *const Self as *const u8, buf.as_mut_ptr(), buf.len());
|
|
}
|
|
let checksum = crc32::crc32(&buf);
|
|
|
|
checksum == self.checksum
|
|
}
|
|
|
|
/// updates the crc32 checksum
|
|
pub fn recalculate_checksum(&mut self) {
|
|
let mut buf = [0; core::mem::size_of::<Self>() - 4]; // don't hash the checksum
|
|
unsafe {
|
|
core::ptr::copy(self as *const Self as *const u8, buf.as_mut_ptr(), buf.len());
|
|
}
|
|
let checksum = crc32::crc32(&buf);
|
|
|
|
self.checksum = checksum;
|
|
}
|
|
}
|
|
|
|
/// # InodeFlags
|
|
/// Flags field of an inode
|
|
#[repr(u32)]
|
|
pub enum InodeFlags {
|
|
/// File is corrupted
|
|
CORRUPT = 1 << 0,
|
|
/// File uses Single Indirect Block
|
|
INDIRECT1 = 1 << 1,
|
|
/// File uses Double Indirect Block
|
|
INDIRECT2 = 1 << 2,
|
|
/// File uses Triple Indirect Block
|
|
INDIRECT3 = 1 << 3,
|
|
/// File uses Quadruple Indirect Block
|
|
INDIRECT4 = 1 << 4,
|
|
/// File uses Quintuple Indirect Block
|
|
INDIRECT5 = 1 << 5,
|
|
/// File uses Sextuple Indirect Block
|
|
INDIRECT6 = 1 << 6,
|
|
}
|
|
|
|
/// # JournalEntry
|
|
/// A Journal Entry
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct JournalEntry {
|
|
/// JournalOperation
|
|
pub operation: u32,
|
|
/// crc32 hash of the content with flags set to zero, used to verify journal was fully written without verifying the stage
|
|
pub zeroed_content_crc32: u32,
|
|
pub content: JournalEntryContents,
|
|
}
|
|
|
|
impl JournalEntry {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.operation = u32::from_be(self.operation);
|
|
self.zeroed_content_crc32 = u32::from_be(self.zeroed_content_crc32);
|
|
match self.operation {
|
|
0 => { // SingleBlockWrite
|
|
unsafe { self.content.block_write.convert_big_endian_to_native() };
|
|
}
|
|
1 => { // MultiblockWrite
|
|
unsafe { self.content.multiblock_write.convert_big_endian_to_native() };
|
|
}
|
|
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.operation = u32::to_be(self.operation);
|
|
self.zeroed_content_crc32 = u32::to_be(self.zeroed_content_crc32);
|
|
match self.operation {
|
|
0 => { // SingleBlockWrite
|
|
unsafe { self.content.block_write.convert_native_to_big_endian() };
|
|
}
|
|
1 => { // MultiblockWrite
|
|
unsafe { self.content.multiblock_write.convert_native_to_big_endian() };
|
|
}
|
|
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # JournalOperation
|
|
/// Type of operation performed by a Journal Entry
|
|
#[repr(u32)]
|
|
pub enum JournalOperation {
|
|
/// A single block write, described by a `JournalBlockWrite`
|
|
SingleBlockWrite = 0,
|
|
/// A multi-block write, described by a `JournalMultiblockWrite`
|
|
MultiblockWrite = 1,
|
|
/// A file creation, described by a `JournalFileCreate`
|
|
FileCreate = 2,
|
|
/// A file deletion, described by a `JournalFileDelete`
|
|
FileDelete = 3,
|
|
/// A file truncation, described by a `JournalFileTruncate`
|
|
FileTruncate = 4,
|
|
}
|
|
|
|
/// # JournalBlockWrite
|
|
/// writes are performed as follows:
|
|
/// 1. create and write the journal entry
|
|
/// 2. allocate a data block for the data to be written
|
|
/// 3. set the entry's allocated flag
|
|
/// 4. write the data to the allocated data block
|
|
/// 5. set the entry's stored flag
|
|
/// == the following steps will be performed upon a journal flush, i.e. when the driver has decided that it's time to finally "commit" the journal ==
|
|
/// 6. depending on the destination of the write, either:
|
|
/// - update inode metadata to point to the new data block
|
|
/// - copy the data from the old data block to the new data block
|
|
/// 7. set the entry's written flag
|
|
/// 8. deallocate the old data block
|
|
/// 9. set the entry's deallocated flag
|
|
/// == done! ==
|
|
/// ideally, with this schema the filesystem shall never become corrupt
|
|
/// all fields in the entry should be modified individually on the block device instead of rewriting the entire entry
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct JournalBlockWrite {
|
|
/// JBRFlags stating how far the write has progressed
|
|
pub flags: u32,
|
|
/// are we writing to an inode instead of a data block, or maybe even directly to the disk?
|
|
/// see JBRTargetType
|
|
pub target_type: u32,
|
|
/// target inode number
|
|
pub target_inode: Index,
|
|
/// target block number (if target is a data block, this will be the index in the inode's direct block array;
|
|
/// if greater than 32, see the following:
|
|
/// let N = maximum number of pointers in an indirect block
|
|
/// (beginning...count)
|
|
/// 32..N: single indirect block
|
|
/// 32+N..N^2: double indirect block
|
|
/// 32+N^2..N^3: triple indirect block
|
|
/// 32+N^3..N^4: quadruple indirect block
|
|
/// 32+N^4..N^5: quintuple indirect block
|
|
/// 32+N^5..N^6: sextuple indirect block
|
|
pub target_block: Index,
|
|
/// actual data block number, unused if target is an inode
|
|
pub real_target_block: Index,
|
|
/// block number of source data block
|
|
pub source_block: Index,
|
|
/// crc32 hash of the source data block
|
|
pub source_block_crc32: u32,
|
|
}
|
|
|
|
impl JournalBlockWrite {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.flags = u32::from_be(self.flags);
|
|
self.target_block = u64::from_be(self.target_block);
|
|
self.source_block = u64::from_be(self.source_block);
|
|
self.source_block_crc32 = u32::from_be(self.source_block_crc32);
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.flags = u32::to_be(self.flags);
|
|
self.target_block = u64::to_be(self.target_block);
|
|
self.source_block = u64::to_be(self.source_block);
|
|
self.source_block_crc32 = u32::to_be(self.source_block_crc32);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # JBRFlags
|
|
/// Flags field of a JournalBlockWrite
|
|
#[repr(u32)]
|
|
#[derive(Copy, Clone)]
|
|
pub enum JBRFlags {
|
|
/// source data block has been chosen but not yet allocated
|
|
Chosen = 1,
|
|
/// source data block has been allocated
|
|
Allocated = 2,
|
|
/// data has been written to the source data block
|
|
Stored = 3,
|
|
/// source data block has either replaced an old data block or has been written to an inode
|
|
Written = 4,
|
|
/// source data block (in the case of a write to an inode) or old data block (in the case of a write to a data block) has been deallocated
|
|
/// (i.e. this journal entry has been fully committed)
|
|
CompleteAndDeallocated = 0,
|
|
}
|
|
|
|
/// # JBRTargetType
|
|
/// Type of target of a JournalBlockWrite
|
|
#[repr(u32)]
|
|
#[derive(Copy, Clone)]
|
|
pub enum JBRTargetType {
|
|
/// target is a data block
|
|
DataBlock = 0,
|
|
/// target is an inode
|
|
Inode = 1,
|
|
/// target is the disk itself
|
|
Disk = 2,
|
|
}
|
|
|
|
/// # JournalMultiblockWrite
|
|
/// a special entry for writing to multiple blocks at once,
|
|
/// used for circumstances where it is very important that all blocks are either
|
|
/// written successfully, or not written at all (i.e. directory blocks).
|
|
/// all data stored in an inode must be written at once using this operation,
|
|
/// so it may not be suitable for large files.
|
|
/// writes are performed as follows:
|
|
/// 1. create and write the journal entry
|
|
/// 2. allocate a data block to store a MultiblockWriteList
|
|
/// 3. set the entry's allocated_list flag
|
|
/// 4. allocate data blocks to store the data to be written
|
|
/// 5. set the entry's allocated_data flag
|
|
/// 6. write the data to the allocated data blocks and the list to the allocated list block
|
|
/// 7. set the entry's stored flag
|
|
/// == the following steps will be performed upon a journal flush ==
|
|
/// 8. update inode metadata to point to the new data blocks
|
|
/// 9. set the entry's written flag
|
|
/// 10. deallocate the old data blocks & list block
|
|
/// 11. set the entry's deallocated flag
|
|
/// == done! ==
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct JournalMultiblockWrite {
|
|
/// JMWFlags stating how far the write has progressed
|
|
pub flags: u32,
|
|
/// inode number of target inode
|
|
pub target_inode: Index,
|
|
/// block number of first target block
|
|
pub target_block: Index,
|
|
/// number of target blocks
|
|
pub target_block_count: Index,
|
|
/// block number of list block structure
|
|
pub list_block: Index,
|
|
/// block number of old list block structure
|
|
pub old_list_block: Index,
|
|
/// crc32 hash of the list block
|
|
pub list_block_crc32: u32,
|
|
}
|
|
|
|
impl JournalMultiblockWrite {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.flags = u32::from_be(self.flags);
|
|
self.target_block = u64::from_be(self.target_block);
|
|
self.target_block_count = u64::from_be(self.target_block_count);
|
|
self.list_block = u64::from_be(self.list_block);
|
|
self.list_block_crc32 = u32::from_be(self.list_block_crc32);
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
self.flags = u32::to_be(self.flags);
|
|
self.target_block = u64::to_be(self.target_block);
|
|
self.target_block_count = u64::to_be(self.target_block_count);
|
|
self.list_block = u64::to_be(self.list_block);
|
|
self.list_block_crc32 = u32::to_be(self.list_block_crc32);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # JMWFlags
|
|
/// Flags field of a JournalMultiblockWrite
|
|
#[repr(u32)]
|
|
#[derive(Copy, Clone)]
|
|
pub enum JMWFlags {
|
|
/// list block has been chosen but not yet allocated
|
|
ChosenList = 1,
|
|
/// list block has been allocated
|
|
AllocatedList = 2,
|
|
/// data blocks have been chosen and stored in the list block but not yet allocated
|
|
ChosenData = 3,
|
|
/// data blocks have been allocated
|
|
AllocatedData = 4,
|
|
/// data has been written to the data blocks and the list block
|
|
Stored = 5,
|
|
/// data blocks have replaced old data blocks
|
|
Written = 6,
|
|
/// data blocks and list block have been deallocated
|
|
/// (i.e. this journal entry has been fully committed)
|
|
CompleteAndDeallocated = 0,
|
|
}
|
|
|
|
/// # ListBlock
|
|
/// a list of data blocks for a journaled multiblock write, similar in structure to an inode
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct ListBlock {
|
|
/// Count of blocks used
|
|
pub count: Index,
|
|
/// Direct-Block-Addresses
|
|
pub direct_block_addresses: [Index; 32],
|
|
/// Single Indirect-Block-Address
|
|
/// Indirect blocks are Indexes to other blocks, their contents are N u64 data pointers
|
|
pub single_indirect_block_address: [Index; 32],
|
|
/// Double Indirect-Block-Address
|
|
/// Double indirect blocks are Indexes to other blocks, their contents are N u64 indirect block pointers (they point to single indirect blocks)
|
|
pub double_indirect_block_address: [Index; 32],
|
|
/// Triple Indirect-Block-Address
|
|
/// Triple indirect blocks are Indexes to other blocks, their contents are N u64 double indirect block pointers (they point to double indirect blocks)
|
|
pub triple_indirect_block_address: [Index; 32],
|
|
/// Quadruple Indirect-Block-Address
|
|
/// Quadruple indirect blocks are Indexes to other blocks, their contents are N u64 triple indirect block pointers (they point to triple indirect blocks)
|
|
pub quadruple_indirect_block_address: [Index; 32],
|
|
/// Quintuple Indirect-Block-Address
|
|
/// Quintuple indirect blocks are Indexes to other blocks, their contents are N u64 quadruple indirect block pointers (they point to quadruple indirect blocks)
|
|
pub quintuple_indirect_block_address: [Index; 32],
|
|
/// Sextuple Indirect-Block-Address
|
|
/// Sextuple indirect blocks are Indexes to other blocks, their contents are N u64 quintuple indirect block pointers (they point to quintuple indirect blocks)
|
|
pub sextuple_indirect_block_address: [Index; 32],
|
|
}
|
|
|
|
impl ListBlock {
|
|
/// in-place conversion from the storage representation (big endian) to the native representation
|
|
pub fn convert_big_endian_to_native(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
for i in 0..32 {
|
|
self.direct_block_addresses[i] = u64::from_be(self.direct_block_addresses[i]);
|
|
self.single_indirect_block_address[i] = u64::from_be(self.single_indirect_block_address[i]);
|
|
self.double_indirect_block_address[i] = u64::from_be(self.double_indirect_block_address[i]);
|
|
self.triple_indirect_block_address[i] = u64::from_be(self.triple_indirect_block_address[i]);
|
|
self.quadruple_indirect_block_address[i] = u64::from_be(self.quadruple_indirect_block_address[i]);
|
|
self.quintuple_indirect_block_address[i] = u64::from_be(self.quintuple_indirect_block_address[i]);
|
|
self.sextuple_indirect_block_address[i] = u64::from_be(self.sextuple_indirect_block_address[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// in-place conversion from the native representation to the storage representation (big endian)
|
|
pub fn convert_native_to_big_endian(&mut self) {
|
|
#[cfg(target_endian = "little")]
|
|
{
|
|
for i in 0..32 {
|
|
self.direct_block_addresses[i] = u64::to_be(self.direct_block_addresses[i]);
|
|
self.single_indirect_block_address[i] = u64::to_be(self.single_indirect_block_address[i]);
|
|
self.double_indirect_block_address[i] = u64::to_be(self.double_indirect_block_address[i]);
|
|
self.triple_indirect_block_address[i] = u64::to_be(self.triple_indirect_block_address[i]);
|
|
self.quadruple_indirect_block_address[i] = u64::to_be(self.quadruple_indirect_block_address[i]);
|
|
self.quintuple_indirect_block_address[i] = u64::to_be(self.quintuple_indirect_block_address[i]);
|
|
self.sextuple_indirect_block_address[i] = u64::to_be(self.sextuple_indirect_block_address[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// # JournalEntryContents
|
|
/// union of all possible journal entries
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub union JournalEntryContents {
|
|
pub block_write: JournalBlockWrite,
|
|
pub multiblock_write: JournalMultiblockWrite,
|
|
} |