From dc8bce4eb9c926bd0d0bec4d59dd2e5838d27127 Mon Sep 17 00:00:00 2001 From: Oakchris1955 <80592203+Oakchris1955@users.noreply.github.com> Date: Thu, 1 Aug 2024 15:37:45 +0300 Subject: [PATCH] feat(fat12): FAT12 supportgit log! --- imgs/fat12.img | Bin 1048576 -> 1048576 bytes imgs/fat12.img.check | 2 +- src/fs.rs | 97 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/imgs/fat12.img b/imgs/fat12.img index ed8c69fcfe998075b0c0c3eb53264ce2ff3a76bb..399f5b6b77c9519d858676ff7a69ab8fdd37f09f 100644 GIT binary patch literal 1048576 zcmeFaU5unzn%|W@U}F-=vl5!mBnLVyq;ZZMW$hkGNg5JCcZ#LkVmL2zRsq~Z7f zKj(cTs=H@DB+FR4|Mj@5Dn8!#yub6D=lh)aKmM_Q^U2xMr@!?2_rJIIwO3x*``X{w z+xt_0>rd{T?ES)C|9`LiBY*85|A)W-!PCJ9r%&D<@P7|a&))bRfBrvj{LY{Mpa1;t z{J(#7@0I^{?>GLtz2Ex3fBSEK%mx1ISHAYw_I~5P`K`Ub`pVv4{|A?U;&1N##@^mv z|4x6w{N-;Cf#2GDW$%@*pL|VM`yc;-Km0X+@SpsxpZ#p_|NI%>{271Q`M;liedizf z>mN}9KNx=FlOKNL`H#NwPyYBD|MXA3@z1>S&Edf}N2lMM48M8#!*5Q1^v&xZfAi)i z-(0-%tzSR**6Q?Io8hs z{#SqW?SJjZ-~QKs^6h`)mGAsp2jBU(Prvi;48Qa5{_s2h{*S)%7k>Pmzxb2y{D-f6 z_eTfc{mZA{{q5m*|Dzv%_dov8cmLBLfA>H8$#?(rSAOxoJov@`>hu>Qb$>(!Esqrf zArJx~5CS3acM*a3|9=-v#^3Rw#Q*<0jyyLEfe;9R5D0+~2!a2f37lT+E%<-R|9^e& zU!e%l|DQ_&KYRG}sR};&zhBt9_>2F<@BZ5F{@UK&Z}aEhJ6_Wt|7(eAH5{q?<{9`Bv;!69S#`rhwe?H%pCvG=9a>izxjs8zxrR>_x0!B?+cvn-v3Y6{cGg)-;cPz#((x}XFK=*-}(M8?EOPr z;inUBx!Sv9$Y0<4#rjTBsJ}D5?hd?v%oEiUUi01I&hx!@%Ju(?pS1Dm`d{DsA71eg z^Pdn1fe;9R5D0+~2!Rj?fe;9R5D0+~2!Rj?fe;9R5D0+~2!Rj?fe`ou5jbweS=UGV z`mXA{Ro^|{eqg8mtM}{jKRu_6xuj&frvCYVZL7CS-d0igr>7rLI&Jma5B^fCZ|cwb z{^{=b|0#XHtD)AP52*X<|6G6Vzpwi9pWOS?x_(!ERsDJO<@z)A*X|CyzpcKizO2%9 zH$K;2|AW8W#`jnF^H1#kZ#BgHHv~c;1pY`8cr=;K7KejR7R%ZAVE>QgBj%xg4+2~B z-t}k6GOJIk`mI}hpm zQva9!{CoF);otk(-h(NfQ)>B=|M2I&Z2w<5=gO14!QPGDU+lfuoBE%+(}){Cc>C=q zPe1<6H|!t$sgK(A_2=0u4}Sc6Jb2y;fe;9R5D0+~2!Rj?fe;9R5D0+~2!TH)1Rf8D zH-p7|u)dlMmW#!DFrF?aqxE8WpKRbC6A{Q`hCm2}KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D z2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D z2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D z2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D z2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D z2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucg zgg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{ zKnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D2!ucggg^*{KnR3D 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 z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA az<>b*1`HT5V8DO@0|pEjFkrxdfi)0Lr40lC delta 2246 zcmeH|&ubGw6vy9ewbt}UYOUH|&{a?`CT>EswOUEA2@RE|Bnt+thtQ@Z7_;qW(YA*s zC>B8kTaR8v@MfEXHxaaVPvSvOHYj-T4^WKn%_Pol6h!pc4cVQ~yu2UtX7-y>DOf56 z?;mBbaqMkV`Dwr6+U)qw_+Y)yY}rl%ya{e6%gcSMgG_xEdf22W#jc5zl~xlsQuAsg zn@g*HuLc0!_Xh4}Uw-@e{Lysb%j@i|53hQkoJ>T~Qoq=E_$M=*WNFC?aZYkm1Mea> zxP2Oj0J~}8gmh>oRweHtz9hMYI3{^7u_@U_oC|L(9ATU1gG%|h@`9}ow|l4F;rgi$ z^rRpFUawleI>BLYEgx34$gNm-Uvr};n* zwsQTKT@YPzY@VZwVwWlzT#wiXHzY(|jwYJ8ZUZcA71}LW5&@mdtLVE^0-~)|+@CaeDN<5Sp_lN|*+Ct)V z(sN^>na*Cou`02(e_Ztg)<4)!wNr2Pq~36_Tkv4tW@j(!W~z`;qxm`GifbxmWkyZI zu)NlyXW~9SGVq3yP#I^!^h;0GsrDsdwwFUpp_-dRzjw^TYzh!D*=eE;>|8)-3-XA!` Be!&0$ diff --git a/imgs/fat12.img.check b/imgs/fat12.img.check index e1d1e88..59ea9c2 100644 --- a/imgs/fat12.img.check +++ b/imgs/fat12.img.check @@ -1 +1 @@ -07823c85e33da9b6461c4b972584cf3d4fdf7987d55dc6d490f0cadae1c775f5 *imgs/fat12.img \ No newline at end of file +ec293f4087abbd287e6024fc7918836de91ced075428f15688b9fb2462733990 *imgs/fat12.img \ No newline at end of file diff --git a/src/fs.rs b/src/fs.rs index da14ec4..fb72914 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -137,7 +137,6 @@ impl BootRecordFAT { } else { let total_clusters = self.total_clusters(); if total_clusters < 4085 { - todo!("FAT12 not yet implemented"); FATType::FAT12 } else if total_clusters < 65525 { FATType::FAT16 @@ -1194,20 +1193,49 @@ where fn read_nth_FAT_entry(&mut self, n: u32) -> Result { // the size of an entry rounded up to bytes let entry_size = self.fat_type.bits_per_entry().next_power_of_two() as u32 / 8; - let fat_offset: u32 = n * entry_size; + let fat_offset: u32 = n * self.fat_type.bits_per_entry() as u32 / 8; let fat_sector_offset = self.props.fat_offset + fat_offset / self.props.sector_size; let entry_offset: usize = (fat_offset % self.props.sector_size) as usize; self.read_nth_sector(fat_sector_offset.into())?; let mut value_bytes = [0_u8; 4]; - value_bytes[..(4_usize - entry_size as usize)] - .copy_from_slice(&self.sector_buffer[entry_offset..entry_offset + entry_size as usize]); // this shouldn't panic + let bytes_to_read: usize = cmp::min( + entry_offset + entry_size as usize, + self.sector_size() as usize, + ) - entry_offset; + value_bytes[..bytes_to_read] + .copy_from_slice(&self.sector_buffer[entry_offset..entry_offset + bytes_to_read]); // this shouldn't panic + + // in FAT12, FAT entries may be split between two different sectors + if self.fat_type == FATType::FAT12 && (bytes_to_read as u32) < entry_size { + self.read_nth_sector((fat_sector_offset + 1).into())?; + + value_bytes[bytes_to_read..entry_size as usize] + .copy_from_slice(&self.sector_buffer[..(entry_size as usize - bytes_to_read)]); + + /*todo!( + "read: {} {:?} n: {} offset: {}", + bytes_to_read, + value_bytes, + n, + fat_offset + );*/ + } let mut value = u32::from_le_bytes(value_bytes); - // ignore the high 4 bits if this is FAT32 - if self.fat_type == FATType::FAT32 { - value &= 0x0FFFFFFF + match self.fat_type { + // FAT12 entries are split between different bytes + FATType::FAT12 => { + if n & 1 != 0 { + value >>= 4 + } else { + value &= 0xFFF + } + } + // ignore the high 4 bits if this is FAT32 + FATType::FAT32 => value &= 0x0FFFFFFF, + _ => (), } /* @@ -1304,25 +1332,30 @@ mod tests { assert_eq!(file_string, EXPECTED_STR); } + static BEE_MOVIE_SCRIPT: &str = include_str!("../tests/bee movie script.txt"); + fn assert_file_is_bee_movie_script(file: &mut File) + where + S: Read + Write + Seek, + { + let mut file_bytes = [0_u8; 65536]; + let bytes_read = file.read(&mut file_bytes).unwrap(); + + let expected_filesize = BEE_MOVIE_SCRIPT.len(); + assert_eq!(bytes_read, expected_filesize); + + let utf8_string = str::from_utf8(&file_bytes[..bytes_read]).unwrap(); + assert_eq!(utf8_string, BEE_MOVIE_SCRIPT); + } + #[test] fn read_huge_file() { use std::io::Cursor; - static BEE_MOVIE_SCRIPT: &str = include_str!("../tests/bee movie script.txt"); - let mut storage = Cursor::new(FAT16.to_owned()); let mut fs = FileSystem::from_storage(&mut storage).unwrap(); let mut file = fs.get_file(PathBuf::from("/bee movie script.txt")).unwrap(); - let mut file_bytes = [0_u8; 65536]; - let bytes_read = file.read(&mut file_bytes).unwrap(); - - const EXPECTED_FILESIZE: usize = 49474; - assert_eq!(bytes_read, EXPECTED_FILESIZE); - - //panic!("{}", String::from_utf8_lossy(&file_bytes[..bytes_read])); - let utf8_string = str::from_utf8(&file_bytes[..bytes_read]).unwrap(); - assert_eq!(utf8_string, BEE_MOVIE_SCRIPT); + assert_file_is_bee_movie_script(&mut file); } #[test] @@ -1389,11 +1422,35 @@ mod tests { assert_eq!(date!(2024 - 07 - 11), file.entry.accessed); } + #[test] + fn read_file_fat12() { + use std::io::Cursor; + + let mut storage = Cursor::new(FAT12.to_owned()); + let mut fs = FileSystem::from_storage(&mut storage).unwrap(); + + let mut file = fs.get_file(PathBuf::from("/foo/bar.txt")).unwrap(); + let mut file_bytes = [0_u8; 1024]; + let bytes_read = file.read(&mut file_bytes).unwrap(); + + let file_string = String::from_utf8_lossy(&file_bytes[..bytes_read]).to_string(); + const EXPECTED_STR: &str = "Hello, World!\n"; + assert_eq!(file_string, EXPECTED_STR); + + // please not that the FAT12 image has been modified so that + // one FAT entry of the file we are reading is split between different sectors + // this way, we also test for this case + let mut file = fs + .get_file(PathBuf::from("/test/bee movie script.txt")) + .unwrap(); + assert_file_is_bee_movie_script(&mut file); + } + #[test] fn assert_img_fat_type() { static TEST_CASES: &[(&[u8], FATType)] = &[ - /*(MINFS, FATType::FAT12), TODO: uncomment this when we add support for FAT12 - (FAT12, FATType::FAT12),*/ + (MINFS, FATType::FAT12), + (FAT12, FATType::FAT12), (FAT16, FATType::FAT16), ];