1 /** 2 * BSD 2-Clause License 3 * 4 * Copyright (c) 2021, Khaled Emara 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 use std::ffi::CString; 29 use std::io::{BufRead, Seek, SeekFrom}; 30 31 use super::attr::Attr; 32 use super::attr_bptree::AttrBtree; 33 use super::attr_leaf::AttrLeaf; 34 use super::attr_shortform::AttrShortform; 35 use super::bmbt_rec::BmbtRec; 36 use super::btree::{BmbtKey, BmdrBlock, Btree, XfsBmbtPtr}; 37 use super::definitions::*; 38 use super::dinode_core::{DinodeCore, XfsDinodeFmt}; 39 use super::dir3::Dir3; 40 use super::dir3_block::Dir2Block; 41 use super::dir3_bptree::Dir2Btree; 42 use super::dir3_leaf::Dir2Leaf; 43 use super::dir3_node::Dir2Node; 44 use super::dir3_sf::Dir2Sf; 45 use super::file::File; 46 use super::file_btree::FileBtree; 47 use super::file_extent_list::FileExtentList; 48 use super::sb::Sb; 49 use super::symlink_extent::SymlinkExtents; 50 51 use byteorder::BigEndian; 52 use byteorder::ReadBytesExt; 53 use libc::{mode_t, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG}; 54 55 pub const LITERAL_AREA_OFFSET: u8 = 0xb0; 56 57 #[derive(Debug)] 58 pub enum DiU { 59 DiDir2Sf(Dir2Sf), 60 DiBmx(Vec<BmbtRec>), 61 DiBmbt((BmdrBlock, Vec<BmbtKey>, Vec<XfsBmbtPtr>)), 62 DiSymlink(Vec<u8>), 63 } 64 65 #[derive(Debug)] 66 pub enum DiA { 67 DiAttrsf(AttrShortform), 68 DiAbmx(Vec<BmbtRec>), 69 DiAbmbt((BmdrBlock, Vec<BmbtKey>, Vec<XfsBmbtPtr>)), 70 } 71 72 #[derive(Debug)] 73 pub struct Dinode { 74 pub di_core: DinodeCore, 75 pub di_u: DiU, 76 pub di_a: Option<DiA>, 77 } 78 79 impl Dinode { from<R: BufRead + Seek>( buf_reader: &mut R, superblock: &Sb, inode_number: XfsIno, ) -> Dinode80 pub fn from<R: BufRead + Seek>( 81 buf_reader: &mut R, 82 superblock: &Sb, 83 inode_number: XfsIno, 84 ) -> Dinode { 85 let ag_no: XfsAgnumber = 86 (inode_number >> (superblock.sb_agblklog + superblock.sb_inopblog)) as u32; 87 if ag_no >= superblock.sb_agcount { 88 panic!("Wrong AG number!"); 89 } 90 91 let ag_blk: XfsAgblock = 92 ((inode_number >> superblock.sb_inopblog) & ((1 << superblock.sb_agblklog) - 1)) as u32; 93 let blk_ino = (inode_number & ((1 << superblock.sb_inopblog) - 1)) as u32; 94 95 let off = ag_no * superblock.sb_agblocks * superblock.sb_blocksize; 96 let off = off + ag_blk * superblock.sb_blocksize; 97 let off = off + blk_ino * (superblock.sb_inodesize as u32); 98 99 buf_reader.seek(SeekFrom::Start(off as u64)).unwrap(); 100 let di_core = DinodeCore::from(buf_reader); 101 102 let di_u: Option<DiU>; 103 match (di_core.di_mode as mode_t) & S_IFMT { 104 S_IFREG => match di_core.di_format { 105 XfsDinodeFmt::Extents => { 106 let mut bmx = Vec::<BmbtRec>::new(); 107 for _i in 0..di_core.di_nextents { 108 bmx.push(BmbtRec::from(buf_reader.by_ref())) 109 } 110 di_u = Some(DiU::DiBmx(bmx)); 111 } 112 XfsDinodeFmt::Btree => { 113 let bmbt = BmdrBlock::from(buf_reader.by_ref()); 114 115 let mut keys = Vec::<BmbtKey>::new(); 116 for _i in 0..bmbt.bb_numrecs { 117 keys.push(BmbtKey::from(buf_reader.by_ref())) 118 } 119 120 let mut pointers = Vec::<XfsBmbtPtr>::new(); 121 for _i in 0..bmbt.bb_numrecs { 122 let pointer = buf_reader.read_u64::<BigEndian>().unwrap(); 123 pointers.push(pointer) 124 } 125 126 di_u = Some(DiU::DiBmbt((bmbt, keys, pointers))); 127 } 128 _ => { 129 panic!("Directory format not yet supported."); 130 } 131 }, 132 S_IFDIR => match di_core.di_format { 133 XfsDinodeFmt::Local => { 134 let dir_sf = Dir2Sf::from(buf_reader.by_ref()); 135 di_u = Some(DiU::DiDir2Sf(dir_sf)); 136 } 137 XfsDinodeFmt::Extents => { 138 let mut bmx = Vec::<BmbtRec>::new(); 139 for _i in 0..di_core.di_nextents { 140 bmx.push(BmbtRec::from(buf_reader.by_ref())) 141 } 142 di_u = Some(DiU::DiBmx(bmx)); 143 } 144 XfsDinodeFmt::Btree => { 145 let bmbt = BmdrBlock::from(buf_reader.by_ref()); 146 147 let mut keys = Vec::<BmbtKey>::new(); 148 for _i in 0..bmbt.bb_numrecs { 149 keys.push(BmbtKey::from(buf_reader.by_ref())) 150 } 151 152 let mut pointers = Vec::<XfsBmbtPtr>::new(); 153 for _i in 0..bmbt.bb_numrecs { 154 let pointer = buf_reader.read_u64::<BigEndian>().unwrap(); 155 pointers.push(pointer) 156 } 157 158 di_u = Some(DiU::DiBmbt((bmbt, keys, pointers))); 159 } 160 _ => { 161 panic!("Directory format not yet supported."); 162 } 163 }, 164 S_IFLNK => match di_core.di_format { 165 XfsDinodeFmt::Local => { 166 let mut data = Vec::<u8>::with_capacity(di_core.di_size as usize); 167 for _i in 0..di_core.di_size { 168 let byte = buf_reader.read_u8().unwrap(); 169 data.push(byte) 170 } 171 di_u = Some(DiU::DiSymlink(data)) 172 } 173 XfsDinodeFmt::Extents => { 174 let mut bmx = Vec::<BmbtRec>::new(); 175 for _i in 0..di_core.di_nextents { 176 bmx.push(BmbtRec::from(buf_reader.by_ref())) 177 } 178 di_u = Some(DiU::DiBmx(bmx)); 179 } 180 _ => { 181 panic!("Unexpected format for symlink"); 182 } 183 }, 184 _ => panic!("Inode type not yet supported."), 185 } 186 187 buf_reader.seek(SeekFrom::Start(off as u64)).unwrap(); 188 buf_reader 189 .seek(SeekFrom::Current( 190 (LITERAL_AREA_OFFSET as i64) + ((di_core.di_forkoff as i64) * 8), 191 )) 192 .unwrap(); 193 194 let di_a: Option<DiA>; 195 if di_core.di_forkoff != 0 { 196 match di_core.di_aformat { 197 XfsDinodeFmt::Local => { 198 let attr_shortform = AttrShortform::from(buf_reader.by_ref()); 199 di_a = Some(DiA::DiAttrsf(attr_shortform)); 200 } 201 XfsDinodeFmt::Extents => { 202 let mut bmx = Vec::<BmbtRec>::new(); 203 for _i in 0..di_core.di_anextents { 204 bmx.push(BmbtRec::from(buf_reader.by_ref())) 205 } 206 di_a = Some(DiA::DiAbmx(bmx)); 207 } 208 XfsDinodeFmt::Btree => { 209 let bmbt = BmdrBlock::from(buf_reader.by_ref()); 210 211 let mut keys = Vec::<BmbtKey>::new(); 212 for _i in 0..bmbt.bb_numrecs { 213 keys.push(BmbtKey::from(buf_reader.by_ref())) 214 } 215 216 let mut pointers = Vec::<XfsBmbtPtr>::new(); 217 for _i in 0..bmbt.bb_numrecs { 218 let pointer = buf_reader.read_u64::<BigEndian>().unwrap(); 219 pointers.push(pointer) 220 } 221 222 di_a = Some(DiA::DiAbmbt((bmbt, keys, pointers))); 223 } 224 _ => { 225 panic!("Attributes format not yet supported."); 226 } 227 } 228 } else { 229 di_a = None; 230 } 231 232 Dinode { 233 di_core, 234 di_u: di_u.unwrap(), 235 di_a, 236 } 237 } 238 get_dir<R: BufRead + Seek>( &self, buf_reader: &mut R, superblock: &Sb, ) -> Box<dyn Dir3<R>>239 pub fn get_dir<R: BufRead + Seek>( 240 &self, 241 buf_reader: &mut R, 242 superblock: &Sb, 243 ) -> Box<dyn Dir3<R>> { 244 match &self.di_u { 245 DiU::DiDir2Sf(dir) => Box::new(dir.clone()), 246 DiU::DiBmx(bmx) => { 247 if bmx.len() == 1 { 248 Box::new(Dir2Block::from( 249 buf_reader.by_ref(), 250 superblock, 251 bmx[0].br_startblock, 252 )) 253 } else if bmx.len() > 4 { 254 Box::new(Dir2Node::from(bmx.clone(), superblock.sb_blocksize)) 255 } else { 256 Box::new(Dir2Leaf::from(buf_reader.by_ref(), superblock, bmx)) 257 } 258 } 259 DiU::DiBmbt((bmbt, keys, pointers)) => Box::new(Dir2Btree::from( 260 bmbt.clone(), 261 keys.clone(), 262 pointers.clone(), 263 superblock.sb_blocksize, 264 )), 265 _ => { 266 panic!("Unsupported dir format!"); 267 } 268 } 269 } 270 get_file<R: BufRead + Seek>( &self, _buf_reader: &mut R, superblock: &Sb, ) -> Box<dyn File<R>>271 pub fn get_file<R: BufRead + Seek>( 272 &self, 273 _buf_reader: &mut R, 274 superblock: &Sb, 275 ) -> Box<dyn File<R>> { 276 match &self.di_u { 277 DiU::DiBmx(bmx) => Box::new(FileExtentList { 278 bmx: bmx.clone(), 279 size: self.di_core.di_size, 280 block_size: superblock.sb_blocksize, 281 }), 282 DiU::DiBmbt((bmdr, keys, pointers)) => Box::new(FileBtree { 283 btree: Btree { 284 bmdr: bmdr.clone(), 285 keys: keys.clone(), 286 ptrs: pointers.clone(), 287 }, 288 size: self.di_core.di_size, 289 block_size: superblock.sb_blocksize, 290 }), 291 _ => { 292 panic!("Unsupported file format!"); 293 } 294 } 295 } 296 get_link_data<R: BufRead + Seek>(&self, buf_reader: &mut R, superblock: &Sb) -> CString297 pub fn get_link_data<R: BufRead + Seek>(&self, buf_reader: &mut R, superblock: &Sb) -> CString { 298 match &self.di_u { 299 DiU::DiSymlink(data) => CString::new(data.clone()).unwrap(), 300 DiU::DiBmx(bmx) => SymlinkExtents::get_target(buf_reader.by_ref(), bmx, superblock), 301 _ => { 302 panic!("Unsupported link format!"); 303 } 304 } 305 } 306 get_attrs<R: BufRead + Seek>( &self, buf_reader: &mut R, superblock: &Sb, ) -> Option<Box<dyn Attr<R>>>307 pub fn get_attrs<R: BufRead + Seek>( 308 &self, 309 buf_reader: &mut R, 310 superblock: &Sb, 311 ) -> Option<Box<dyn Attr<R>>> { 312 match &self.di_a { 313 Some(DiA::DiAttrsf(attr)) => Some(Box::new(attr.clone())), 314 Some(DiA::DiAbmx(bmx)) => { 315 if self.di_core.di_anextents > 0 { 316 buf_reader.seek(SeekFrom::Current(8)).unwrap(); 317 let magic = buf_reader.read_u16::<BigEndian>().unwrap(); 318 buf_reader.seek(SeekFrom::Current(-8)).unwrap(); 319 320 match magic { 321 XFS_ATTR3_LEAF_MAGIC => { 322 return Some(Box::new(AttrLeaf::from( 323 buf_reader.by_ref(), 324 superblock, 325 bmx.clone(), 326 ))); 327 } 328 XFS_DA3_NODE_MAGIC => { 329 return Some(Box::new(AttrLeaf::from( 330 buf_reader.by_ref(), 331 superblock, 332 bmx.clone(), 333 ))); 334 } 335 _ => panic!("Unknown magic number!"), 336 } 337 } else { 338 None 339 } 340 } 341 Some(DiA::DiAbmbt((bmdr, keys, pointers))) => Some(Box::new(AttrBtree { 342 btree: Btree { 343 bmdr: bmdr.clone(), 344 keys: keys.clone(), 345 ptrs: pointers.clone(), 346 }, 347 total_size: -1, 348 })), 349 None => None, 350 } 351 } 352 } 353