use crate::inner::Block;
use super::TypePerm;
use bitflags::bitflags;
use libc::{gid_t, uid_t};
use std::mem::size_of;
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
#[repr(C)]
pub struct Inode {
pub type_and_perm: TypePerm,
pub user_id: u16,
pub low_size: u32,
pub last_access_time: u32,
pub creation_time: u32,
pub last_modification_time: u32,
pub deletion_time: u32,
pub group_id: u16,
pub nbr_hard_links: u16,
pub nbr_disk_sectors: u32,
pub flags: InodeFlags,
operating_system_specific_value_1: u32,
pub direct_block_pointers: [Block; 12],
pub singly_indirect_block_pointers: Block,
pub doubly_indirect_block_pointers: Block,
pub triply_indirect_block_pointers: Block,
generation_number: u32,
extended_attribute_block: u32,
pub upper_size: u32,
fragment_addr: Block,
operating_system_specific_value_2: u32,
}
impl Inode {
pub const FAST_SYMLINK_SIZE_MAX: usize = 60;
pub fn new(type_and_perm: TypePerm) -> Self {
Self {
creation_time: 0,
nbr_hard_links: 1,
type_and_perm,
..Default::default()
}
}
pub fn write_symlink(&mut self, target: &str) {
let target_len = target.len();
assert!(target_len <= Self::FAST_SYMLINK_SIZE_MAX);
unsafe {
let slice = std::slice::from_raw_parts_mut(
&mut self.direct_block_pointers as *mut _ as *mut u8,
target_len,
);
slice.copy_from_slice(target.as_bytes());
self.low_size = target_len as u32;
}
}
pub fn set_owner(&mut self, owner: uid_t) -> &mut Self {
self.user_id = owner as u16;
self
}
pub fn set_group(&mut self, group: gid_t) -> &mut Self {
self.group_id = group as u16;
self
}
pub fn is_a_directory(&self) -> bool {
self.type_and_perm.is_directory()
}
pub fn is_a_regular_file(&self) -> bool {
self.type_and_perm.is_regular()
}
pub fn get_size(&self) -> u64 {
if self.is_a_directory() {
self.low_size as u64
} else {
self.low_size as u64 + ((self.upper_size as u64) << 32)
}
}
pub fn update_size(&mut self, new_size: u64, block_size: u32) {
self.low_size = new_size as u32;
self.upper_size = (new_size >> 32) as u32;
let block_size = block_size as u64;
let multiplier = block_size / 512;
let block_off = if new_size == 0 {
0
} else {
(new_size - 1) / block_size as u64
};
let blocknumber_per_block = block_size as u64 / size_of::<Block>() as u64;
let block_data = if new_size == 0 {
0
} else {
let mut offset_start = 0;
let mut offset_end = 12;
let mut block_data = 0;
if block_off >= offset_start {
block_data = (block_off + 1) * multiplier;
}
offset_start = offset_end;
offset_end += blocknumber_per_block;
if block_off >= offset_start {
block_data += multiplier
}
offset_start = offset_end;
offset_end += blocknumber_per_block * blocknumber_per_block;
if block_off >= offset_start {
block_data += multiplier
+ ((block_off - offset_start) / blocknumber_per_block + 1) * multiplier
}
offset_start = offset_end;
if block_off >= offset_start {
block_data += multiplier
+ (((block_off - offset_start)
/ (blocknumber_per_block * blocknumber_per_block))
+ 1)
* multiplier
}
block_data
};
self.nbr_disk_sectors = block_data as u32;
}
}
bitflags! {
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct InodeFlags: u32 {
const SECURE_DELETION = 0x00000001;
const KEEP_A_COPY_OF_DATA_WHEN_DELETED = 0x00000002;
const FILE_COMPRESSION = 0x00000004;
const SYNCHRONOUS_UPDATES_NEW_DATA_IS_WRITTEN_IMMEDIATELY_TO_DISK = 0x00000008;
const IMMUTABLE_FILE = 0x00000010;
const APPEND_ONLY = 0x00000020;
const FILE_IS_NOT_INCLUDED_IN_DUMP_COMMAND = 0x00000040;
const LAST_ACCESSED_TIME_SHOULD_NOT_UPDATED = 0x00000080;
const HASH_INDEXED_DIRECTORY = 0x00010000;
const AFS_DIRECTORY = 0x00020000;
const JOURNAL_FILE_DATA = 0x00040000;
}
}