From 03af6364dc1240cb5497c1d29f842a8684b43341 Mon Sep 17 00:00:00 2001 From: Stepan Perun Date: Thu, 19 Aug 2021 04:46:54 +0300 Subject: [PATCH] 21.8 --- LICENSE => License | 1 + Readme.md | 25 + data/desktop | 8 + data/grecovery-pkexec | 3 + data/icons/apply.png | Bin 0 -> 1826 bytes data/icons/clear.png | Bin 0 -> 2694 bytes data/icons/close.png | Bin 0 -> 1725 bytes data/icons/folder.png | Bin 0 -> 836 bytes data/icons/gresource.xml | 13 + data/icons/image.png | Bin 0 -> 1296 bytes data/icons/info.png | Bin 0 -> 2498 bytes data/icons/recovery.png | Bin 0 -> 2786 bytes data/icons/reload.png | Bin 0 -> 2388 bytes data/icons/search.png | Bin 0 -> 4115 bytes gtk/src/formats-win.c | 195 + gtk/src/formats-win.h | 28 + gtk/src/grecovery-app.c | 48 + gtk/src/grecovery-app.h | 19 + gtk/src/grecovery-win.c | 415 ++ gtk/src/grecovery-win.h | 19 + gtk/src/main.c | 21 + gtk/src/recovery.c | 1057 +++++ gtk/src/recovery.h | 34 + include/common.h | 667 ++++ include/config.h | 634 +++ include/filegen.h | 435 ++ include/fnctdsk.h | 254 ++ include/hdaccess.h | 106 + include/hdcache.h | 38 + include/intrf.h | 111 + include/list.h | 590 +++ include/log.h | 93 + include/log_part.h | 45 + include/partauto.h | 41 + include/phcfg.h | 46 + include/photorec.h | 294 ++ include/sessionp.h | 58 + meson.build | 27 + subprojects/lib/meson.build | 16 + subprojects/lib/src/addpart.c | 87 + subprojects/lib/src/addpart.h | 35 + subprojects/lib/src/alignio.h | 140 + subprojects/lib/src/analyse.c | 459 +++ subprojects/lib/src/analyse.h | 148 + subprojects/lib/src/apfs.c | 105 + subprojects/lib/src/apfs.h | 48 + subprojects/lib/src/apfs_common.c | 85 + subprojects/lib/src/apfs_common.h | 104 + subprojects/lib/src/autoset.c | 58 + subprojects/lib/src/autoset.h | 38 + subprojects/lib/src/bfs.c | 92 + subprojects/lib/src/bfs.h | 108 + subprojects/lib/src/bsd.c | 174 + subprojects/lib/src/bsd.h | 192 + subprojects/lib/src/btrfs.c | 122 + subprojects/lib/src/btrfs.h | 162 + subprojects/lib/src/chgarch.c | 123 + subprojects/lib/src/chgarch.h | 43 + subprojects/lib/src/chgtype.c | 98 + subprojects/lib/src/chgtype.h | 41 + subprojects/lib/src/common.c | 423 ++ subprojects/lib/src/common.h | 667 ++++ subprojects/lib/src/cramfs.c | 105 + subprojects/lib/src/cramfs.h | 107 + subprojects/lib/src/crc.c | 129 + subprojects/lib/src/crc.h | 43 + subprojects/lib/src/dfxml.c | 352 ++ subprojects/lib/src/dfxml.h | 60 + subprojects/lib/src/dir.c | 859 ++++ subprojects/lib/src/dir.h | 117 + subprojects/lib/src/dir_common.h | 123 + subprojects/lib/src/ewf.c | 605 +++ subprojects/lib/src/ewf.h | 45 + subprojects/lib/src/exfat.c | 120 + subprojects/lib/src/exfat.h | 138 + subprojects/lib/src/exfatp.c | 126 + subprojects/lib/src/exfatp.h | 42 + subprojects/lib/src/ext2.c | 183 + subprojects/lib/src/ext2.h | 48 + subprojects/lib/src/ext2_common.c | 94 + subprojects/lib/src/ext2_common.h | 233 ++ subprojects/lib/src/ext2_dir.c | 404 ++ subprojects/lib/src/ext2_dir.h | 41 + subprojects/lib/src/ext2_inc.h | 45 + subprojects/lib/src/ext2grp.c | 112 + subprojects/lib/src/ext2grp.h | 57 + subprojects/lib/src/ext2p.c | 126 + subprojects/lib/src/ext2p.h | 43 + subprojects/lib/src/f2fs.c | 101 + subprojects/lib/src/f2fs.h | 53 + subprojects/lib/src/f2fs_fs.h | 107 + subprojects/lib/src/fat.c | 1191 ++++++ subprojects/lib/src/fat.h | 182 + subprojects/lib/src/fat_common.c | 66 + subprojects/lib/src/fat_common.h | 177 + subprojects/lib/src/fat_dir.c | 612 +++ subprojects/lib/src/fat_dir.h | 50 + subprojects/lib/src/fatp.c | 241 ++ subprojects/lib/src/fatp.h | 42 + subprojects/lib/src/fatx.c | 68 + subprojects/lib/src/fatx.h | 55 + subprojects/lib/src/file_1cd.c | 79 + subprojects/lib/src/file_3dm.c | 70 + subprojects/lib/src/file_3ds.c | 84 + subprojects/lib/src/file_7z.c | 89 + subprojects/lib/src/file_DB.c | 65 + subprojects/lib/src/file_a.c | 85 + subprojects/lib/src/file_ab.c | 114 + subprojects/lib/src/file_abr.c | 122 + subprojects/lib/src/file_acb.c | 70 + subprojects/lib/src/file_ace.c | 234 ++ subprojects/lib/src/file_ado.c | 66 + subprojects/lib/src/file_afdesign.c | 88 + subprojects/lib/src/file_ahn.c | 68 + subprojects/lib/src/file_aif.c | 91 + subprojects/lib/src/file_all.c | 66 + subprojects/lib/src/file_als.c | 96 + subprojects/lib/src/file_amd.c | 101 + subprojects/lib/src/file_amr.c | 112 + subprojects/lib/src/file_apa.c | 69 + subprojects/lib/src/file_ape.c | 153 + subprojects/lib/src/file_apple.c | 65 + subprojects/lib/src/file_ari.c | 86 + subprojects/lib/src/file_arj.c | 181 + subprojects/lib/src/file_asf.c | 172 + subprojects/lib/src/file_asl.c | 67 + subprojects/lib/src/file_asm.c | 86 + subprojects/lib/src/file_atd.c | 66 + subprojects/lib/src/file_au.c | 100 + subprojects/lib/src/file_axp.c | 131 + subprojects/lib/src/file_axx.c | 141 + subprojects/lib/src/file_bac.c | 138 + subprojects/lib/src/file_bdm.c | 66 + subprojects/lib/src/file_berkeley.c | 85 + subprojects/lib/src/file_bfa.c | 86 + subprojects/lib/src/file_bim.c | 69 + subprojects/lib/src/file_bin.c | 85 + subprojects/lib/src/file_binvox.c | 63 + subprojects/lib/src/file_bkf.c | 121 + subprojects/lib/src/file_bld.c | 256 ++ subprojects/lib/src/file_bmp.c | 229 ++ subprojects/lib/src/file_bpg.c | 124 + subprojects/lib/src/file_bvr.c | 100 + subprojects/lib/src/file_bz2.c | 69 + subprojects/lib/src/file_c4d.c | 63 + subprojects/lib/src/file_cab.c | 90 + subprojects/lib/src/file_caf.c | 144 + subprojects/lib/src/file_cam.c | 64 + subprojects/lib/src/file_catdrawing.c | 67 + subprojects/lib/src/file_cdt.c | 73 + subprojects/lib/src/file_che.c | 120 + subprojects/lib/src/file_chm.c | 72 + subprojects/lib/src/file_class.c | 81 + subprojects/lib/src/file_clip.c | 113 + subprojects/lib/src/file_cm.c | 64 + subprojects/lib/src/file_compress.c | 64 + subprojects/lib/src/file_cow.c | 146 + subprojects/lib/src/file_cpi.c | 63 + subprojects/lib/src/file_crw.c | 88 + subprojects/lib/src/file_csh.c | 67 + subprojects/lib/src/file_ctg.c | 64 + subprojects/lib/src/file_cwk.c | 104 + subprojects/lib/src/file_d2s.c | 99 + subprojects/lib/src/file_dad.c | 123 + subprojects/lib/src/file_dar.c | 73 + subprojects/lib/src/file_dat.c | 125 + subprojects/lib/src/file_dbf.c | 76 + subprojects/lib/src/file_dbn.c | 71 + subprojects/lib/src/file_dcm.c | 66 + subprojects/lib/src/file_ddf.c | 172 + subprojects/lib/src/file_dex.c | 105 + subprojects/lib/src/file_dim.c | 63 + subprojects/lib/src/file_dir.c | 119 + subprojects/lib/src/file_djv.c | 80 + subprojects/lib/src/file_dmp.c | 70 + subprojects/lib/src/file_doc.c | 1918 +++++++++ subprojects/lib/src/file_doc.h | 37 + subprojects/lib/src/file_dpx.c | 104 + subprojects/lib/src/file_drw.c | 86 + subprojects/lib/src/file_drw2.c | 67 + subprojects/lib/src/file_ds2.c | 89 + subprojects/lib/src/file_ds_store.c | 82 + subprojects/lib/src/file_dsc.c | 66 + subprojects/lib/src/file_dss.c | 91 + subprojects/lib/src/file_dst.c | 77 + subprojects/lib/src/file_dta.c | 78 + subprojects/lib/src/file_dump.c | 159 + subprojects/lib/src/file_dv.c | 231 ++ subprojects/lib/src/file_dvi.c | 77 + subprojects/lib/src/file_dvr.c | 72 + subprojects/lib/src/file_dwg.c | 82 + subprojects/lib/src/file_dxf.c | 121 + subprojects/lib/src/file_e01.c | 142 + subprojects/lib/src/file_ecryptfs.c | 105 + subprojects/lib/src/file_edb.c | 75 + subprojects/lib/src/file_elf.c | 229 ++ subprojects/lib/src/file_emf.c | 498 +++ subprojects/lib/src/file_ess.c | 63 + subprojects/lib/src/file_evt.c | 126 + subprojects/lib/src/file_evtx.c | 90 + subprojects/lib/src/file_exe.c | 1003 +++++ subprojects/lib/src/file_exr.c | 67 + subprojects/lib/src/file_exs.c | 89 + subprojects/lib/src/file_ext.c | 173 + subprojects/lib/src/file_ext2.c | 82 + subprojects/lib/src/file_fat.c | 159 + subprojects/lib/src/file_fbf.c | 67 + subprojects/lib/src/file_fbk.c | 64 + subprojects/lib/src/file_fcp.c | 69 + subprojects/lib/src/file_fcs.c | 202 + subprojects/lib/src/file_fdb.c | 69 + subprojects/lib/src/file_fds.c | 77 + subprojects/lib/src/file_fh10.c | 75 + subprojects/lib/src/file_fh5.c | 95 + subprojects/lib/src/file_filevault.c | 70 + subprojects/lib/src/file_fit.c | 85 + subprojects/lib/src/file_fits.c | 247 ++ subprojects/lib/src/file_flac.c | 118 + subprojects/lib/src/file_flp.c | 88 + subprojects/lib/src/file_flv.c | 136 + subprojects/lib/src/file_fm.c | 82 + subprojects/lib/src/file_fob.c | 85 + subprojects/lib/src/file_fos.c | 64 + subprojects/lib/src/file_found.c | 69 + subprojects/lib/src/file_found.h | 38 + subprojects/lib/src/file_fp5.c | 66 + subprojects/lib/src/file_fp7.c | 84 + subprojects/lib/src/file_freeway.c | 67 + subprojects/lib/src/file_frm.c | 86 + subprojects/lib/src/file_fs.c | 125 + subprojects/lib/src/file_fwd.c | 63 + subprojects/lib/src/file_gam.c | 66 + subprojects/lib/src/file_gct.c | 70 + subprojects/lib/src/file_gho.c | 68 + subprojects/lib/src/file_gi.c | 82 + subprojects/lib/src/file_gif.c | 217 + subprojects/lib/src/file_gm6.c | 169 + subprojects/lib/src/file_gp2.c | 84 + subprojects/lib/src/file_gp5.c | 96 + subprojects/lib/src/file_gpg.c | 863 ++++ subprojects/lib/src/file_gpx.c | 67 + subprojects/lib/src/file_gsm.c | 158 + subprojects/lib/src/file_gz.c | 419 ++ subprojects/lib/src/file_gz.h | 36 + subprojects/lib/src/file_hdf.c | 162 + subprojects/lib/src/file_hdr.c | 93 + subprojects/lib/src/file_hds.c | 86 + subprojects/lib/src/file_hfsp.c | 73 + subprojects/lib/src/file_hm.c | 68 + subprojects/lib/src/file_hr9.c | 80 + subprojects/lib/src/file_http.c | 63 + subprojects/lib/src/file_ibd.c | 120 + subprojects/lib/src/file_icc.c | 78 + subprojects/lib/src/file_icns.c | 138 + subprojects/lib/src/file_ico.c | 172 + subprojects/lib/src/file_idx.c | 91 + subprojects/lib/src/file_ifo.c | 81 + subprojects/lib/src/file_imb.c | 65 + subprojects/lib/src/file_indd.c | 182 + subprojects/lib/src/file_info.c | 68 + subprojects/lib/src/file_iso.c | 89 + subprojects/lib/src/file_it.c | 94 + subprojects/lib/src/file_itu.c | 74 + subprojects/lib/src/file_jks.c | 80 + subprojects/lib/src/file_jpg.c | 2860 ++++++++++++++ subprojects/lib/src/file_jpg.h | 33 + subprojects/lib/src/file_jsonlz4.c | 72 + subprojects/lib/src/file_kdb.c | 65 + subprojects/lib/src/file_kdbx.c | 65 + subprojects/lib/src/file_key.c | 66 + subprojects/lib/src/file_ldf.c | 74 + subprojects/lib/src/file_list.c | 1426 +++++++ subprojects/lib/src/file_lit.c | 68 + subprojects/lib/src/file_lnk.c | 258 ++ subprojects/lib/src/file_logic.c | 66 + subprojects/lib/src/file_lso.c | 81 + subprojects/lib/src/file_luks.c | 77 + subprojects/lib/src/file_lxo.c | 95 + subprojects/lib/src/file_lzh.c | 187 + subprojects/lib/src/file_lzo.c | 67 + subprojects/lib/src/file_m2ts.c | 263 ++ subprojects/lib/src/file_mat.c | 72 + subprojects/lib/src/file_max.c | 65 + subprojects/lib/src/file_mb.c | 99 + subprojects/lib/src/file_mcd.c | 66 + subprojects/lib/src/file_mdb.c | 94 + subprojects/lib/src/file_mdf.c | 75 + subprojects/lib/src/file_mdp.c | 77 + subprojects/lib/src/file_mfa.c | 77 + subprojects/lib/src/file_mfg.c | 84 + subprojects/lib/src/file_mft.c | 111 + subprojects/lib/src/file_mid.c | 162 + subprojects/lib/src/file_mig.c | 140 + subprojects/lib/src/file_mk5.c | 67 + subprojects/lib/src/file_mkv.c | 270 ++ subprojects/lib/src/file_mlv.c | 226 ++ subprojects/lib/src/file_mobi.c | 86 + subprojects/lib/src/file_mov.c | 638 +++ subprojects/lib/src/file_mp3.c | 812 ++++ subprojects/lib/src/file_mpg.c | 400 ++ subprojects/lib/src/file_mpl.c | 63 + subprojects/lib/src/file_mrw.c | 110 + subprojects/lib/src/file_msa.c | 92 + subprojects/lib/src/file_mus.c | 79 + subprojects/lib/src/file_mxf.c | 164 + subprojects/lib/src/file_myo.c | 76 + subprojects/lib/src/file_mysql.c | 88 + subprojects/lib/src/file_nd2.c | 67 + subprojects/lib/src/file_nds.c | 91 + subprojects/lib/src/file_nes.c | 79 + subprojects/lib/src/file_njx.c | 84 + subprojects/lib/src/file_nk2.c | 251 ++ subprojects/lib/src/file_nsf.c | 71 + subprojects/lib/src/file_oci.c | 134 + subprojects/lib/src/file_ogg.c | 138 + subprojects/lib/src/file_one.c | 74 + subprojects/lib/src/file_orf.c | 82 + subprojects/lib/src/file_paf.c | 67 + subprojects/lib/src/file_pap.c | 65 + subprojects/lib/src/file_par2.c | 158 + subprojects/lib/src/file_pcap.c | 72 + subprojects/lib/src/file_pcb.c | 67 + subprojects/lib/src/file_pct.c | 158 + subprojects/lib/src/file_pcx.c | 121 + subprojects/lib/src/file_pdb.c | 125 + subprojects/lib/src/file_pdf.c | 464 +++ subprojects/lib/src/file_pds.c | 69 + subprojects/lib/src/file_pf.c | 212 + subprojects/lib/src/file_pfx.c | 102 + subprojects/lib/src/file_pgdump.c | 119 + subprojects/lib/src/file_plist.c | 78 + subprojects/lib/src/file_plr.c | 70 + subprojects/lib/src/file_plt.c | 71 + subprojects/lib/src/file_png.c | 358 ++ subprojects/lib/src/file_pnm.c | 105 + subprojects/lib/src/file_prc.c | 86 + subprojects/lib/src/file_prd.c | 69 + subprojects/lib/src/file_prt.c | 84 + subprojects/lib/src/file_ps.c | 129 + subprojects/lib/src/file_psb.c | 240 ++ subprojects/lib/src/file_psd.c | 229 ++ subprojects/lib/src/file_psf.c | 73 + subprojects/lib/src/file_psp.c | 106 + subprojects/lib/src/file_pst.c | 171 + subprojects/lib/src/file_ptb.c | 70 + subprojects/lib/src/file_ptf.c | 81 + subprojects/lib/src/file_pyc.c | 107 + subprojects/lib/src/file_pzf.c | 84 + subprojects/lib/src/file_pzh.c | 95 + subprojects/lib/src/file_qbb.c | 228 ++ subprojects/lib/src/file_qdf.c | 76 + subprojects/lib/src/file_qkt.c | 66 + subprojects/lib/src/file_qxd.c | 84 + subprojects/lib/src/file_r3d.c | 180 + subprojects/lib/src/file_ra.c | 128 + subprojects/lib/src/file_raf.c | 121 + subprojects/lib/src/file_rar.c | 116 + subprojects/lib/src/file_raw.c | 65 + subprojects/lib/src/file_rdc.c | 65 + subprojects/lib/src/file_reg.c | 144 + subprojects/lib/src/file_res.c | 65 + subprojects/lib/src/file_rfp.c | 67 + subprojects/lib/src/file_riff.c | 414 ++ subprojects/lib/src/file_riff.h | 39 + subprojects/lib/src/file_rlv.c | 71 + subprojects/lib/src/file_rm.c | 78 + subprojects/lib/src/file_rns.c | 64 + subprojects/lib/src/file_rpm.c | 114 + subprojects/lib/src/file_rw2.c | 73 + subprojects/lib/src/file_rx2.c | 78 + subprojects/lib/src/file_save.c | 66 + subprojects/lib/src/file_sdsk.c | 75 + subprojects/lib/src/file_ses.c | 64 + subprojects/lib/src/file_sgcta.c | 67 + subprojects/lib/src/file_shn.c | 64 + subprojects/lib/src/file_sib.c | 64 + subprojects/lib/src/file_sig.c | 686 ++++ subprojects/lib/src/file_sit.c | 65 + subprojects/lib/src/file_skd.c | 68 + subprojects/lib/src/file_skp.c | 66 + subprojects/lib/src/file_snag.c | 79 + subprojects/lib/src/file_sp3.c | 157 + subprojects/lib/src/file_sp3.h | 317 ++ subprojects/lib/src/file_spe.c | 406 ++ subprojects/lib/src/file_spf.c | 123 + subprojects/lib/src/file_spss.c | 64 + subprojects/lib/src/file_sql.c | 112 + subprojects/lib/src/file_sqm.c | 64 + subprojects/lib/src/file_steuer2014.c | 119 + subprojects/lib/src/file_stl.c | 83 + subprojects/lib/src/file_stu.c | 65 + subprojects/lib/src/file_studio.c | 77 + subprojects/lib/src/file_swf.c | 372 ++ subprojects/lib/src/file_tar.c | 141 + subprojects/lib/src/file_tar.h | 58 + subprojects/lib/src/file_tax.c | 65 + subprojects/lib/src/file_tg.c | 72 + subprojects/lib/src/file_tib.c | 168 + subprojects/lib/src/file_tiff.c | 197 + subprojects/lib/src/file_tiff.h | 168 + subprojects/lib/src/file_tiff_be.c | 887 +++++ subprojects/lib/src/file_tiff_le.c | 911 +++++ subprojects/lib/src/file_tivo.c | 85 + subprojects/lib/src/file_torrent.c | 66 + subprojects/lib/src/file_tph.c | 89 + subprojects/lib/src/file_tpl.c | 66 + subprojects/lib/src/file_ttf.c | 147 + subprojects/lib/src/file_txt.c | 3946 +++++++++++++++++++ subprojects/lib/src/file_tz.c | 80 + subprojects/lib/src/file_v2i.c | 69 + subprojects/lib/src/file_vault.c | 102 + subprojects/lib/src/file_vdi.c | 126 + subprojects/lib/src/file_vdj.c | 67 + subprojects/lib/src/file_veg.c | 71 + subprojects/lib/src/file_vfb.c | 77 + subprojects/lib/src/file_vib.c | 67 + subprojects/lib/src/file_vmdk.c | 143 + subprojects/lib/src/file_vmg.c | 88 + subprojects/lib/src/file_wad.c | 82 + subprojects/lib/src/file_wallet.c | 66 + subprojects/lib/src/file_wdp.c | 72 + subprojects/lib/src/file_wee.c | 85 + subprojects/lib/src/file_wim.c | 157 + subprojects/lib/src/file_win.c | 100 + subprojects/lib/src/file_wks.c | 91 + subprojects/lib/src/file_wld.c | 106 + subprojects/lib/src/file_wmf.c | 140 + subprojects/lib/src/file_wnk.c | 64 + subprojects/lib/src/file_woff.c | 101 + subprojects/lib/src/file_wpb.c | 66 + subprojects/lib/src/file_wpd.c | 114 + subprojects/lib/src/file_wtv.c | 80 + subprojects/lib/src/file_wv.c | 136 + subprojects/lib/src/file_x3f.c | 93 + subprojects/lib/src/file_x3i.c | 67 + subprojects/lib/src/file_x4a.c | 122 + subprojects/lib/src/file_xar.c | 93 + subprojects/lib/src/file_xcf.c | 87 + subprojects/lib/src/file_xfi.c | 69 + subprojects/lib/src/file_xfs.c | 172 + subprojects/lib/src/file_xm.c | 281 ++ subprojects/lib/src/file_xml.c | 134 + subprojects/lib/src/file_xpt.c | 88 + subprojects/lib/src/file_xsv.c | 68 + subprojects/lib/src/file_xv.c | 70 + subprojects/lib/src/file_xz.c | 83 + subprojects/lib/src/file_z2d.c | 69 + subprojects/lib/src/file_zcode.c | 66 + subprojects/lib/src/file_zip.c | 1494 +++++++ subprojects/lib/src/file_zpr.c | 66 + subprojects/lib/src/filegen.c | 984 +++++ subprojects/lib/src/filegen.h | 434 ++ subprojects/lib/src/fnctdsk.c | 497 +++ subprojects/lib/src/fnctdsk.h | 254 ++ subprojects/lib/src/geometry.c | 173 + subprojects/lib/src/geometry.h | 58 + subprojects/lib/src/gfs2.c | 89 + subprojects/lib/src/gfs2.h | 102 + subprojects/lib/src/guid_cmp.h | 39 + subprojects/lib/src/guid_cpy.h | 37 + subprojects/lib/src/hdaccess.c | 2011 ++++++++++ subprojects/lib/src/hdaccess.h | 106 + subprojects/lib/src/hdcache.c | 341 ++ subprojects/lib/src/hdcache.h | 38 + subprojects/lib/src/hdwin32.c | 114 + subprojects/lib/src/hdwin32.h | 39 + subprojects/lib/src/hfs.c | 134 + subprojects/lib/src/hfs.h | 108 + subprojects/lib/src/hfsp.c | 161 + subprojects/lib/src/hfsp.h | 57 + subprojects/lib/src/hfsp_struct.h | 153 + subprojects/lib/src/hidden.c | 61 + subprojects/lib/src/hidden.h | 38 + subprojects/lib/src/hpa_dco.c | 358 ++ subprojects/lib/src/hpa_dco.h | 37 + subprojects/lib/src/hpfs.c | 110 + subprojects/lib/src/hpfs.h | 49 + subprojects/lib/src/intrf.c | 265 ++ subprojects/lib/src/intrf.h | 111 + subprojects/lib/src/io_redir.c | 242 ++ subprojects/lib/src/io_redir.h | 42 + subprojects/lib/src/iso.c | 112 + subprojects/lib/src/iso.h | 47 + subprojects/lib/src/iso9660.h | 70 + subprojects/lib/src/jfs.c | 123 + subprojects/lib/src/jfs.h | 51 + subprojects/lib/src/jfs_superblock.h | 126 + subprojects/lib/src/lang.h | 61 + subprojects/lib/src/list.h | 590 +++ subprojects/lib/src/list_sort.c | 161 + subprojects/lib/src/list_sort.h | 35 + subprojects/lib/src/log.c | 329 ++ subprojects/lib/src/log.h | 93 + subprojects/lib/src/log_part.c | 51 + subprojects/lib/src/log_part.h | 45 + subprojects/lib/src/luks.c | 106 + subprojects/lib/src/luks.h | 50 + subprojects/lib/src/luks_struct.h | 65 + subprojects/lib/src/lvm.c | 188 + subprojects/lib/src/lvm.h | 155 + subprojects/lib/src/md.c | 416 ++ subprojects/lib/src/md.h | 284 ++ subprojects/lib/src/memmem.h | 69 + subprojects/lib/src/misc.c | 324 ++ subprojects/lib/src/misc.h | 42 + subprojects/lib/src/msdos.c | 593 +++ subprojects/lib/src/msdos.h | 47 + subprojects/lib/src/netware.c | 73 + subprojects/lib/src/netware.h | 57 + subprojects/lib/src/ntfs.c | 421 ++ subprojects/lib/src/ntfs.h | 101 + subprojects/lib/src/ntfs_dir.c | 561 +++ subprojects/lib/src/ntfs_dir.h | 44 + subprojects/lib/src/ntfs_inc.h | 44 + subprojects/lib/src/ntfs_io.c | 187 + subprojects/lib/src/ntfs_struct.h | 248 ++ subprojects/lib/src/ntfs_utl.c | 208 + subprojects/lib/src/ntfs_utl.h | 43 + subprojects/lib/src/ntfsp.c | 161 + subprojects/lib/src/ntfsp.h | 42 + subprojects/lib/src/ole.h | 103 + subprojects/lib/src/partauto.c | 168 + subprojects/lib/src/partauto.h | 41 + subprojects/lib/src/partgpt.c | 619 +++ subprojects/lib/src/partgpt.h | 91 + subprojects/lib/src/partgptro.c | 39 + subprojects/lib/src/parthumax.c | 365 ++ subprojects/lib/src/parthumax.h | 44 + subprojects/lib/src/parti386.c | 1858 +++++++++ subprojects/lib/src/parti386.h | 60 + subprojects/lib/src/partmac.c | 476 +++ subprojects/lib/src/partmac.h | 118 + subprojects/lib/src/partnone.c | 566 +++ subprojects/lib/src/partsun.c | 478 +++ subprojects/lib/src/partsun.h | 45 + subprojects/lib/src/partxbox.c | 392 ++ subprojects/lib/src/partxbox.h | 53 + subprojects/lib/src/pdisksel.c | 68 + subprojects/lib/src/pdisksel.h | 41 + subprojects/lib/src/pe.h | 186 + subprojects/lib/src/phcfg.c | 239 ++ subprojects/lib/src/phcfg.h | 46 + subprojects/lib/src/photorec.c | 1275 ++++++ subprojects/lib/src/photorec.h | 294 ++ subprojects/lib/src/photorec_check_header.h | 212 + subprojects/lib/src/pnext.h | 123 + subprojects/lib/src/poptions.c | 100 + subprojects/lib/src/poptions.h | 45 + subprojects/lib/src/psearch.h | 104 + subprojects/lib/src/refs.c | 83 + subprojects/lib/src/refs.h | 47 + subprojects/lib/src/rfs.c | 218 + subprojects/lib/src/rfs.h | 128 + subprojects/lib/src/savehdr.c | 242 ++ subprojects/lib/src/savehdr.h | 57 + subprojects/lib/src/sessionp.c | 344 ++ subprojects/lib/src/sessionp.h | 58 + subprojects/lib/src/setdate.c | 63 + subprojects/lib/src/setdate.h | 36 + subprojects/lib/src/sudo.c | 81 + subprojects/lib/src/sudo.h | 35 + subprojects/lib/src/sun.c | 127 + subprojects/lib/src/sun.h | 100 + subprojects/lib/src/suspend.h | 34 + subprojects/lib/src/suspend_no.c | 25 + subprojects/lib/src/swap.c | 182 + subprojects/lib/src/swap.h | 72 + subprojects/lib/src/sysv.c | 125 + subprojects/lib/src/sysv.h | 211 + subprojects/lib/src/types.h | 34 + subprojects/lib/src/ufs.c | 210 + subprojects/lib/src/ufs.h | 492 +++ subprojects/lib/src/unicode.c | 57 + subprojects/lib/src/unicode.h | 45 + subprojects/lib/src/utfsize.c | 120 + subprojects/lib/src/utfsize.h | 38 + subprojects/lib/src/vmfs.c | 95 + subprojects/lib/src/vmfs.h | 49 + subprojects/lib/src/wbfs.c | 95 + subprojects/lib/src/wbfs.h | 46 + subprojects/lib/src/win32.c | 564 +++ subprojects/lib/src/win32.h | 36 + subprojects/lib/src/xfs.c | 145 + subprojects/lib/src/xfs.h | 55 + subprojects/lib/src/xfs_struct.h | 115 + subprojects/lib/src/zfs.c | 99 + subprojects/lib/src/zfs.h | 58 + 587 files changed, 96497 insertions(+) rename LICENSE => License (99%) create mode 100644 Readme.md create mode 100644 data/desktop create mode 100755 data/grecovery-pkexec create mode 100644 data/icons/apply.png create mode 100644 data/icons/clear.png create mode 100644 data/icons/close.png create mode 100644 data/icons/folder.png create mode 100644 data/icons/gresource.xml create mode 100644 data/icons/image.png create mode 100644 data/icons/info.png create mode 100644 data/icons/recovery.png create mode 100644 data/icons/reload.png create mode 100644 data/icons/search.png create mode 100644 gtk/src/formats-win.c create mode 100644 gtk/src/formats-win.h create mode 100644 gtk/src/grecovery-app.c create mode 100644 gtk/src/grecovery-app.h create mode 100644 gtk/src/grecovery-win.c create mode 100644 gtk/src/grecovery-win.h create mode 100644 gtk/src/main.c create mode 100644 gtk/src/recovery.c create mode 100644 gtk/src/recovery.h create mode 100644 include/common.h create mode 100644 include/config.h create mode 100644 include/filegen.h create mode 100644 include/fnctdsk.h create mode 100644 include/hdaccess.h create mode 100644 include/hdcache.h create mode 100644 include/intrf.h create mode 100644 include/list.h create mode 100644 include/log.h create mode 100644 include/log_part.h create mode 100644 include/partauto.h create mode 100644 include/phcfg.h create mode 100644 include/photorec.h create mode 100644 include/sessionp.h create mode 100644 meson.build create mode 100644 subprojects/lib/meson.build create mode 100644 subprojects/lib/src/addpart.c create mode 100644 subprojects/lib/src/addpart.h create mode 100644 subprojects/lib/src/alignio.h create mode 100644 subprojects/lib/src/analyse.c create mode 100644 subprojects/lib/src/analyse.h create mode 100644 subprojects/lib/src/apfs.c create mode 100644 subprojects/lib/src/apfs.h create mode 100644 subprojects/lib/src/apfs_common.c create mode 100644 subprojects/lib/src/apfs_common.h create mode 100644 subprojects/lib/src/autoset.c create mode 100644 subprojects/lib/src/autoset.h create mode 100644 subprojects/lib/src/bfs.c create mode 100644 subprojects/lib/src/bfs.h create mode 100644 subprojects/lib/src/bsd.c create mode 100644 subprojects/lib/src/bsd.h create mode 100644 subprojects/lib/src/btrfs.c create mode 100644 subprojects/lib/src/btrfs.h create mode 100644 subprojects/lib/src/chgarch.c create mode 100644 subprojects/lib/src/chgarch.h create mode 100644 subprojects/lib/src/chgtype.c create mode 100644 subprojects/lib/src/chgtype.h create mode 100644 subprojects/lib/src/common.c create mode 100644 subprojects/lib/src/common.h create mode 100644 subprojects/lib/src/cramfs.c create mode 100644 subprojects/lib/src/cramfs.h create mode 100644 subprojects/lib/src/crc.c create mode 100644 subprojects/lib/src/crc.h create mode 100644 subprojects/lib/src/dfxml.c create mode 100644 subprojects/lib/src/dfxml.h create mode 100644 subprojects/lib/src/dir.c create mode 100644 subprojects/lib/src/dir.h create mode 100644 subprojects/lib/src/dir_common.h create mode 100644 subprojects/lib/src/ewf.c create mode 100644 subprojects/lib/src/ewf.h create mode 100644 subprojects/lib/src/exfat.c create mode 100644 subprojects/lib/src/exfat.h create mode 100644 subprojects/lib/src/exfatp.c create mode 100644 subprojects/lib/src/exfatp.h create mode 100644 subprojects/lib/src/ext2.c create mode 100644 subprojects/lib/src/ext2.h create mode 100644 subprojects/lib/src/ext2_common.c create mode 100644 subprojects/lib/src/ext2_common.h create mode 100644 subprojects/lib/src/ext2_dir.c create mode 100644 subprojects/lib/src/ext2_dir.h create mode 100644 subprojects/lib/src/ext2_inc.h create mode 100644 subprojects/lib/src/ext2grp.c create mode 100644 subprojects/lib/src/ext2grp.h create mode 100644 subprojects/lib/src/ext2p.c create mode 100644 subprojects/lib/src/ext2p.h create mode 100644 subprojects/lib/src/f2fs.c create mode 100644 subprojects/lib/src/f2fs.h create mode 100644 subprojects/lib/src/f2fs_fs.h create mode 100644 subprojects/lib/src/fat.c create mode 100644 subprojects/lib/src/fat.h create mode 100644 subprojects/lib/src/fat_common.c create mode 100644 subprojects/lib/src/fat_common.h create mode 100644 subprojects/lib/src/fat_dir.c create mode 100644 subprojects/lib/src/fat_dir.h create mode 100644 subprojects/lib/src/fatp.c create mode 100644 subprojects/lib/src/fatp.h create mode 100644 subprojects/lib/src/fatx.c create mode 100644 subprojects/lib/src/fatx.h create mode 100644 subprojects/lib/src/file_1cd.c create mode 100644 subprojects/lib/src/file_3dm.c create mode 100644 subprojects/lib/src/file_3ds.c create mode 100644 subprojects/lib/src/file_7z.c create mode 100644 subprojects/lib/src/file_DB.c create mode 100644 subprojects/lib/src/file_a.c create mode 100644 subprojects/lib/src/file_ab.c create mode 100644 subprojects/lib/src/file_abr.c create mode 100644 subprojects/lib/src/file_acb.c create mode 100644 subprojects/lib/src/file_ace.c create mode 100644 subprojects/lib/src/file_ado.c create mode 100644 subprojects/lib/src/file_afdesign.c create mode 100644 subprojects/lib/src/file_ahn.c create mode 100644 subprojects/lib/src/file_aif.c create mode 100644 subprojects/lib/src/file_all.c create mode 100644 subprojects/lib/src/file_als.c create mode 100644 subprojects/lib/src/file_amd.c create mode 100644 subprojects/lib/src/file_amr.c create mode 100644 subprojects/lib/src/file_apa.c create mode 100644 subprojects/lib/src/file_ape.c create mode 100644 subprojects/lib/src/file_apple.c create mode 100644 subprojects/lib/src/file_ari.c create mode 100644 subprojects/lib/src/file_arj.c create mode 100644 subprojects/lib/src/file_asf.c create mode 100644 subprojects/lib/src/file_asl.c create mode 100644 subprojects/lib/src/file_asm.c create mode 100644 subprojects/lib/src/file_atd.c create mode 100644 subprojects/lib/src/file_au.c create mode 100644 subprojects/lib/src/file_axp.c create mode 100644 subprojects/lib/src/file_axx.c create mode 100644 subprojects/lib/src/file_bac.c create mode 100644 subprojects/lib/src/file_bdm.c create mode 100644 subprojects/lib/src/file_berkeley.c create mode 100644 subprojects/lib/src/file_bfa.c create mode 100644 subprojects/lib/src/file_bim.c create mode 100644 subprojects/lib/src/file_bin.c create mode 100644 subprojects/lib/src/file_binvox.c create mode 100644 subprojects/lib/src/file_bkf.c create mode 100644 subprojects/lib/src/file_bld.c create mode 100644 subprojects/lib/src/file_bmp.c create mode 100644 subprojects/lib/src/file_bpg.c create mode 100644 subprojects/lib/src/file_bvr.c create mode 100644 subprojects/lib/src/file_bz2.c create mode 100644 subprojects/lib/src/file_c4d.c create mode 100644 subprojects/lib/src/file_cab.c create mode 100644 subprojects/lib/src/file_caf.c create mode 100644 subprojects/lib/src/file_cam.c create mode 100644 subprojects/lib/src/file_catdrawing.c create mode 100644 subprojects/lib/src/file_cdt.c create mode 100644 subprojects/lib/src/file_che.c create mode 100644 subprojects/lib/src/file_chm.c create mode 100644 subprojects/lib/src/file_class.c create mode 100644 subprojects/lib/src/file_clip.c create mode 100644 subprojects/lib/src/file_cm.c create mode 100644 subprojects/lib/src/file_compress.c create mode 100644 subprojects/lib/src/file_cow.c create mode 100644 subprojects/lib/src/file_cpi.c create mode 100644 subprojects/lib/src/file_crw.c create mode 100644 subprojects/lib/src/file_csh.c create mode 100644 subprojects/lib/src/file_ctg.c create mode 100644 subprojects/lib/src/file_cwk.c create mode 100644 subprojects/lib/src/file_d2s.c create mode 100644 subprojects/lib/src/file_dad.c create mode 100644 subprojects/lib/src/file_dar.c create mode 100644 subprojects/lib/src/file_dat.c create mode 100644 subprojects/lib/src/file_dbf.c create mode 100644 subprojects/lib/src/file_dbn.c create mode 100644 subprojects/lib/src/file_dcm.c create mode 100644 subprojects/lib/src/file_ddf.c create mode 100644 subprojects/lib/src/file_dex.c create mode 100644 subprojects/lib/src/file_dim.c create mode 100644 subprojects/lib/src/file_dir.c create mode 100644 subprojects/lib/src/file_djv.c create mode 100644 subprojects/lib/src/file_dmp.c create mode 100644 subprojects/lib/src/file_doc.c create mode 100644 subprojects/lib/src/file_doc.h create mode 100644 subprojects/lib/src/file_dpx.c create mode 100644 subprojects/lib/src/file_drw.c create mode 100644 subprojects/lib/src/file_drw2.c create mode 100644 subprojects/lib/src/file_ds2.c create mode 100644 subprojects/lib/src/file_ds_store.c create mode 100644 subprojects/lib/src/file_dsc.c create mode 100644 subprojects/lib/src/file_dss.c create mode 100644 subprojects/lib/src/file_dst.c create mode 100644 subprojects/lib/src/file_dta.c create mode 100644 subprojects/lib/src/file_dump.c create mode 100644 subprojects/lib/src/file_dv.c create mode 100644 subprojects/lib/src/file_dvi.c create mode 100644 subprojects/lib/src/file_dvr.c create mode 100644 subprojects/lib/src/file_dwg.c create mode 100644 subprojects/lib/src/file_dxf.c create mode 100644 subprojects/lib/src/file_e01.c create mode 100644 subprojects/lib/src/file_ecryptfs.c create mode 100644 subprojects/lib/src/file_edb.c create mode 100644 subprojects/lib/src/file_elf.c create mode 100644 subprojects/lib/src/file_emf.c create mode 100644 subprojects/lib/src/file_ess.c create mode 100644 subprojects/lib/src/file_evt.c create mode 100644 subprojects/lib/src/file_evtx.c create mode 100644 subprojects/lib/src/file_exe.c create mode 100644 subprojects/lib/src/file_exr.c create mode 100644 subprojects/lib/src/file_exs.c create mode 100644 subprojects/lib/src/file_ext.c create mode 100644 subprojects/lib/src/file_ext2.c create mode 100644 subprojects/lib/src/file_fat.c create mode 100644 subprojects/lib/src/file_fbf.c create mode 100644 subprojects/lib/src/file_fbk.c create mode 100644 subprojects/lib/src/file_fcp.c create mode 100644 subprojects/lib/src/file_fcs.c create mode 100644 subprojects/lib/src/file_fdb.c create mode 100644 subprojects/lib/src/file_fds.c create mode 100644 subprojects/lib/src/file_fh10.c create mode 100644 subprojects/lib/src/file_fh5.c create mode 100644 subprojects/lib/src/file_filevault.c create mode 100644 subprojects/lib/src/file_fit.c create mode 100644 subprojects/lib/src/file_fits.c create mode 100644 subprojects/lib/src/file_flac.c create mode 100644 subprojects/lib/src/file_flp.c create mode 100644 subprojects/lib/src/file_flv.c create mode 100644 subprojects/lib/src/file_fm.c create mode 100644 subprojects/lib/src/file_fob.c create mode 100644 subprojects/lib/src/file_fos.c create mode 100644 subprojects/lib/src/file_found.c create mode 100644 subprojects/lib/src/file_found.h create mode 100644 subprojects/lib/src/file_fp5.c create mode 100644 subprojects/lib/src/file_fp7.c create mode 100644 subprojects/lib/src/file_freeway.c create mode 100644 subprojects/lib/src/file_frm.c create mode 100644 subprojects/lib/src/file_fs.c create mode 100644 subprojects/lib/src/file_fwd.c create mode 100644 subprojects/lib/src/file_gam.c create mode 100644 subprojects/lib/src/file_gct.c create mode 100644 subprojects/lib/src/file_gho.c create mode 100644 subprojects/lib/src/file_gi.c create mode 100644 subprojects/lib/src/file_gif.c create mode 100644 subprojects/lib/src/file_gm6.c create mode 100644 subprojects/lib/src/file_gp2.c create mode 100644 subprojects/lib/src/file_gp5.c create mode 100644 subprojects/lib/src/file_gpg.c create mode 100644 subprojects/lib/src/file_gpx.c create mode 100644 subprojects/lib/src/file_gsm.c create mode 100644 subprojects/lib/src/file_gz.c create mode 100644 subprojects/lib/src/file_gz.h create mode 100644 subprojects/lib/src/file_hdf.c create mode 100644 subprojects/lib/src/file_hdr.c create mode 100644 subprojects/lib/src/file_hds.c create mode 100644 subprojects/lib/src/file_hfsp.c create mode 100644 subprojects/lib/src/file_hm.c create mode 100644 subprojects/lib/src/file_hr9.c create mode 100644 subprojects/lib/src/file_http.c create mode 100644 subprojects/lib/src/file_ibd.c create mode 100644 subprojects/lib/src/file_icc.c create mode 100644 subprojects/lib/src/file_icns.c create mode 100644 subprojects/lib/src/file_ico.c create mode 100644 subprojects/lib/src/file_idx.c create mode 100644 subprojects/lib/src/file_ifo.c create mode 100644 subprojects/lib/src/file_imb.c create mode 100644 subprojects/lib/src/file_indd.c create mode 100644 subprojects/lib/src/file_info.c create mode 100644 subprojects/lib/src/file_iso.c create mode 100644 subprojects/lib/src/file_it.c create mode 100644 subprojects/lib/src/file_itu.c create mode 100644 subprojects/lib/src/file_jks.c create mode 100644 subprojects/lib/src/file_jpg.c create mode 100644 subprojects/lib/src/file_jpg.h create mode 100644 subprojects/lib/src/file_jsonlz4.c create mode 100644 subprojects/lib/src/file_kdb.c create mode 100644 subprojects/lib/src/file_kdbx.c create mode 100644 subprojects/lib/src/file_key.c create mode 100644 subprojects/lib/src/file_ldf.c create mode 100644 subprojects/lib/src/file_list.c create mode 100644 subprojects/lib/src/file_lit.c create mode 100644 subprojects/lib/src/file_lnk.c create mode 100644 subprojects/lib/src/file_logic.c create mode 100644 subprojects/lib/src/file_lso.c create mode 100644 subprojects/lib/src/file_luks.c create mode 100644 subprojects/lib/src/file_lxo.c create mode 100644 subprojects/lib/src/file_lzh.c create mode 100644 subprojects/lib/src/file_lzo.c create mode 100644 subprojects/lib/src/file_m2ts.c create mode 100644 subprojects/lib/src/file_mat.c create mode 100644 subprojects/lib/src/file_max.c create mode 100644 subprojects/lib/src/file_mb.c create mode 100644 subprojects/lib/src/file_mcd.c create mode 100644 subprojects/lib/src/file_mdb.c create mode 100644 subprojects/lib/src/file_mdf.c create mode 100644 subprojects/lib/src/file_mdp.c create mode 100644 subprojects/lib/src/file_mfa.c create mode 100644 subprojects/lib/src/file_mfg.c create mode 100644 subprojects/lib/src/file_mft.c create mode 100644 subprojects/lib/src/file_mid.c create mode 100644 subprojects/lib/src/file_mig.c create mode 100644 subprojects/lib/src/file_mk5.c create mode 100644 subprojects/lib/src/file_mkv.c create mode 100644 subprojects/lib/src/file_mlv.c create mode 100644 subprojects/lib/src/file_mobi.c create mode 100644 subprojects/lib/src/file_mov.c create mode 100644 subprojects/lib/src/file_mp3.c create mode 100644 subprojects/lib/src/file_mpg.c create mode 100644 subprojects/lib/src/file_mpl.c create mode 100644 subprojects/lib/src/file_mrw.c create mode 100644 subprojects/lib/src/file_msa.c create mode 100644 subprojects/lib/src/file_mus.c create mode 100644 subprojects/lib/src/file_mxf.c create mode 100644 subprojects/lib/src/file_myo.c create mode 100644 subprojects/lib/src/file_mysql.c create mode 100644 subprojects/lib/src/file_nd2.c create mode 100644 subprojects/lib/src/file_nds.c create mode 100644 subprojects/lib/src/file_nes.c create mode 100644 subprojects/lib/src/file_njx.c create mode 100644 subprojects/lib/src/file_nk2.c create mode 100644 subprojects/lib/src/file_nsf.c create mode 100644 subprojects/lib/src/file_oci.c create mode 100644 subprojects/lib/src/file_ogg.c create mode 100644 subprojects/lib/src/file_one.c create mode 100644 subprojects/lib/src/file_orf.c create mode 100644 subprojects/lib/src/file_paf.c create mode 100644 subprojects/lib/src/file_pap.c create mode 100644 subprojects/lib/src/file_par2.c create mode 100644 subprojects/lib/src/file_pcap.c create mode 100644 subprojects/lib/src/file_pcb.c create mode 100644 subprojects/lib/src/file_pct.c create mode 100644 subprojects/lib/src/file_pcx.c create mode 100644 subprojects/lib/src/file_pdb.c create mode 100644 subprojects/lib/src/file_pdf.c create mode 100644 subprojects/lib/src/file_pds.c create mode 100644 subprojects/lib/src/file_pf.c create mode 100644 subprojects/lib/src/file_pfx.c create mode 100644 subprojects/lib/src/file_pgdump.c create mode 100644 subprojects/lib/src/file_plist.c create mode 100644 subprojects/lib/src/file_plr.c create mode 100644 subprojects/lib/src/file_plt.c create mode 100644 subprojects/lib/src/file_png.c create mode 100644 subprojects/lib/src/file_pnm.c create mode 100644 subprojects/lib/src/file_prc.c create mode 100644 subprojects/lib/src/file_prd.c create mode 100644 subprojects/lib/src/file_prt.c create mode 100644 subprojects/lib/src/file_ps.c create mode 100644 subprojects/lib/src/file_psb.c create mode 100644 subprojects/lib/src/file_psd.c create mode 100644 subprojects/lib/src/file_psf.c create mode 100644 subprojects/lib/src/file_psp.c create mode 100644 subprojects/lib/src/file_pst.c create mode 100644 subprojects/lib/src/file_ptb.c create mode 100644 subprojects/lib/src/file_ptf.c create mode 100644 subprojects/lib/src/file_pyc.c create mode 100644 subprojects/lib/src/file_pzf.c create mode 100644 subprojects/lib/src/file_pzh.c create mode 100644 subprojects/lib/src/file_qbb.c create mode 100644 subprojects/lib/src/file_qdf.c create mode 100644 subprojects/lib/src/file_qkt.c create mode 100644 subprojects/lib/src/file_qxd.c create mode 100644 subprojects/lib/src/file_r3d.c create mode 100644 subprojects/lib/src/file_ra.c create mode 100644 subprojects/lib/src/file_raf.c create mode 100644 subprojects/lib/src/file_rar.c create mode 100644 subprojects/lib/src/file_raw.c create mode 100644 subprojects/lib/src/file_rdc.c create mode 100644 subprojects/lib/src/file_reg.c create mode 100644 subprojects/lib/src/file_res.c create mode 100644 subprojects/lib/src/file_rfp.c create mode 100644 subprojects/lib/src/file_riff.c create mode 100644 subprojects/lib/src/file_riff.h create mode 100644 subprojects/lib/src/file_rlv.c create mode 100644 subprojects/lib/src/file_rm.c create mode 100644 subprojects/lib/src/file_rns.c create mode 100644 subprojects/lib/src/file_rpm.c create mode 100644 subprojects/lib/src/file_rw2.c create mode 100644 subprojects/lib/src/file_rx2.c create mode 100644 subprojects/lib/src/file_save.c create mode 100644 subprojects/lib/src/file_sdsk.c create mode 100644 subprojects/lib/src/file_ses.c create mode 100644 subprojects/lib/src/file_sgcta.c create mode 100644 subprojects/lib/src/file_shn.c create mode 100644 subprojects/lib/src/file_sib.c create mode 100644 subprojects/lib/src/file_sig.c create mode 100644 subprojects/lib/src/file_sit.c create mode 100644 subprojects/lib/src/file_skd.c create mode 100644 subprojects/lib/src/file_skp.c create mode 100644 subprojects/lib/src/file_snag.c create mode 100644 subprojects/lib/src/file_sp3.c create mode 100644 subprojects/lib/src/file_sp3.h create mode 100644 subprojects/lib/src/file_spe.c create mode 100644 subprojects/lib/src/file_spf.c create mode 100644 subprojects/lib/src/file_spss.c create mode 100644 subprojects/lib/src/file_sql.c create mode 100644 subprojects/lib/src/file_sqm.c create mode 100644 subprojects/lib/src/file_steuer2014.c create mode 100644 subprojects/lib/src/file_stl.c create mode 100644 subprojects/lib/src/file_stu.c create mode 100644 subprojects/lib/src/file_studio.c create mode 100644 subprojects/lib/src/file_swf.c create mode 100644 subprojects/lib/src/file_tar.c create mode 100644 subprojects/lib/src/file_tar.h create mode 100644 subprojects/lib/src/file_tax.c create mode 100644 subprojects/lib/src/file_tg.c create mode 100644 subprojects/lib/src/file_tib.c create mode 100644 subprojects/lib/src/file_tiff.c create mode 100644 subprojects/lib/src/file_tiff.h create mode 100644 subprojects/lib/src/file_tiff_be.c create mode 100644 subprojects/lib/src/file_tiff_le.c create mode 100644 subprojects/lib/src/file_tivo.c create mode 100644 subprojects/lib/src/file_torrent.c create mode 100644 subprojects/lib/src/file_tph.c create mode 100644 subprojects/lib/src/file_tpl.c create mode 100644 subprojects/lib/src/file_ttf.c create mode 100644 subprojects/lib/src/file_txt.c create mode 100644 subprojects/lib/src/file_tz.c create mode 100644 subprojects/lib/src/file_v2i.c create mode 100644 subprojects/lib/src/file_vault.c create mode 100644 subprojects/lib/src/file_vdi.c create mode 100644 subprojects/lib/src/file_vdj.c create mode 100644 subprojects/lib/src/file_veg.c create mode 100644 subprojects/lib/src/file_vfb.c create mode 100644 subprojects/lib/src/file_vib.c create mode 100644 subprojects/lib/src/file_vmdk.c create mode 100644 subprojects/lib/src/file_vmg.c create mode 100644 subprojects/lib/src/file_wad.c create mode 100644 subprojects/lib/src/file_wallet.c create mode 100644 subprojects/lib/src/file_wdp.c create mode 100644 subprojects/lib/src/file_wee.c create mode 100644 subprojects/lib/src/file_wim.c create mode 100644 subprojects/lib/src/file_win.c create mode 100644 subprojects/lib/src/file_wks.c create mode 100644 subprojects/lib/src/file_wld.c create mode 100644 subprojects/lib/src/file_wmf.c create mode 100644 subprojects/lib/src/file_wnk.c create mode 100644 subprojects/lib/src/file_woff.c create mode 100644 subprojects/lib/src/file_wpb.c create mode 100644 subprojects/lib/src/file_wpd.c create mode 100644 subprojects/lib/src/file_wtv.c create mode 100644 subprojects/lib/src/file_wv.c create mode 100644 subprojects/lib/src/file_x3f.c create mode 100644 subprojects/lib/src/file_x3i.c create mode 100644 subprojects/lib/src/file_x4a.c create mode 100644 subprojects/lib/src/file_xar.c create mode 100644 subprojects/lib/src/file_xcf.c create mode 100644 subprojects/lib/src/file_xfi.c create mode 100644 subprojects/lib/src/file_xfs.c create mode 100644 subprojects/lib/src/file_xm.c create mode 100644 subprojects/lib/src/file_xml.c create mode 100644 subprojects/lib/src/file_xpt.c create mode 100644 subprojects/lib/src/file_xsv.c create mode 100644 subprojects/lib/src/file_xv.c create mode 100644 subprojects/lib/src/file_xz.c create mode 100644 subprojects/lib/src/file_z2d.c create mode 100644 subprojects/lib/src/file_zcode.c create mode 100644 subprojects/lib/src/file_zip.c create mode 100644 subprojects/lib/src/file_zpr.c create mode 100644 subprojects/lib/src/filegen.c create mode 100644 subprojects/lib/src/filegen.h create mode 100644 subprojects/lib/src/fnctdsk.c create mode 100644 subprojects/lib/src/fnctdsk.h create mode 100644 subprojects/lib/src/geometry.c create mode 100644 subprojects/lib/src/geometry.h create mode 100644 subprojects/lib/src/gfs2.c create mode 100644 subprojects/lib/src/gfs2.h create mode 100644 subprojects/lib/src/guid_cmp.h create mode 100644 subprojects/lib/src/guid_cpy.h create mode 100644 subprojects/lib/src/hdaccess.c create mode 100644 subprojects/lib/src/hdaccess.h create mode 100644 subprojects/lib/src/hdcache.c create mode 100644 subprojects/lib/src/hdcache.h create mode 100644 subprojects/lib/src/hdwin32.c create mode 100644 subprojects/lib/src/hdwin32.h create mode 100644 subprojects/lib/src/hfs.c create mode 100644 subprojects/lib/src/hfs.h create mode 100644 subprojects/lib/src/hfsp.c create mode 100644 subprojects/lib/src/hfsp.h create mode 100644 subprojects/lib/src/hfsp_struct.h create mode 100644 subprojects/lib/src/hidden.c create mode 100644 subprojects/lib/src/hidden.h create mode 100644 subprojects/lib/src/hpa_dco.c create mode 100644 subprojects/lib/src/hpa_dco.h create mode 100644 subprojects/lib/src/hpfs.c create mode 100644 subprojects/lib/src/hpfs.h create mode 100644 subprojects/lib/src/intrf.c create mode 100644 subprojects/lib/src/intrf.h create mode 100644 subprojects/lib/src/io_redir.c create mode 100644 subprojects/lib/src/io_redir.h create mode 100644 subprojects/lib/src/iso.c create mode 100644 subprojects/lib/src/iso.h create mode 100644 subprojects/lib/src/iso9660.h create mode 100644 subprojects/lib/src/jfs.c create mode 100644 subprojects/lib/src/jfs.h create mode 100644 subprojects/lib/src/jfs_superblock.h create mode 100644 subprojects/lib/src/lang.h create mode 100644 subprojects/lib/src/list.h create mode 100644 subprojects/lib/src/list_sort.c create mode 100644 subprojects/lib/src/list_sort.h create mode 100644 subprojects/lib/src/log.c create mode 100644 subprojects/lib/src/log.h create mode 100644 subprojects/lib/src/log_part.c create mode 100644 subprojects/lib/src/log_part.h create mode 100644 subprojects/lib/src/luks.c create mode 100644 subprojects/lib/src/luks.h create mode 100644 subprojects/lib/src/luks_struct.h create mode 100644 subprojects/lib/src/lvm.c create mode 100644 subprojects/lib/src/lvm.h create mode 100644 subprojects/lib/src/md.c create mode 100644 subprojects/lib/src/md.h create mode 100644 subprojects/lib/src/memmem.h create mode 100644 subprojects/lib/src/misc.c create mode 100644 subprojects/lib/src/misc.h create mode 100644 subprojects/lib/src/msdos.c create mode 100644 subprojects/lib/src/msdos.h create mode 100644 subprojects/lib/src/netware.c create mode 100644 subprojects/lib/src/netware.h create mode 100644 subprojects/lib/src/ntfs.c create mode 100644 subprojects/lib/src/ntfs.h create mode 100644 subprojects/lib/src/ntfs_dir.c create mode 100644 subprojects/lib/src/ntfs_dir.h create mode 100644 subprojects/lib/src/ntfs_inc.h create mode 100644 subprojects/lib/src/ntfs_io.c create mode 100644 subprojects/lib/src/ntfs_struct.h create mode 100644 subprojects/lib/src/ntfs_utl.c create mode 100644 subprojects/lib/src/ntfs_utl.h create mode 100644 subprojects/lib/src/ntfsp.c create mode 100644 subprojects/lib/src/ntfsp.h create mode 100644 subprojects/lib/src/ole.h create mode 100644 subprojects/lib/src/partauto.c create mode 100644 subprojects/lib/src/partauto.h create mode 100644 subprojects/lib/src/partgpt.c create mode 100644 subprojects/lib/src/partgpt.h create mode 100644 subprojects/lib/src/partgptro.c create mode 100644 subprojects/lib/src/parthumax.c create mode 100644 subprojects/lib/src/parthumax.h create mode 100644 subprojects/lib/src/parti386.c create mode 100644 subprojects/lib/src/parti386.h create mode 100644 subprojects/lib/src/partmac.c create mode 100644 subprojects/lib/src/partmac.h create mode 100644 subprojects/lib/src/partnone.c create mode 100644 subprojects/lib/src/partsun.c create mode 100644 subprojects/lib/src/partsun.h create mode 100644 subprojects/lib/src/partxbox.c create mode 100644 subprojects/lib/src/partxbox.h create mode 100644 subprojects/lib/src/pdisksel.c create mode 100644 subprojects/lib/src/pdisksel.h create mode 100644 subprojects/lib/src/pe.h create mode 100644 subprojects/lib/src/phcfg.c create mode 100644 subprojects/lib/src/phcfg.h create mode 100644 subprojects/lib/src/photorec.c create mode 100644 subprojects/lib/src/photorec.h create mode 100644 subprojects/lib/src/photorec_check_header.h create mode 100644 subprojects/lib/src/pnext.h create mode 100644 subprojects/lib/src/poptions.c create mode 100644 subprojects/lib/src/poptions.h create mode 100644 subprojects/lib/src/psearch.h create mode 100644 subprojects/lib/src/refs.c create mode 100644 subprojects/lib/src/refs.h create mode 100644 subprojects/lib/src/rfs.c create mode 100644 subprojects/lib/src/rfs.h create mode 100644 subprojects/lib/src/savehdr.c create mode 100644 subprojects/lib/src/savehdr.h create mode 100644 subprojects/lib/src/sessionp.c create mode 100644 subprojects/lib/src/sessionp.h create mode 100644 subprojects/lib/src/setdate.c create mode 100644 subprojects/lib/src/setdate.h create mode 100644 subprojects/lib/src/sudo.c create mode 100644 subprojects/lib/src/sudo.h create mode 100644 subprojects/lib/src/sun.c create mode 100644 subprojects/lib/src/sun.h create mode 100644 subprojects/lib/src/suspend.h create mode 100644 subprojects/lib/src/suspend_no.c create mode 100644 subprojects/lib/src/swap.c create mode 100644 subprojects/lib/src/swap.h create mode 100644 subprojects/lib/src/sysv.c create mode 100644 subprojects/lib/src/sysv.h create mode 100644 subprojects/lib/src/types.h create mode 100644 subprojects/lib/src/ufs.c create mode 100644 subprojects/lib/src/ufs.h create mode 100644 subprojects/lib/src/unicode.c create mode 100644 subprojects/lib/src/unicode.h create mode 100644 subprojects/lib/src/utfsize.c create mode 100644 subprojects/lib/src/utfsize.h create mode 100644 subprojects/lib/src/vmfs.c create mode 100644 subprojects/lib/src/vmfs.h create mode 100644 subprojects/lib/src/wbfs.c create mode 100644 subprojects/lib/src/wbfs.h create mode 100644 subprojects/lib/src/win32.c create mode 100644 subprojects/lib/src/win32.h create mode 100644 subprojects/lib/src/xfs.c create mode 100644 subprojects/lib/src/xfs.h create mode 100644 subprojects/lib/src/xfs_struct.h create mode 100644 subprojects/lib/src/zfs.c create mode 100644 subprojects/lib/src/zfs.h diff --git a/LICENSE b/License similarity index 99% rename from LICENSE rename to License index d159169..1f963da 100644 --- a/LICENSE +++ b/License @@ -337,3 +337,4 @@ proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. + diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..db05bbc --- /dev/null +++ b/Readme.md @@ -0,0 +1,25 @@ +### GRecovery + +* Data Recovery Utility +* Base in [PhotoRec](https://www.cgsecurity.org) + + +#### Dependencies + +* gcc, meson +* libz ( & dev ) +* ext2fs ( & dev ) +* libjpeg ( & dev ) +* libntfs-3g ( & dev ) +* libgtk 3.0 ( & dev ) + + +#### Build + +1. Configure: meson build --prefix /usr --strip + +2. Build: ninja -C build + +3. Install: sudo ninja -C build install + +4. Uninstall: sudo ninja -C build uninstall diff --git a/data/desktop b/data/desktop new file mode 100644 index 0000000..8247e48 --- /dev/null +++ b/data/desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=GRecovery +Comment=Data Recovery Utility +Exec=grecovery-pkexec +Icon=image +Terminal=false +Type=Application +Categories=GTK;Utility; diff --git a/data/grecovery-pkexec b/data/grecovery-pkexec new file mode 100755 index 0000000..a29386f --- /dev/null +++ b/data/grecovery-pkexec @@ -0,0 +1,3 @@ +#!/bin/bash + +pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY "/usr/bin/grecovery" $@ diff --git a/data/icons/apply.png b/data/icons/apply.png new file mode 100644 index 0000000000000000000000000000000000000000..47c9d25052c56093c23a1181f3825c8dd122e2e3 GIT binary patch literal 1826 zcmV+-2i^FIP){z-@v^jqca==tQz ztHrqXTE=ff7q&g!I#-m!jsz|+9cc>acc136_Skn-c7@c^of`4BXQj(#ZVcD} z(+~{-)85styH7l=#$&H@@!-pG|Dp0#23~kugPZSVV??Q>2$+V~ByM!o$@q8YURUAX z=OZ-Cc%jV^8vFxjvaqC6Zbxo;f|*XYVLZLf~Q~9V7$WrJU<33 zfl2sg^2W_RKjc^C^CH~x{Sb{Fd6ti}&J6w4PtH#UCczsDRWwpc7akoU6Dx0ylh>jEf)l(&)}_ zGjQUz@Tb_D{lF65+<#dJ{ArJUtkh8qx8DUwzPY;{;>>eZ*`*V zsOIAPF<5;z2BmqtYCvegsFoqD!eZ}|n@KqLR&T7j9-(ISjSjf>!8jZ=&+P^$8XUEH z6zJFSKXN{uWu~zcw+Fpnb~gd1UkTOdf?H8otnAU?E$3u`wlI$bjx?XUr2l+}>(cy| z3c+x&fd2vg;iUaE%j5LfpLw|>PQDnV=Cn)UNbgS9nKoxhPAw1tdR|$qip+fxzb?L+ zhy_PFe+aD*9kCj&@AuKwPcxHc><;^F_O(G+dakWTXI~wNlXiss;xfrZdo6>V%s6)V zD!-?5uEk=>*+8tlG7x8+9e_RRBsXnG8^=K;=)!-&jR)&4mDZQ%UL8Wk1YzNs)@qiW z3&pxiaTr`CI&7W-9MA^Tw)*v`wYyz=F$N1yx5M0%0gYCi>x4BIqcLu|+f$DWvtmIc zn1KqOa(1bFfB1)~=ev^_b*nD+$Ha93uWiN}^aX7oj0I6pxjYvA1O|Lpo@P>eU_gb5~RTm>M`?x_p(&rW(!;nQ8Sd zY8AD@izV1;p;*md+VrPXdhRqfI+l~ut zu=@g6w3Qid5kxfhOS(iII-aOiT99ITlm?WBltz@slqQs>zy&rxMmNqii+#7#Tqo=> z&kh6Y1dVo8xS)3d_d8BM=mG#Nq8S}W;*Ci@Ly}*g)FKo7laK@kDi3Q)3bQFWl;)IN zN**PjQo!i~9c)vLPX|`oVAw1>463!lph^jflk`_p8La60Pmd$x={PRQ!y$QDDibqO znUL-uos1r(p~{1^NP(85D4#rth*C^xNoh@KW9$!s;v|DT-etmuc2%}$H;MJwG^la) zZ7C&WoE3=^sZ5AV@^e%sVyrR|vMXAi0Hv*g19%JKb!Q6`^bfGR=*9zp{imJ)kiq(Y zP$Zk^YU*bPLIh6_O67^KnS5c2v8!w~(0te-cr*v4A QZ2$lO07*qoM6N<$g8Gku#{d8T literal 0 HcmV?d00001 diff --git a/data/icons/clear.png b/data/icons/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..bb3290fcb4c96e783a04eafe73172b728372ac5d GIT binary patch literal 2694 zcmV;13VHR3P)qN2-88sv?mf6g8!4 zp`}$NR8UbVO)09_)BsI^v>2R_W+^1WPQ1ih;yw1;{FYhn(m$RPTq|zvY_`;nbToQb zdUw9x+;hHr&jA0wX7(a8`S4%fg-e)WKBg3I6uwuWY1Ac@ZdE6ohaTPzcPewRnG*l2 zwZ=xBnVVKzeRH6y_F`(xGdzvd%@illoXIsKuG~;6b?_~NLx4eq_JUI z^Iiz?&)j7!Bg`(#%gKQgX@^o-;n|STtUMfSY|SWvXE*<8xNp`02#wuUQCY2f$pLUT z38~~M0F7A~9*p4F(CBC~L$^$OWiQBiMUl00i}DR;bP&Q#XVXUs00dG{>}fiY=7Qe+ z)V86~SqHFXb8j#6ImAs4 zfxAg4rLz95Tj-Dasy8a5OyQ9;HivVmwf+5qJl|CPN+}D3I#gr5UCknwCZr`&qo>3Z zs>9_P4s^?m5bX9Jy*`kfHOJ|eT}55auVxcy_tPK|}wh#yfG1%RR!m==kmJ84#ILRn_JL}VK zYGgNj|L)80ObyH^z~;@HwLN?GWHxNrUh&)5nye^jszOn*9m&JBU1 zeYI@Q-cB59N+6by2v>(uUQvxuD1^bmLG<-@AQBnD%{Sy>Vev;9rc&2l_3gyI8L0uK zptbHS`W-Wizg1cHpv`oKbgU6xY7m6kXl#k$!-fbBcNTyP0~M7usICsfaU68CH)CYD zZ}iPS@5r5zB325db$9WLrd_kTqV55k$RYSnFNjhg43NS>V)z&&(J(yX;6M|{-h(!} zdJKf;)uFt+67}`J$f95{Fs0DW@DjvaqL>tp(K|8Te=e=TMC>ndvRw~6Ql zRB~)pIF$7NEz-#dn4y6Xj>=Mkf*gT)H5xh(f0mw`pL%=y_OmyTX|MiVd$2B~~V>BINE>`M3%1k3_R zuIerrK*%k8KA5*;QNi46m=ebTS^+}K;HLWFr8;0(_E`F4>mV~40ShoFO=LxL4~mZg z$TT!+KtX38KLhK$1GF?0eBUq%?<@`9Z7b0SLaX3;0-l?MGkOS2*Fnfwo=YE!6vA~4 z7^Z%zCVbCH!$=IoI>!vE(@iX#Oy-MnOJbTD`^&1j@nv1iB9YGCdk^)k~}H(7kjA zBu|0q3>wX*31}Hy$Agm@g+>NJz@bFe`<37zbPlZCtFsTJ`QUyUR73pw&EV%8VDYu_ zP9@YW{ar67M`QcZdHCs!lkT@mDpwK7IfT~>B{>Ys94lHI5(P*Mw}ZR=U;%l`N(JYT zN`dRqUAfL#uV9%w{B2oGW`_o=Y}8Y_St+qE^l6q(Tz%5hcW znDCPT<3pb+%%nxUd!eb6fFu+|2^gjYC9`=y+;@O0UrMDEG#bx3 zlJK&t10A}#7=kCER6M%^MmZuU`ZL2(*)UG*$zWqKag0nCKnGwxvMJ^6*p<1dzyE{d z1IOR-s9pmzv;;(BAgmmjbP7G~^)$D5sm7fSPzFfpK?)y|bLiGeB;&mxl0u0n2r)p} zT*QX@>8}0$zHx#lhBhJSWLmXJ#!kJ7N1w=a-@AU~Yn|iB{pJBSuN}I~w)0;ox7)&4^w^3og5+ph0# z51FZ0ZirqiB~gYEq*mTaqMMgMW5v+)3iuvJ*O3ESPGPxMP+Y7N;(!J&LF<9{_^aEU z9~|zGDFAXpoD@0PxSCE&NhcK2NoP2jqcj{wVEvll6^p{!Dmy^F!i-?R3eJ&cFkg@K zcguJzcC@s5{^F{-FHplS#6Z`6zxmL?8>S}(hFfw3fLqnr|A#S&-^J z+T6SXhCXg?Y2L=1@A7p@V{^kX(c9l+oCNb3`?`;ligS!S#ckTW@wl8DHiZl)G|k4- zeKlGKav@}Um$y^eJKLn8ss2P@)ZoP2zN4R@;C+0IAUM~ZPG@9sX@RGy#7WyM9B|;x zs8a|cs<2V7s;QLv#yS;1SV-oPP7a5iPOMTmQt=dg{UXILEY3?X6j0`~+N|5K_r3e? zzyHiw%Un5}2v=2CN?k*(5&|K=QAwOGCo9Qo5b%cE?bc`KX2l=yDf8Gg+ji`I9~JKG zc)O${G zGO4MnRzhc2hfL2*8R+P0SKjAv+IPa%m*~)!WF&H7YRIG$rR613U0bDu_Kr3}_3xQ> zyJ6#NbmOZslChq`Vmg(S77H(TBH?s9_aI$=#GSh)+0*Fba3bs}@knKLMIu1)d%^oF zaC53g>U#m*?Qsb&cRX-;oO=-vPNBDFq;kRF-7x%z3r>_*mc<0_MIge!9s77w?L<2+ z+_un$ppnOA6{Skx-?Cqz(rg1q{of*S@#d*IO{h~qe(o^9K<T2A}!!L`34eF^=E zxj%3fy&MsRMUf^9B({i!h?4|VUL+g%10+Nu*m+Mai zJMo$6@JaBW6=21WkB@s?SBWZAqvj$VuhMlDqobp{HrDeG&&9MH)|}uPx!;!QR=-4-O7K z<#-!9RcJqkFp68z4%Gv`|u{K@=2}P$3G0 zC@2DnjxV#?liTjP5-Usb)$?u1CzA|j=fy%rn}ha!^ub#D(= z0#?>}LEIkS9lxlxw)iiL?pmj9+r7riX4j&t4v1vkwyn7PK^vs12Yvr})OEdO(X9;3 zX0w-Gz@ZEVgRRd3@ZkRYA2*}dZ@lr=)obo?E`^K{VY(>3>jF|pSJc~e2eeF2!+qI-ZfAf@+zl)9bqC7q$!WNfncdGoR)j0_ zGCzgYs|2lEQ8EVIw@{GbX}Zw?wbV#!ksNgYWiAP~f-QcyGyqkGxtaDN#3b&eAoYfT zrZzX#eqzD=RjQ2)6dzcGSsyYWfR$p%g|&cYWTvJL!D4ioz}<}6*8&DUGB@)+9HW_u zd9kUNbp~W$8diE?Au8xb06e0?#{Y^KsI%) z)9LJojky(9mSY4|ue!K15-k3ad$Jr)?Q{(cdB)vYM=+oOhuy+-iGKhi&=iD+daq3Y O0000 + + info.png + close.png + image.png + folder.png + search.png + recovery.png + apply.png + clear.png + reload.png + + diff --git a/data/icons/image.png b/data/icons/image.png new file mode 100644 index 0000000000000000000000000000000000000000..30618c310fb65ea1b2cb66029d00bb14265bf868 GIT binary patch literal 1296 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBgK_U@8vq32_B-=>QlR8JU=vn3tIk~vFxVgD`czAeudHMMG`1$z-1Ox;H1%-r!goTAgL_|bI zMa9I##KpxWBqSsyC8eaKq@|^0WMt&!{g)YR0~)ipFU zG&MD~w6wIfwRLoKbai$0^z`)g^$iRR3=Iv9jEszpjZI8UOifMA%*@Qq%`Ge}EG;dq ztgNi9t!->+2gD8k(A#IyyQ!J3G6&y1Ki&dwYBP z`uZkJm@sM5q-oQp&6qJ`)~s2xXV0ELfBvFHiRX!K7HoQnRDmPUAS=J;>C-XE?v5P`}UnXckbT3d+*-8`}glZc<|ui!-tO^ zJ$n53@slS{o<4p0?Af#D&!4||@#5vnm#<#Edj0zKn>TOXzJ2@d-Mjbi-+%b<;p4}T zpFVy1{Q2{jFJFHA`0?-GzyJULe_Qf%5-`mvmIV0)Gq7@r$|_k}+1WcdIyt+zy19FJ zdU^Z!`uPV0hGjOjO*dGwkR6y-wLM)NLp+YZoqFC+I8fwR{qu8k{W3MDG-$9bGP#)X zLpUi(=|t0mQ%A}_DAw?Wzq|93!DaiqI~prGU3zC}1!msbA}!n#mb<*TpZj0Pj7xsv zZ{}P*yZ8C*&$ah=K9BL9KmRYkg`|T*ZOiUuuGc0jmk4%eXd507)>(1SQ=&fnpwfYu zML*0HB3wdEXEKEze5WVGbYt-pfdhJ~zZSaKOO?bouiB-Y?)-IyciRj$U7e8mGx-`G zn{3fDG7OxWBGoo~zvS5i9ygiaMzA+B^HycvyK48#VVCO9iyMT#E)bDAbF(v7L1wp& z=AK&pxh~ro*HtJwoMXN@RpbK4-@{YwW*xkJGveEWXw_f?hfL$QR=2A*}%X@MzQL==Pph39nZ!l}T9Z%4%#``DOh(EmYgr;Nbe^JaB?OHA(-<~E!S zIrZ3_?Vu@}M|`d4wXU+QSHCw+eQT%@y6$j*7t8h6+w|&hHogeev~TWS^KH-C&1;sw zKInF{eoyhUxtEidx$SN&GS1%i^}uTOu=(yQryP^Y&_8S!y#33|-TuP&S4kqEWxu7wDjy!N|NZ{cf&$luGds@)y^qWkyjWc= zy?V7RgHptiUnk=g4odCR^}MeWYItp`uROzYv0lG#bN_MAak1BLQ;$*tm1~}^elF{r G5}E)$=o?`G literal 0 HcmV?d00001 diff --git a/data/icons/info.png b/data/icons/info.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5e130563cb21e21c4f2f1772385e5f571e4ed0 GIT binary patch literal 2498 zcmV;z2|f0SP)r<@fS)C`L;j(EBFtorkBTS-i%t2z%G7PV|mfL)p8Y z^>qlWzwKTp!oCNlq?=)^o>Re}etP5M6JCARJm2$!nT_S9OO7^sr(YRbQrk&3?;jx9 z$5f>FG(lh;+sMCYAB|C({Of4*`@#nCvlfLO$noPF|9tZ+uQ-&4k6*Y~5||@Zi6lyr zdW?|hLxlWe4}pc-3HUb<@To^&{YD%1VGPEKBtrzpj-S6*@)AcJruRkC%Rj)K=8jjn<t0QVlRrQz^g(x%&HuMotK8mpo%aTI@L@_qf%o$ zYOLI+hQ(C#ZMV82^uYSSzQV1H_RW#0R#Njw?pdxQ#KTZ{Y>+T_l|xsR#G`aj<2cl! zn#3ndrh0`dj%IbR@wTy!IN1@oPep{(h)0?3a4YPEX2l?LcR5S{cP;E0b*!*_7*N|f z;#B(+#(8|5%;TN>sn3pmt9A?!Z@LBCOWDCCzY7js>>05Fxd&wg+qD_*T{#RZsfSOz zckIE>9w>`CGjLYk$8-;<7_me~_@c8ku^z2C(1S2l zs(!(yBvk9?!54vhjx61&B<`h3a4BXF=Yl@qrAxtj{ZX)rJq&hnr$CV12F^tTT61_% z4@-9plF$8j9oCzeI{GR+Wt!vZ7ukHRQ1A}&b4BVuULHMP6#=CGNg{qT>ilK z0v~Zdhz<{uz>5Ac@t~*iiw>R88z*}EzWyJWo@s6!b57}3J_v%mfiYobNk5bxA0$c@ zVX#QMRSZA7n>8PLvWh-8_`sADGmW>8YlC3eXQjAaG%M)qEKMm&<{UZ`sS#_CU9LBQ&dYW6@OB1NA z*O7|#kE>dAxNVy`;Z zl-xIgR|S}L)1G@W|G4>FBUiO&M}op8zOrh=WiBe4U*#fp*N zz|MCPvyE4<4`WyZJ$>rG_c%T!G(P5D=2we(bRXM@I>91QH<-t_Li)b;5eX!0y-G|s zNwJ?btf?2Cs107`R+o*JP7gbzQbP$HI>B_a3?!HOMkElNa~|8VpEb~n z{_^JG#|?7bwfaKyws7lVLE4Q3%;L3&Ii2Z&VYqD`&w|zZb6~nf0l`Hb&~SQyn9;f} zoajN2+5zu)Z9Ayd7aA;2TNa1uuR5!;7tvXbYu652+8`iTHsS@Rq{;lfTu!Qv^%FeT zx%=hBbmJ9_*BbW89iYGRjOuBN!Vo>J%U5wPz2VxpheP+Yd0ZQqY#trP8|AQhTkAa^ za;R^U^og4 z*0;c>M(KzIRBFQH?7l(_m+pmWYfiz8wO7G#qXOec1!|)9my0Bd$Bc5gtbW*f+OlNL z)Md>>wh1`Htzf7D2J56?5p@hC=R28xrJ5-@aE)*x_QT|*63~x2kNp^@6;KN`srK-* zRwa>mJL<71_$%=X9C5B;#09l=JSE?t0E7Esy$q&BoP`O0-wWfzw~GG~uz>IYWgq++B{n%?{ zdgMhiE%E}H9(|eqFU9uJagz_ZQNuXmq8c^7mtUxjjEo-m%yP}=uX0PPrY}9E;wI81 z-ayT+m3^;3PF_+gOrsjFa*L}zw~qb{wZ~+B$&w|1oI7{!bN>GR@7Oqp8@y?kn*G)M zgPq)X8L`=-ATy}&^w@hKriHmD?h%U|HgO8#5GNyFEjZZowp~UpYM~}-qX*Ur1P2E{ zOo?9d^Yi0?*KZ&$*k6Kk%ryI^`e7fVbruHKHK4 zTV%v+gNzu&N||X<*O;l1H-L3)!#<3`SR8|6Kk%r$f?NWx#s0{R8mOgt1#~rQ;HkOku%BGcdFyi&PvTsYB&SzwiCsRK|w+9`uh5QNrk3RA(QK~ z78vAW;~Khfio^2QFZi2FKj5YBeV3Q>-#59rrx94kHtd_iT@iz^I0nZe2XY}Na-#@gIgf8X-)@%aeFZ|>Wv6b3g$jzD)p=r2qf` M07*qoM6N<$f|s=4NdN!< literal 0 HcmV?d00001 diff --git a/data/icons/recovery.png b/data/icons/recovery.png new file mode 100644 index 0000000000000000000000000000000000000000..5f91cc62f91e0618cd4bcd407c361b56f479f3fa GIT binary patch literal 2786 zcmV<83LW){P)EX>4Tx04R}tkv&MmKpe$iTct%>1nnRqlA$_T5EXIMDionYs1;guFuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0scmXsb<$WplX(p zP9}tGZdC}rB7{Cf5Wuj+OnpuiQ}7&L_we!cF3z*O&;2h+~SXQNBOx zvch?bvs$UK);;+P!+C9Gnd>x%ki;UEAVPqQ8p^1^LY!8O6ccIMPk8tT9luB}nOtQs zax9<<6_Voz|AXJ%nuW;;Hz}L|x?gPjV+0890?oQ@e;?a+^8^Sy16NwxUu^(0pQP8@ zTI>ku-3BhM+nT%wTc`thv3l_Hp_EWT>mu4RCM> zj20<--Q(S%&ffk#)9UXBAhdFZAWfD3^!cujT8U?2;WIWK~!ko?U`$A6xS8Ue|L6f zcGnNQ>&FsoY_Q!J8_Xj-YzHeLqyZt*N7{%q5=zrjr&3XqMv)Q`@u8N8`YB&Zgw#es z1Su*}rPO?BoCm}SG$u7|s2z}1t+n?#%t4 zd;b4(?wy72ZEkk(ITkI%d(>|lcufsT!SK?@-Ki-*g4R9reV_78fmtVN)PodD+SPiog%KIS{)z?;vx%ko#3zqbCdKRo1Fd_Pzb zkg3-7`5NKbjw5azH!q|!&u$}c=MPu>?!j%l zDzfr6C^Fmx=51`k`xwEVCPs#X#72Ww|BcT6-mCte&YtUypPlWlKm0N6GZ-cYoQXT| zuw_}F3L)kNTuRA}_OIz~ew+OJQ%OllMvnMFnu#6t`w)OcA`~Ym$w(!I!JbR>bVYFI z>|oid2T?VB%5fA$*#ex3&$@_4qeP?8IfFM1gRZX{k$uN0URjJv02#bAdFPQfWE{*m zGI$qx@n+`Gb>;6gpZtnt8y-h@xhFiX>$=Szn>L1FAf;s0s#SAx;KyrX{QAiP)<5(U zFghXDKZjZ9fze)aa&mCrILAA$zRF+gECxqzGvmUA3mAqmLBt8%S+{Q8tjF#a79V~# zh!AzG-mo5r(7_1Kjf&yRcs*I{*uIwDaDa2Y9stgrJ2yeU@k%VDl+35aEWzj9>Ad~E z;N<(C5)OtyxWSBp8BJ`K36^!M858fD5#(q$xp_HkC=B6Nj0xjSpio>KQc5h#nzI)C zfh77*tMm^x^VpVUWZky}8SMvoJM6-h!*D172ppOdU2}sq3T7~&zzN}^v?QJMFGdK3 zlg5LennIIxnyvLkG>-poF?~aw?5GUzgOZXlO_;-2mIO_5;=?cK=y&5*4SboBqCzj( zxdrH|i7@&RNECv2yTTmJx>;=qjF zK&lqOVfbfj7E(%dVUgW9%0ne*sVvVW>pmZ1v;)O7acGN4b;YK{r%t7Tg|L_j|LtDH z^^Y`qdK#&$TtQOuQe;eEnwCw~h!k82xoQ88PVZnhKivkI8JURD>lnHN%NV2ev>F(H zb3PgX$jHbb5C~wJV+HJLQ0H&|_Hkp-&%@>E_;OYw4a>f7XHnoozn3)EHL9x0aGEZL zqr(J8#N8vX5E_tDvT4&McJJPe-|y$pp+m&0d(d!j{6ZGjZw7c|&1nqt_Bc{XyI)KS z8opk{x@%X+TVBM?uFG7$?y@5=RT^c!X;eyyVHoV(xf6h*q9O_k3haR`%fgU?Q`bDa z^Qn`*n<|!NCESmncZPI2ItH*T7Z)%0(mA3{8G(7#fwZ(V+-|ph?eqEYcs%yYi;9Xc zO*7#c)3Rs@B=OPZOdGUmn)dnFwS{F^3|#Nv{1t_8RJp4L5-4;x4M-{3x^*j0Jn;mU zW#RYxsjaQW>2xOa^LRWMhJg?QkHakR1}Jfi`lntAB~NT3H?H$5LsDS?Ao=9l`B`;;0>%jxnvD)D%c8!%o{^D}aaB`LUS6I6X6e$U?BBni)vH&d zC<;Odgb?)g_1TNZJKLJ{Acg4x{&h8r)J#~G#3nbZMQRcUH! zqNb*X=bwKbpU+22OA9qMH2_$aMMFaaue|b#O_dWTPVm-SZ=q?LO~LVINI`vvcRZmG zLM*%n08&y?*uH%`m6erbW@Z9VS67GA=|ok>Qsnvb=jrO|A}1#YDJ9w2*;G_i(A?ZS z8KA_4&Ml|!6#9ZJC44>~FTC)A4Lojf@T#hg-}>2NFD)&lw6v6lh6autIl^>X*vT+V zmPVDSC^S`z#bQ)fS5E*BP*qih)9JMPR#a55WXX~V{WfpjOi4+}g#3TEwjdOW#bWgL z_p^NYa{ISvG)f>4AU{8!0|yS!+}uohdOB;@t{q#fMItyH4m&azFJ8p&_hXvoq*|CR zD)Xk0l#&An4v?RpkJsxZ5C{;9#cc6rW@hr}qmL#$6OBfxuC69IIhjZ#LMRl%?RMjG zxn{NQnvOyz-v*Q1PX<)qV*|Uebx;nbMyBYs^=Gd`gw6(QSTwF|5Rh1nT(=<_4bzaN$ z1>2F8m6ZW-^5jWeE*Ap>1Ei#+@cQeo)6vm^rfIzK#v8P@wo+DB#(VF*H`y%C#{n_v z$K9DYkeZsxQ%^m`%P+r-s;U@J;_$_2{~euIux5V5+av zVm$EamJ*g_QC(fl@#DuC8X7{=G&|G8^`R(=y=IDojxXlsvt6CGkj+&68#itwH#e8M zx;hj^v0HqG$5&y%&i`?z7OGAAVQZ=|3nAFOdpAdq9<^uq&b|xvMPs@MOi7`;X&}De zJ$?GLO`Z7yo^2r;cbqznwzRZNcsMC3iLG0=a^%Pnu3o+Rt^L1z=LE+K*w5P9+WrxV zM7|S$k~^JF^78V24%EgYpsA{A)8byYTM^LW5l8}_0hZjNl=mLTKL{8=H*hpgAr0^V ouDECSu*HB;AaLvad;3=H|8JCBM`sk}(f|Me07*qoM6N<$f{`m&S^xk5 literal 0 HcmV?d00001 diff --git a/data/icons/reload.png b/data/icons/reload.png new file mode 100644 index 0000000000000000000000000000000000000000..34da27c2919b8ebb1a215db1d678536b923b61db GIT binary patch literal 2388 zcmV-a39I&rP)ch$eDs}1Jw)|NKebvm<@-Te=%e~>|J%m|Zse`d1hm_K9yLyZzr&Zkw8dAshu z5|Y4Tc`O&MKIf9neg(~A%~DdkFYsB$96tQxZ>w?^ zyKm>29t-+thHoBh81FpTFfJ7TjvLI1O&Gs6>+PmQfEAJ4e?tSgbQg&0?K&cV{8?Tf z&4`oCME5?wuIQ0=-MY{6UObQ$?K*Sw%_oM=AFB6+l@ObZYU2B-i3GghlHk`su098{ zA)X5+;mv%kifjhoCqQ-v7QlG(G)~XOSCyHihdXzyaGdV$)7guLVwSZoyed1JR6(wx z$cwkRWN#`L)?taPMq$QbC=yu}LI3@2XrI$rT;g@VfoPn6S=wJG!k(GoI=Dl$qhSdt z^|12_C!gip<6?Ba&m~(EsE{Tw3T+>z;Z5N6h)ecIl#nUwGarb`__OFN3sF3K?1&W! zvFoqpb3Gn5lTC3=U>MRURE!X_$VTva*hutj-&PG`Mf)(5-3PW?dzX10(W)Q`oahRGe6!U{m$v+DzZ1Z2@HZ7Is~JT2C%^F z>#>VqycOq>i2MzM_LmUW{4k@0*!?k;WM^U%=m$0k9Ts95+5jtqYGD51XN7&Wg|&!r zw~Gl`wPH!)!^_Fd-jgSbGCmv7x)7tH_$rdeFI1ClGxU zvNp0F^gRo>uGG{(z1Wm37{J#tMwoSr@H$Ys^s#ZMVPZT@ zl+dpd)Ts3F7bSZV8bJGctw8i{)Pf}nkv{XTT1qp*iJ9gxM3Aik7{InzEE&IAun5D< zUoVHLTkpOTR}S3GOmg~}>4?@(H_FA@uM|v!>OkvSEg#y*s^B_Udg^VpxN^{bX5Pgf zbX;ozY>KP{g>&y~2kOU$beZ8bz2mOa6CC@Fx8ywB6;}^hS8G6100x*%Rp&e|%{-rY zz5rrUOfDD0gmqcZMP>c1(S9$cBOAR{N}qaNWr@?RaixY28i0|14UDnmJmN1K{)RWr zs6M)pSAMl8rG!ezW?h#&F!HMbb>C_}bgx!}l0z=^RtY)qyL{C5(T;MVQ?7HR8q|EM z_%OI$4YT(>Eo>3?du;u5V?tN?Rf0N-RrTh__(nC1Hs{=QaU44dY7cs>kk3O1_39TU_7hv1= zHJ}q6!tyOgu@#``$&b&A)FGzEqk;D=iv&!D)<)qKBdrCC&sVMHl?(poHg8v zK*h5h6x{hSzE%ly_B<|RCb`dOcL38oXU^UCxX=h~3i73l8WbJ!p^tXBU7Kx+DFkhn zz3>^-a0cYv%K6aqtpH7jZ0M~Nda%9v#npmOXgTJfO~JmX2I;e(KvXWkvh4@iRF4I- z_C2rAWS4`SYZ)Jk?q#qkv=T9J}qTtc+F|M zVZ7E3GfjP<<6QxAE@dDq08_jMFL%uWarFpiW}bhKUm(7xq(+3hk$Wz+CC~@;O*ITP zNxH*K@aX-0r?Fb7i-K(~D7uw_jB_a;axSH?GqRG%pLkI#q7ZQ4yMn;JVhVvrluo~? z-5ya%WYLx&AJn(JO*V+DhT4AreP}j&(d4ZUi_|?!LE5QAAWCkfa5S!pD4lv$C$1Xi z+@^BEJ`!r-9;#D9!_`wNjd__%bOMcM;= z(PdI5n5R9IJ@mMAy>B+LORFLle&wy&TZU-4m%_Mpw?B88!=Br&NBz%=!Dknrc-y3o znOzIkW5Ka3rRZ*rrtzx6GOrE~QkH{ZW-<<&|=fb!goNh5A}}>}{i{eDLx1 zKYH-@_kFaZqm*s4LB*vQ7TXqeD5@@4mY1?YN-H`{c+br#Zln9N5;*F(9#qi5LYtxv zfr?ji$b$g}30cf^kCBWJTc<8lZDtK%#otlInb34EhDA1ou;7w#pth(@72Glhu;Okp zlP^uDK7}S8>5BAVM(v#{r4bsp`1q@412*my4uvrPV!=1aC;yA!e)4EzxmO7+I`*nb zQav<=8M|u|^+kOOBZwc7E=YIeABYGuNOOdUw2$3bD^9+)V;<;xlz_ZF268^1%xfdG zFC9b2YC7b?Sc|OOUQ2y1;WcUq0Io&3lU{{^cc`-#cA#zSGFHy3{7M zO??P&2Ka;cIuqi^V5V!INu7qQUL(5HC1ikJ_}gjQ@7GA5d`r~rzYvyt0WtP2qO|;5 z&F%}4KJ}JN+j_UAzi!yupO!cVcN%KCirS#IsLijL7q)moCDn~L)qRj*$T&uHnhZ10 zz`Vz_qqZVT9Kyw9yfVdPz3;am$IirWVLhfFwqXXc%ox$>(sT@OY#*MjZhR%v!R-g0 zv#!Wbh$PaFm(AhGNMsa`k-Tq%d3_{#V|aqm*5B<9+WrNSutoz1{|uJ^00009HlsjI8qgJdQ%u{XQVwr$(CZQHhOV~uc=f1KGkGa2?Yins2)|LR%I^UEYp z=TqnNYuEYqRe@-&@xLsJ|8a4g16}b5;uI|`MvR$t-_bMpH|mVL(8vpjr2{-k5j-`O zWSx|7l-86p0;x41p_xGvMlnXI{++g)r(+;18U|0W}tD|_tp57zao_CBb@0+ zt@@1K@^1my|4gz`3UY<*I(GfG_hm-UFhT)bvEwi<*|HzI51vA+6Ce>1lu|e*hh-V? z@-|it_u=+8TZNl%S`N291ZtNt@$(PMsohr+$HYrkenx-zUkY&OS>(}SM7~-bT7uGT z9>5aG@ym;M;}2KvL$ebjRuq(RO$pJQ5uGytlT$s_k<^bRaZN&8hoS5mxZADP;EuQ1 zgxtV+2#@Z>vG2S`+gyEPDLj17*f}6rxaZ7S?qJ!`JW;;%vZo2+2MA=+AYaDIVNq7OV1+7QmWET%|PY@ZIG(V$#9>C2i)a63~jh2 zw3ImZxtA!S#P?T!PCw$D0_=SnSs?`W^={a}oK?3WhfX%|z297oKyvgH3|S+MWXF{I zogEEtKVwX1mYj1%Db>g%rKCa#nx-imaN_DstIa1Io+VYnZ8lV4c<9|Sh}9cG2*=3h zUa3t}zhcd2^!v^Yz?%u(d6di)dwcSwo8O0BGupyWFWv)14AhN|hy+G{JzDx+$_ul( zoSoQ)m71oR4h;|6iw75bwrN{ZYcex4BMy&@1Sd|MkbdY}cdSm`O(fA>W~IZH_vY}R zJFUgg+Vc^QU4x@P`K-zrxZ|qN>r2miA=`TrA0m|H3m4p-HQEvWaMb}&!$w_Ai@h_> z_x6PSTl1xSGB)(~~0yN2WG!-8{YZ zz=5Av~@?PLkY(TSmx(T@!`j^(e2}h{nk7Zv$9-RxPmY0VF3pv<5G@IkOh6 z!Y{8J!O4a|PBxPxP4=_BV(8*Rp%9cjFUlA5k!{;aE|*Jgb*o!18eTHIq;Jup+q$lM z6UJB`08djfH8C-{W8c1g|99EN7msb;wk^yjV?zUE{H5BdvU{9Y!!6ER4!d^=Y2tcdBH6}tN6UZEp7EL!;#Sjrkepcp(>2!$%ELkZDdhl+%;4Op_w@8^5JF5xQP7%cHd{xIu%k@-zxMs+J+~d^Z1rFR z+$*7H(=BlN>dhYn@Z|*`%!PtHptNKa*Ah5#Y8slFFvA(KBU*Xr$E+-$dJ4^Tx8DkU$LQf}2+w{WdeLWpo2C#~1(>8e#LRIOb04`9{L zD-Nc{8@@g~I)ixn6l&++i6p5mZGQq;yPy`>@+7i8PT;uxOVR9vX!eu?t5u+U;y?xZ{k`aY~&Fl~R2fOkJkw=`>A` z8K@z#~TBmF2+Y*x9eDwtQ#yr$pm(>AQQj!3II<&V}K;Z%Pq&2AcQyD z0Xnfp4l&t@HCI;3g)m<%hSg#vsMN}H5OuHW7hE^8EK9Yd)UFxp@sVRkDW%7HS1hR_ zrFCjjD~%zzT{kY~ijkYkMcwd12$iNnb*pXL(s2UWZ<=Yh zCW#}X$dqa7D4D%ah$}p=8oH%iSSl5>@4In#_KJAnkU^B5@l!}4VC3>hHOO}#L7X!N z5GnG8?aTo%3V=|lnKffOj<9VG4n%s#WFtzRuPO!Z|0>FlfqVNsa@Q zI>bm4Vw#4qEHkqux~q3;S0>H2rm57>QbMN*K#1Z>4+6OQj9Ng0B(d)UQq3Jba?|MU zypV;Fl+r9uZmt48+$_A5GJ{C<*jTFLEd22Buw1cXg`A$AmRTR4>srO4mvI*6V6~JP zu#;xNCAXR6oT&;I4q;q627%TJDisi^rZmC`GMym++JPTHYYETguno=}uIhwvZ5W19 zOlj^iiYcZE zq1qI)eVkG0Sp)ieYKW@MJl5;`z2*XMz~blbLV?BNf8IL*2V zVdI$@Bea#7c1RE~!V*rEQZz{f)mjl-1-GntIiqAK5Kx>tdK{FH(+iqLDaU(Tq2MBk zkwyuY_gj$E)a$Jyk4V#$$13L8jyVk}@hQDF9Icbt*;#5?7Cm{g$*R>VJ9_jebDK@p za2(qGOgl66GiTs|4te*tq?9Z-dw7Vcw7;)p0a}7mjnk(mh1U893j%n^_w_MGNbA(` zQHU@?-Qy@1EmkX$2bJ2#mIXm*$WR)MBrywFC?1BCbDtVUhZ?OGYqg5Zah%L8#+NwV zR>D!%-Z_WC?>EG6X0m*t2WDqLhq3`A7Q1f&m61JWog| zj~+P*f2xU!t5NkRv5Wcg+UT;Ew_0tx)owe@=0uLiF-?-B8!ijqtqwEIkY%rR4;7eU z7~Sw$O=z>3TGP{w?0YRo9ldlNkES19sn@JQI{<-3=!ZBy+8~_jC!f`|(L4Q7rzY^W z14qY|h+;HPO=Ha>0)v6n>(0Gaw*UCD#_Vja(U^57W@hpkD^HR%3vILO{^_}DnpyA+ z&Pr3(nF^h3oVe|ojw|>5?tE{2`@6hS#Tc|h*dzrZ8kcW5fT`4KJ?`iFSLfuU{&V-F zqn2g#-1cT`SaF~ZvtGmgaRRELWe|*y@>MSsJr^7-I)%tC6k^L#f^$zgN@-+@Ij3RR zFuHv{=?JUU81=}uuRTYHjfdxoHM2J_NskeNFyNZQqu6(J3ST)rpmT2dlNW8?`P{Px z_{;-HO$0dEU-isQ>xM{iQ5{yjf@`K2l2mIQ$1+Ix=g0f*_eEw~v29zzB9>HKX$vL- z8Pe`-(*?kRKdv!Hx4eTeqbFCc*nLJD1sa1gf{DonuGoD7-pwD1xVj1-|J*lqxm0-9 zrJHxY=B%#^edYe-*3&*N9jX_|rZoe^E_(15*D&E5m<|}yC`xsj$VBK}k+QY`_6flX z<5~rI9kptzHM>;D&ATb7DsHK4dO1dFtObioKmn(-@SFFIAt)_HYtd~mG&BeyQhf3Y z-&W)e-L_4O4W2r@)2$^jn zj)|5^NvR1yOxv-TYiM`~kYfp;HJ}u-F@}97X2E&~v0bi$$ts zaHs&$8agvFw>lxV?LVzsaZ32$GQ_zOe3A9CDH~q?T8PDq7b6h@U-;?|(wyr&`RYA~ zzIN7Er{DZ$Li;Ymdz&#{U~xv)50%-H-XaL4xK;#zDSh3hG1CmN|JbxV(MagNjuoxm zu#9^J%SePqstKk;6UUp*96+()qQ9>faV+rVZ~s(S27UORL&tx7PVNtU_cp|ta`1(A ziU-F6W-V{1zOv2oITNmv**1^}iB1@27MN~FYHT)vRvNB}T^xAa+jmzVO(}Wi9XD0k zhC!#Cq#B7N7;777#LgT*7o@kR2VoTB8{hwBq8aXY`0%OUo;ARHeg0nL7D0lS3PtXa zDil(!twe%x0%b5HoD$!l`hdytsb~EbU&FkeEb6V^6Cht*(&GkqJ-<98RR)m)CuTVk zG6yi{o>~=t5aT;P`AtlTyz9uZ@ypI0V1Xi;Fi(prl>x=cw;hZ3-DOj4IB!!Dry9p* z4KO2j14OM_M!OT?hrj$o7>DWYM<*w@Eev4cVaYsqMdq#kMt{BXRzm6HHY_i>Lp9q8 z6OB_X4#(+2>p6yGv&}=Kv(rpM|E^na!*7O}nmFiuW`) ze_yTQ%JoaUY9ur!I;=Z0-7v5#r6OjUZT$L=SF}W!-g0z$`XB&358#{ypC6k46&ru{ zn04(q=3vpyztghK>e``FRcV4|M6c^g`8kMkv4GL>DRt>pI}RN?HE{s|ky-I`9G=Y& z_)nULVUlU)jiqAoX*);KTMhP>9Mfd9(d04-3>qIX3Nj2j5Atx-FMS-1)%3y z{SC{^X=eIYfaP_c(VZaNlZe!pNtreeview ); + + gtk_list_store_append ( GTK_LIST_STORE ( model ), &iter ); + gtk_list_store_set ( GTK_LIST_STORE ( model ), &iter, + COL_NUM, ind, + COL_SET, set, + COL_FTP, descr, + -1 ); +} + +static void formats_win_toggled ( G_GNUC_UNUSED GtkCellRendererToggle *toggle, char *path_str, FormatsWin *win ) +{ + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model ( win->treeview ); + + GtkTreePath *path = gtk_tree_path_new_from_string ( path_str ); + gtk_tree_model_get_iter ( model, &iter, path ); + + gboolean toggle_item; + gtk_tree_model_get ( model, &iter, COL_SET, &toggle_item, -1 ); + gtk_list_store_set ( GTK_LIST_STORE ( model ), &iter, COL_SET, !toggle_item, -1 ); + + gtk_tree_path_free ( path ); +} + +static GtkScrolledWindow * formats_win_create_treeview_scroll ( FormatsWin *win ) +{ + GtkScrolledWindow *scroll = (GtkScrolledWindow *)gtk_scrolled_window_new ( NULL, NULL ); + gtk_scrolled_window_set_policy ( scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + gtk_widget_set_visible ( GTK_WIDGET ( scroll ), TRUE ); + + GtkListStore *store = gtk_list_store_new ( COL_ALL, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_STRING ); + + win->treeview = (GtkTreeView *)gtk_tree_view_new_with_model ( GTK_TREE_MODEL ( store ) ); + gtk_widget_set_visible ( GTK_WIDGET ( win->treeview ), TRUE ); + + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + struct Column { const char *name; const char *type; uint8_t num; } column_n[] = + { + { "Num", "text", COL_NUM }, + { "Set", "active", COL_SET }, + { "Type", "text", COL_FTP } + }; + + uint8_t c = 0; for ( c = 0; c < COL_ALL; c++ ) + { + if ( c == COL_SET ) + renderer = gtk_cell_renderer_toggle_new (); + else + renderer = gtk_cell_renderer_text_new (); + + if ( c == COL_SET ) g_signal_connect ( renderer, "toggled", G_CALLBACK ( formats_win_toggled ), win ); + + column = gtk_tree_view_column_new_with_attributes ( column_n[c].name, renderer, column_n[c].type, column_n[c].num, NULL ); + gtk_tree_view_append_column ( win->treeview, column ); + } + + gtk_container_add ( GTK_CONTAINER ( scroll ), GTK_WIDGET ( win->treeview ) ); + g_object_unref ( G_OBJECT (store) ); + + return scroll; +} + +static void formats_win_save ( G_GNUC_UNUSED GtkButton *button, FormatsWin *win ) +{ + g_signal_emit_by_name ( win, "formats-set-data", SG_SAVE, G_OBJECT ( win->treeview ) ); + + gtk_widget_destroy ( GTK_WIDGET ( win ) ); +} + +static void formats_win_reset ( G_GNUC_UNUSED GtkButton *button, FormatsWin *win ) +{ + g_signal_emit_by_name ( win, "formats-set-data", SG_RESET, G_OBJECT ( win->treeview ) ); +} + +static void formats_win_restore ( G_GNUC_UNUSED GtkButton *button, FormatsWin *win ) +{ + g_signal_emit_by_name ( win, "formats-set-data", SG_RESTORE, G_OBJECT ( win->treeview ) ); +} + +static void formats_win_create_buttons ( GtkBox *h_box, FormatsWin *win ) +{ + // const char *labels[] = { "Reset", "Restore", "Ok" }; + const char *labels[] = { "/gres/clear.png", "/gres/reload.png", "/gres/apply.png" }; + const void *funcs[] = { formats_win_reset, formats_win_restore, formats_win_save }; + + uint8_t c = 0; for ( c = 0; c < G_N_ELEMENTS ( labels ); c++ ) + { + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource ( labels[c], NULL ); + GdkPixbuf *pixbuf_scale = gdk_pixbuf_scale_simple ( pixbuf, 16, 16, GDK_INTERP_BILINEAR ); + GtkImage *image = (GtkImage *)gtk_image_new_from_pixbuf ( pixbuf_scale ); + + GtkButton *button = (GtkButton *)gtk_button_new (); // gtk_button_new_with_label ( labels[c] ); + gtk_button_set_image ( button, GTK_WIDGET ( image ) ); + + if ( pixbuf ) g_object_unref ( pixbuf ); + if ( pixbuf ) g_object_unref ( pixbuf_scale ); + + g_signal_connect ( button, "clicked", G_CALLBACK ( funcs[c] ), win ); + + gtk_widget_set_visible ( GTK_WIDGET ( button ), TRUE ); + gtk_box_pack_start ( h_box, GTK_WIDGET ( button ), TRUE, TRUE, 0 ); + } +} + +static void formats_win_create ( FormatsWin *win ) +{ + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource ( "/gres/recovery.png", NULL ); + + GtkWindow *window = GTK_WINDOW ( win ); + // gtk_window_set_title ( window, "Formats" ); + gtk_window_set_default_size ( window, 500, 300 ); + gtk_window_set_icon ( window, pixbuf ); + + if ( pixbuf ) g_object_unref ( pixbuf ); + + GtkBox *v_box = (GtkBox *)gtk_box_new ( GTK_ORIENTATION_VERTICAL, 0 ); + GtkBox *h_box = (GtkBox *)gtk_box_new ( GTK_ORIENTATION_HORIZONTAL, 0 ); + + gtk_box_set_spacing ( v_box, 10 ); + gtk_box_set_spacing ( h_box, 10 ); + + gtk_widget_set_visible ( GTK_WIDGET ( v_box ), TRUE ); + gtk_widget_set_visible ( GTK_WIDGET ( h_box ), TRUE ); + + gtk_box_pack_start ( v_box, GTK_WIDGET ( formats_win_create_treeview_scroll ( win ) ), TRUE, TRUE, 0 ); + + formats_win_create_buttons ( h_box, win ); + + gtk_box_pack_start ( v_box, GTK_WIDGET ( h_box ), FALSE, FALSE, 0 ); + + gtk_container_set_border_width ( GTK_CONTAINER ( v_box ), 10 ); + gtk_container_add ( GTK_CONTAINER ( window ), GTK_WIDGET ( v_box ) ); + + gtk_window_present ( GTK_WINDOW ( win ) ); +} + +static void formats_win_init ( FormatsWin *win ) +{ + formats_win_create ( win ); +} + +static void formats_win_finalize ( GObject *object ) +{ + G_OBJECT_CLASS ( formats_win_parent_class )->finalize ( object ); +} + +static void formats_win_class_init ( FormatsWinClass *class ) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + + oclass->finalize = formats_win_finalize; + + g_signal_new ( "formats-set-data", G_TYPE_FROM_CLASS ( class ), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_OBJECT ); +} + +FormatsWin * formats_win_new ( void ) +{ + FormatsWin *win = g_object_new ( FORMATS_TYPE_WIN, NULL ); + + return win; +} diff --git a/gtk/src/formats-win.h b/gtk/src/formats-win.h new file mode 100644 index 0000000..0a5e651 --- /dev/null +++ b/gtk/src/formats-win.h @@ -0,0 +1,28 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#pragma once + +#include + +#define FORMATS_TYPE_WIN formats_win_get_type () + +enum res_n +{ + SG_SAVE, + SG_RESET, + SG_RESTORE, + SG_ALL +}; + +G_DECLARE_FINAL_TYPE ( FormatsWin, formats_win, FORMATS, WIN, GtkWindow ) + +FormatsWin * formats_win_new ( void ); + +void formats_win_treeview_append ( uint , gboolean , const char *, FormatsWin * ); diff --git a/gtk/src/grecovery-app.c b/gtk/src/grecovery-app.c new file mode 100644 index 0000000..06d95ac --- /dev/null +++ b/gtk/src/grecovery-app.c @@ -0,0 +1,48 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#include "grecovery-app.h" +#include "grecovery-win.h" + +struct _GRecoveryApp +{ + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE ( GRecoveryApp, grecovery_app, GTK_TYPE_APPLICATION ) + +static void grecovery_app_activate ( GApplication *app ) +{ + grecovery_win_new ( GRECOVERY_APP ( app ) ); +} + +static void grecovery_app_init ( G_GNUC_UNUSED GRecoveryApp *app ) +{ + +} + +static void grecovery_app_finalize ( GObject *object ) +{ + G_OBJECT_CLASS ( grecovery_app_parent_class )->finalize ( object ); +} + +static void grecovery_app_class_init ( GRecoveryAppClass *class ) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + G_APPLICATION_CLASS (class)->activate = grecovery_app_activate; + + object_class->finalize = grecovery_app_finalize; +} + +GRecoveryApp * grecovery_app_new ( void ) +{ + return g_object_new ( GRECOVERY_TYPE_APP, "application-id", "org.gtk.grecovery", "flags", G_APPLICATION_NON_UNIQUE, NULL ); +} + diff --git a/gtk/src/grecovery-app.h b/gtk/src/grecovery-app.h new file mode 100644 index 0000000..64951fb --- /dev/null +++ b/gtk/src/grecovery-app.h @@ -0,0 +1,19 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#pragma once + +#include + +#define GRECOVERY_TYPE_APP grecovery_app_get_type () + +G_DECLARE_FINAL_TYPE ( GRecoveryApp, grecovery_app, GRECOVERY, APP, GtkApplication ) + +GRecoveryApp * grecovery_app_new ( void ); + diff --git a/gtk/src/grecovery-win.c b/gtk/src/grecovery-win.c new file mode 100644 index 0000000..13f7144 --- /dev/null +++ b/gtk/src/grecovery-win.c @@ -0,0 +1,415 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#include "grecovery-win.h" +#include "recovery.h" + +enum cols_n +{ + COL_NUM, + COL_FLG, + COL_FTP, + COL_SYS, + COL_FSZ, + COL_LBL, + NUM_COLS +}; + +struct _GRecoveryWin +{ + GtkWindow parent_instance; + + GtkEntry *entry_save; + GtkTreeView *treeview; + GtkTreeSelection *selection; + + GtkComboBoxText *combo_disk; + GtkComboBoxText *combo_type; + GtkComboBoxText *combo_whole; + + GtkLabel *prg_label; + GtkProgressBar *prg_bar; + + Recovery *recovery; + + uint src_update; + ulong disk_signal_id; + ulong part_signal_id; +}; + +G_DEFINE_TYPE ( GRecoveryWin, grecovery_win, GTK_TYPE_WINDOW ) + +static void grecovery_win_about ( GtkWindow *window ) +{ + GtkAboutDialog *dialog = (GtkAboutDialog *)gtk_about_dialog_new (); + gtk_window_set_transient_for ( GTK_WINDOW ( dialog ), window ); + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource ( "/gres/recovery.png", NULL ); + + gtk_about_dialog_set_logo ( dialog, pixbuf ); + gtk_window_set_icon ( GTK_WINDOW ( dialog ), pixbuf ); + + if ( pixbuf ) g_object_unref ( pixbuf ); + + // Gui authors + const char *authors[] = { "Stepan Perun", " ", NULL }; + + // PhotoRec authors + const char *photorec[] = { "Christophe Grenier", " ", NULL }; + + // All sources authors + const char *authors_all[] = { "Gary S. Brown", "Hans Reiser", "Ingo Molnar", "Gadi Oxman", "Klaus Halfmann", "Anton Altaparmakov", "Lode Leroy", "Richard Russon", "Tomasz Kojm", "Peter Turczak", "Simson Garfinkel", "Nick Schrader", "James Holodnak", "Dmitry Brant", "Free Software Foundation Inc.", "International Business Machines Corp.", " ", NULL }; + + gtk_about_dialog_add_credit_section ( dialog, "PhotoRec", photorec ); + gtk_about_dialog_add_credit_section ( dialog, "All sources", authors_all ); + + gtk_about_dialog_set_program_name ( dialog, "GRecovery" ); + gtk_about_dialog_set_version ( dialog, "21.8" ); + gtk_about_dialog_set_license_type ( dialog, GTK_LICENSE_GPL_2_0 ); + gtk_about_dialog_set_authors ( dialog, authors ); + gtk_about_dialog_set_website ( dialog, "https://github.com/vl-nix/grecovery" ); + gtk_about_dialog_set_copyright ( dialog, "Copyright 2021 GRecovery" ); + gtk_about_dialog_set_comments ( dialog, "Data Recovery Utility\nBase in PhotoRec" ); + + gtk_dialog_run ( GTK_DIALOG (dialog) ); + gtk_widget_destroy ( GTK_WIDGET (dialog) ); +} + +static void grecovery_win_message_dialog ( const char *f_error, const char *file_or_info, GtkMessageType mesg_type, GtkWindow *window ) +{ + GtkMessageDialog *dialog = ( GtkMessageDialog *)gtk_message_dialog_new ( + window, GTK_DIALOG_MODAL, + mesg_type, GTK_BUTTONS_CLOSE, + "%s\n%s", f_error, file_or_info ); + + gtk_dialog_run ( GTK_DIALOG ( dialog ) ); + gtk_widget_destroy ( GTK_WIDGET ( dialog ) ); +} + +static void grecovery_win_stop ( GRecoveryWin *win ) +{ + win->src_update = 0; + + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_disk ), TRUE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->treeview ), TRUE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_type ), TRUE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_whole ), TRUE ); + + recovery_search_update ( win->prg_label, win->prg_bar, win->recovery ); +} + +static gboolean grecovery_win_timeout_update ( GRecoveryWin *win ) +{ + recovery_search_update ( win->prg_label, win->prg_bar, win->recovery ); + + if ( recovery_done ( win->recovery ) ) { grecovery_win_stop ( win ); return FALSE; } + + return TRUE; +} + +static void grecovery_win_search ( GRecoveryWin *win ) +{ + const char *dir = gtk_entry_get_text ( win->entry_save ); + + uint8_t type = (uint8_t)gtk_combo_box_get_active ( GTK_COMBO_BOX ( win->combo_type ) ); + uint8_t whole = (uint8_t)gtk_combo_box_get_active ( GTK_COMBO_BOX ( win->combo_whole ) ); + + if ( dir && !g_file_test ( dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR ) ) + { grecovery_win_message_dialog ( "Dir not found.", dir, GTK_MESSAGE_WARNING, GTK_WINDOW ( win ) ); return; } + + gtk_label_set_text ( win->prg_label, " " ); + gtk_progress_bar_set_fraction ( win->prg_bar, 0 ); + + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_disk ), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->treeview ), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_type ), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET ( win->combo_whole ), FALSE ); + + win->src_update = g_timeout_add ( 250, (GSourceFunc)grecovery_win_timeout_update, win ); + + recovery_search ( type, whole, dir, GTK_WINDOW ( win ), win->recovery ); +} + +static char * grecovery_win_file_open ( const char *path, const char *accept, const char *icon, uint8_t num, GtkWindow *window ) +{ + GtkFileChooserDialog *dialog = ( GtkFileChooserDialog *)gtk_file_chooser_dialog_new ( + " ", window, num, "gtk-cancel", GTK_RESPONSE_CANCEL, accept, GTK_RESPONSE_ACCEPT, NULL ); + + gtk_window_set_icon_name ( GTK_WINDOW ( dialog ), icon ); + + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER ( dialog ), path ); + + gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER ( dialog ), FALSE ); + + char *filename = NULL; + + if ( gtk_dialog_run ( GTK_DIALOG ( dialog ) ) == GTK_RESPONSE_ACCEPT ) + filename = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER ( dialog ) ); + + gtk_widget_destroy ( GTK_WIDGET ( dialog ) ); + + return filename; +} + +static void grecovery_win_signal_file_open ( GtkEntry *entry, GtkEntryIconPosition icon_pos, G_GNUC_UNUSED GdkEventButton *event, GRecoveryWin *win ) +{ + if ( icon_pos == GTK_ENTRY_ICON_SECONDARY ) + { + g_autofree char *file = grecovery_win_file_open ( g_get_home_dir (), "gtk-open", "document-open", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_WINDOW ( win ) ); + + if ( file ) gtk_entry_set_text ( win->entry_save, file ); + } +} + +static void grecovery_win_disk_set ( GRecoveryWin *win ) +{ + g_signal_handler_block ( win->combo_disk, win->disk_signal_id ); + g_signal_handler_block ( win->selection, win->part_signal_id ); + + recovery_set_list_disk ( win->combo_disk, win->recovery ); + recovery_set_list_part ( win->treeview, win->recovery ); + + g_signal_handler_unblock ( win->combo_disk, win->disk_signal_id ); + g_signal_handler_unblock ( win->selection, win->part_signal_id ); +} + +static void grecovery_win_signal_combo_disk_changed ( GtkComboBoxText *combo, GRecoveryWin *win ) +{ + uint act = (uint)gtk_combo_box_get_active ( GTK_COMBO_BOX ( combo ) ); + g_autofree char *text = gtk_combo_box_text_get_active_text ( combo ); + + if ( text && g_str_has_prefix ( "Add disk", text ) ) + { + g_autofree char *file = grecovery_win_file_open ( g_get_home_dir (), "gtk-open", "document-open", GTK_FILE_CHOOSER_ACTION_OPEN, GTK_WINDOW ( win ) ); + + if ( !file ) return; + if ( !recovery_add_disk ( file, win->recovery ) ) return; + + grecovery_win_disk_set ( win ); + } + else + { + recovery_disk_changed ( act, win->recovery ); + recovery_set_list_part ( win->treeview, win->recovery ); + } +} + +static void grecovery_win_signal_tree_part_changed ( GtkTreeSelection *selection, GRecoveryWin *win ) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if ( gtk_tree_selection_get_selected ( selection, &model, &iter ) ) + { + uint order = 0; + gtk_tree_model_get ( model, &iter, COL_NUM, &order, -1 ); + + g_autofree char *n_str = gtk_tree_model_get_string_from_iter ( model, &iter ); + + recovery_part_changed ( ( uint )atoi ( n_str ), order, win->recovery ); + } +} + +static GtkScrolledWindow * grecovery_win_create_treeview_scroll ( GRecoveryWin *win ) +{ + GtkScrolledWindow *scroll = (GtkScrolledWindow *)gtk_scrolled_window_new ( NULL, NULL ); + gtk_scrolled_window_set_policy ( scroll, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + gtk_widget_set_visible ( GTK_WIDGET ( scroll ), TRUE ); + + GtkListStore *store = gtk_list_store_new ( NUM_COLS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + win->treeview = (GtkTreeView *)gtk_tree_view_new_with_model ( GTK_TREE_MODEL ( store ) ); + gtk_widget_set_visible ( GTK_WIDGET ( win->treeview ), TRUE ); + + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + struct Column { const char *name; const char *type; uint8_t num; } column_n[] = + { + { "Num", "text", COL_NUM }, + { "Flags", "text", COL_FLG }, + { "Type", "text", COL_FTP }, + { "System", "text", COL_SYS }, + { "Size", "text", COL_FSZ }, + { "Label", "text", COL_LBL } + }; + + uint8_t c = 0; for ( c = 0; c < NUM_COLS; c++ ) + { + renderer = gtk_cell_renderer_text_new (); + + column = gtk_tree_view_column_new_with_attributes ( column_n[c].name, renderer, column_n[c].type, column_n[c].num, NULL ); + gtk_tree_view_append_column ( win->treeview, column ); + } + + gtk_container_add ( GTK_CONTAINER ( scroll ), GTK_WIDGET ( win->treeview ) ); + g_object_unref ( G_OBJECT (store) ); + + win->selection = (GtkTreeSelection *)gtk_tree_view_get_selection ( win->treeview ); + win->part_signal_id = g_signal_connect ( win->selection, "changed", G_CALLBACK ( grecovery_win_signal_tree_part_changed ), win ); + + return scroll; +} + +static void grecovery_win_srch ( G_GNUC_UNUSED GtkButton *button, GRecoveryWin *win ) +{ + grecovery_win_search ( win ); +} + +static void grecovery_win_info ( G_GNUC_UNUSED GtkButton *button, GRecoveryWin *win ) +{ + grecovery_win_about ( GTK_WINDOW ( win ) ); +} + +static void grecovery_win_frmt ( G_GNUC_UNUSED GtkButton *button, GRecoveryWin *win ) +{ + recovery_formats_win ( win->recovery ); +} + +static void grecovery_win_quit ( G_GNUC_UNUSED GtkButton *button, GRecoveryWin *win ) +{ + gtk_widget_destroy ( GTK_WIDGET ( win ) ); +} + +static void grecovery_win_create_butttons ( GtkBox *h_box, GRecoveryWin *win ) +{ + // const char *labels[] = { "🛈", "🗐", "🔎", "⏻" }; + const char *label_prg[] = { "/gres/info.png", "/gres/image.png", "/gres/search.png", "/gres/close.png" }; + const void *funcs[] = { grecovery_win_info, grecovery_win_frmt, grecovery_win_srch, grecovery_win_quit }; + + uint8_t c = 0; for ( c = 0; c < G_N_ELEMENTS ( label_prg ); c++ ) + { + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource ( label_prg[c], NULL ); + GdkPixbuf *pixbuf_scale = gdk_pixbuf_scale_simple ( pixbuf, 16, 16, GDK_INTERP_BILINEAR ); + GtkImage *image = (GtkImage *)gtk_image_new_from_pixbuf ( pixbuf_scale ); + + GtkButton *button = (GtkButton *)gtk_button_new (); // gtk_button_new_with_label ( labels[c] ); + gtk_button_set_image ( button, GTK_WIDGET ( image ) ); + + if ( pixbuf ) g_object_unref ( pixbuf ); + if ( pixbuf ) g_object_unref ( pixbuf_scale ); + + g_signal_connect ( button, "clicked", G_CALLBACK ( funcs[c] ), win ); + + gtk_widget_set_visible ( GTK_WIDGET ( button ), TRUE ); + gtk_box_pack_start ( h_box, GTK_WIDGET ( button ), TRUE, TRUE, 0 ); + } +} + +static GtkComboBoxText * grecovery_win_create_combo ( const char *text_a, const char *text_b, GRecoveryWin *win ) +{ + GtkComboBoxText *combo = (GtkComboBoxText *) gtk_combo_box_text_new (); + + gtk_combo_box_text_append_text ( combo, text_a ); + gtk_combo_box_text_append_text ( combo, text_b ); + gtk_combo_box_set_active ( GTK_COMBO_BOX ( combo ), 0 ); + + gtk_widget_set_visible ( GTK_WIDGET ( combo ), TRUE ); + + return combo; +} + +static void grecovery_win_create ( GRecoveryWin *win ) +{ + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource ( "/gres/recovery.png", NULL ); + + GtkWindow *window = GTK_WINDOW ( win ); + gtk_window_set_title ( window, "GRecovery" ); + gtk_window_set_default_size ( window, 400, 500 ); + gtk_window_set_icon ( window, pixbuf ); + + if ( pixbuf ) g_object_unref ( pixbuf ); + + GtkBox *v_box = (GtkBox *)gtk_box_new ( GTK_ORIENTATION_VERTICAL, 0 ); + GtkBox *h_box = (GtkBox *)gtk_box_new ( GTK_ORIENTATION_HORIZONTAL, 0 ); + + gtk_box_set_spacing ( v_box, 5 ); + gtk_box_set_spacing ( h_box, 5 ); + + gtk_widget_set_margin_top ( GTK_WIDGET ( v_box ), 10 ); + gtk_widget_set_margin_bottom ( GTK_WIDGET ( v_box ), 10 ); + gtk_widget_set_margin_start ( GTK_WIDGET ( v_box ), 10 ); + gtk_widget_set_margin_end ( GTK_WIDGET ( v_box ), 10 ); + + gtk_widget_set_visible ( GTK_WIDGET ( v_box ), TRUE ); + gtk_widget_set_visible ( GTK_WIDGET ( h_box ), TRUE ); + + win->combo_disk = grecovery_win_create_combo ( "None", "Add disk", win ); + win->disk_signal_id = g_signal_connect ( win->combo_disk, "changed", G_CALLBACK ( grecovery_win_signal_combo_disk_changed ), win ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->combo_disk ), FALSE, FALSE, 0 ); + + gtk_box_pack_start ( v_box, GTK_WIDGET ( grecovery_win_create_treeview_scroll ( win ) ), TRUE, TRUE, 0 ); + + win->prg_label = (GtkLabel *)gtk_label_new ( " " ); + gtk_widget_set_halign ( GTK_WIDGET ( win->prg_label ), GTK_ALIGN_START ); + + win->prg_bar = (GtkProgressBar *)gtk_progress_bar_new (); + + gtk_widget_set_visible ( GTK_WIDGET ( win->prg_label ), TRUE ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->prg_label ), FALSE, FALSE, 0 ); + + gtk_widget_set_visible ( GTK_WIDGET ( win->prg_bar ), TRUE ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->prg_bar ), FALSE, FALSE, 0 ); + + win->combo_type = grecovery_win_create_combo ( "FAT / NTFS ...", "Ext2 - Ext4", win ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->combo_type ), FALSE, FALSE, 0 ); + + win->combo_whole = grecovery_win_create_combo ( "Whole", "Free", win ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->combo_whole ), FALSE, FALSE, 0 ); + + win->entry_save = (GtkEntry *)gtk_entry_new (); + gtk_entry_set_text ( win->entry_save, "Recovery ..." ); + g_object_set ( win->entry_save, "editable", FALSE, NULL ); + gtk_entry_set_icon_from_icon_name ( win->entry_save, GTK_ENTRY_ICON_SECONDARY, "folder" ); + g_signal_connect ( win->entry_save, "icon-press", G_CALLBACK ( grecovery_win_signal_file_open ), win ); + + gtk_widget_set_visible ( GTK_WIDGET ( win->entry_save ), TRUE ); + gtk_box_pack_start ( v_box, GTK_WIDGET ( win->entry_save ), FALSE, FALSE, 0 ); + + grecovery_win_create_butttons ( h_box, win ); + gtk_box_pack_end ( v_box, GTK_WIDGET ( h_box ), FALSE, FALSE, 0 ); + + gtk_container_add ( GTK_CONTAINER ( window ), GTK_WIDGET ( v_box ) ); + + gtk_window_present ( GTK_WINDOW ( win ) ); +} + +static void grecovery_win_init ( GRecoveryWin *win ) +{ + win->src_update = 0; + win->recovery = recovery_new (); + + grecovery_win_create ( win ); + grecovery_win_disk_set ( win ); +} + +static void grecovery_win_finalize ( GObject *object ) +{ + GRecoveryWin *win = GRECOVERY_WIN ( object ); + + if ( win->src_update ) g_source_remove ( win->src_update ); + + recovery_stop ( win->recovery ); + + g_object_unref ( win->recovery ); + + G_OBJECT_CLASS ( grecovery_win_parent_class )->finalize ( object ); +} + +static void grecovery_win_class_init ( GRecoveryWinClass *class ) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + + oclass->finalize = grecovery_win_finalize; +} + +GRecoveryWin * grecovery_win_new ( GRecoveryApp *app ) +{ + return g_object_new ( GRECOVERY_TYPE_WIN, "application", app, NULL ); +} diff --git a/gtk/src/grecovery-win.h b/gtk/src/grecovery-win.h new file mode 100644 index 0000000..7535423 --- /dev/null +++ b/gtk/src/grecovery-win.h @@ -0,0 +1,19 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#pragma once + +#include "grecovery-app.h" + +#define GRECOVERY_TYPE_WIN grecovery_win_get_type () + +G_DECLARE_FINAL_TYPE ( GRecoveryWin, grecovery_win, GRECOVERY, WIN, GtkWindow ) + +GRecoveryWin * grecovery_win_new ( GRecoveryApp * ); + diff --git a/gtk/src/main.c b/gtk/src/main.c new file mode 100644 index 0000000..8c91d12 --- /dev/null +++ b/gtk/src/main.c @@ -0,0 +1,21 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#include "grecovery-app.h" + +int main ( void ) +{ + GRecoveryApp *app = grecovery_app_new (); + + int status = g_application_run ( G_APPLICATION ( app ), 0, NULL ); + + g_object_unref ( app ); + + return status; +} diff --git a/gtk/src/recovery.c b/gtk/src/recovery.c new file mode 100644 index 0000000..c13148c --- /dev/null +++ b/gtk/src/recovery.c @@ -0,0 +1,1057 @@ +/* +* Copyright 2021 Stepan Perun +* +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "recovery.h" +#include "formats-win.h" + +#include "../subprojects/lib/src/dir.h" +#include "../subprojects/lib/src/fat.h" +#include "../subprojects/lib/src/fat_dir.h" +#include "../subprojects/lib/src/file_tar.h" +#include "../subprojects/lib/src/pnext.h" +#include "../subprojects/lib/src/file_found.h" +#include "../subprojects/lib/src/psearch.h" +#include "../subprojects/lib/src/photorec_check_header.h" + +#define READ_SIZE 1024*512 + +extern const arch_fnct_t arch_none; +extern file_enable_t array_file_enable[]; + +extern const file_hint_t file_hint_tar; +extern file_check_list_t file_check_list; + +struct _Recovery +{ + GObject parent_instance; + + disk_t *selt_disk; + partition_t *selt_part; + + list_disk_t *list_disk; + list_part_t *list_part; + + struct ph_param *params; + struct ph_options *options; + + gboolean recovery_done; + gboolean stop_recovery; +}; + +G_DEFINE_TYPE ( Recovery, recovery, G_TYPE_OBJECT ) + +static char * recovery_file_open ( const char *msg, const char *path, const char *accept, const char *icon, uint8_t num ) +{ + GtkFileChooserDialog *dialog = ( GtkFileChooserDialog *)gtk_file_chooser_dialog_new ( + msg, NULL, num, "gtk-cancel", GTK_RESPONSE_CANCEL, accept, GTK_RESPONSE_ACCEPT, NULL ); + + gtk_window_set_icon_name ( GTK_WINDOW ( dialog ), icon ); + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER ( dialog ), path ); + gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER ( dialog ), FALSE ); + + char *filename = NULL; + + if ( gtk_dialog_run ( GTK_DIALOG ( dialog ) ) == GTK_RESPONSE_ACCEPT ) + filename = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER ( dialog ) ); + + gtk_widget_destroy ( GTK_WIDGET ( dialog ) ); + + return filename; +} + +static void recovery_message_dialog ( const char *f_error, const char *file_or_info, GtkMessageType mesg_type, GtkWindow *window ) +{ + GtkMessageDialog *dialog = ( GtkMessageDialog *)gtk_message_dialog_new ( + window, GTK_DIALOG_MODAL, + mesg_type, GTK_BUTTONS_CLOSE, + "%s\n%s", f_error, file_or_info ); + + gtk_dialog_run ( GTK_DIALOG ( dialog ) ); + gtk_widget_destroy ( GTK_WIDGET ( dialog ) ); +} + +static void recovery_no_disk_warn ( GtkWindow *window, Recovery *recovery ) +{ + recovery_message_dialog ( "No harddisk found.", "Root? ... Add disk?", GTK_MESSAGE_WARNING, window ); +} + +static pstatus_t photorec_find_blocksize ( alloc_data_t *list_search_space, Recovery *recovery ) +{ + uint64_t offset = 0; + unsigned char *buffer_start; + unsigned char *buffer_olddata; + unsigned char *buffer; + unsigned int buffer_size; + const unsigned int blocksize = recovery->params->blocksize; + const unsigned int read_size = ( blocksize > 65536 ? blocksize : 65536 ); + + time_t start_time; + time_t previous_time; + + alloc_data_t *current_search_space; + file_recovery_t file_recovery; + + recovery->params->file_nbr = 0; + reset_file_recovery ( &file_recovery ); + file_recovery.blocksize = blocksize; + + buffer_size = blocksize + READ_SIZE; + buffer_start = (unsigned char *)MALLOC(buffer_size); + buffer_olddata = buffer_start; + buffer = buffer_olddata + blocksize; + + start_time = time ( NULL ); + + previous_time = start_time; + memset ( buffer_olddata, 0, blocksize ); + current_search_space = td_list_entry ( list_search_space->list.next, alloc_data_t, list ); + + if ( current_search_space != list_search_space ) + offset = current_search_space->start; + if ( recovery->options->verbose > 0 ) + info_list_search_space ( list_search_space, current_search_space, recovery->params->disk->sector_size, 0, recovery->options->verbose ); + + while ( gtk_events_pending () ) gtk_main_iteration (); + + recovery->params->offset = offset; + recovery->params->disk->pread ( recovery->params->disk, buffer, READ_SIZE, offset ); + + while ( current_search_space != list_search_space ) + { + uint64_t old_offset = offset; + + { + file_recovery_t file_recovery_new; + + if ( file_recovery.file_stat != NULL && file_recovery.file_stat->file_hint == &file_hint_tar && + is_valid_tar_header ( (const struct tar_posix_header *) (buffer-0x200 ) ) ) + { + /* Currently saving a tar, do not check the data for know header */ + } + else + { + const struct td_list_head *tmpl; + file_recovery_new.file_stat = NULL; + + td_list_for_each ( tmpl, &file_check_list.list ) + { + const struct td_list_head *tmp; + const file_check_list_t *tmp2 = td_list_entry_const ( tmpl, const file_check_list_t, list ); + + td_list_for_each ( tmp, &tmp2->file_checks[buffer[tmp2->offset]].list ) + { + const file_check_t *file_check = td_list_entry_const ( tmp, const file_check_t, list ); + + if ( ( file_check->length == 0 || memcmp ( buffer + file_check->offset, file_check->value, file_check->length ) == 0 ) && + file_check->header_check ( buffer, read_size, 1, &file_recovery, &file_recovery_new ) != 0 ) + { + file_recovery_new.file_stat=file_check->file_stat; break; + } + } + + if ( file_recovery_new.file_stat != NULL ) break; + } + + if ( file_recovery_new.file_stat != NULL && file_recovery_new.file_stat->file_hint != NULL ) + { + /* A new file begins, backup file offset */ + current_search_space = file_found ( current_search_space, offset, file_recovery_new.file_stat ); + recovery->params->file_nbr++; + file_recovery_cpy ( &file_recovery, &file_recovery_new ); + } + } + } + + if ( file_recovery.file_stat != NULL ) /* Check for data EOF */ + { + data_check_t res = DC_CONTINUE; + + if ( file_recovery.data_check != NULL ) + res = file_recovery.data_check ( buffer_olddata, 2*blocksize, &file_recovery ); + + file_recovery.file_size += blocksize; + + if ( res==DC_STOP || res==DC_ERROR ) /* EOF found */ + reset_file_recovery ( &file_recovery ); + } + + /* Check for maximum filesize */ + if ( file_recovery.file_stat != NULL && file_recovery.file_stat->file_hint->max_filesize > 0 && file_recovery.file_size >= file_recovery.file_stat->file_hint->max_filesize ) + reset_file_recovery ( &file_recovery ); + + if ( recovery->params->file_nbr >= 10 ) + current_search_space = list_search_space; + else + get_next_sector ( list_search_space, ¤t_search_space, &offset, blocksize ); + + if ( current_search_space == list_search_space ) /* End of disk found => EOF */ + reset_file_recovery(&file_recovery); + else + recovery->params->offset=offset; + + buffer_olddata += blocksize; + buffer += blocksize; + + if ( old_offset + blocksize != offset || buffer + read_size > buffer_start + buffer_size ) + { + memcpy ( buffer_start, buffer_olddata, blocksize ); + buffer_olddata = buffer_start; + buffer = buffer_olddata + blocksize; + + if ( recovery->options->verbose > 1 ) + { + log_verbose ( "Reading sector %10llu/%llu\n", + (unsigned long long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size ), + (unsigned long long)( (recovery->params->partition->part_size-1) / recovery->params->disk->sector_size) ); + } + + if ( recovery->params->disk->pread ( recovery->params->disk, buffer, READ_SIZE, offset ) != READ_SIZE ) + { +#ifdef HAVE_NCURSES_XXX + wmove(stdscr,11,0); + wclrtoeol(stdscr); + wprintw(stdscr,"Error reading sector %10lu\n", + (unsigned long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size) ); +#endif + } + + { + time_t current_time; + current_time = time(NULL); + + if ( current_time > previous_time ) + { + previous_time=current_time; + + while ( gtk_events_pending () ) gtk_main_iteration (); + + if ( recovery->stop_recovery ) + { + log_info("PhotoRec has been stopped\n"); + current_search_space=list_search_space; + } + } + } + } + + } + + free ( buffer_start ); + + return PSTATUS_OK; +} + +static pstatus_t photorec_aux ( alloc_data_t *list_search_space, Recovery *recovery ) +{ + uint64_t offset; + unsigned char *buffer_start; + unsigned char *buffer_olddata; + unsigned char *buffer; + unsigned int buffer_size; + const unsigned int blocksize = recovery->params->blocksize; + const unsigned int read_size = ( blocksize > 65536 ? blocksize : 65536 ); + uint64_t offset_before_back = 0; + unsigned int back = 0; + + time_t start_time; + time_t previous_time; + time_t next_checkpoint; + pstatus_t ind_stop = PSTATUS_OK; + + pfstatus_t file_recovered_old = PFSTATUS_BAD; + alloc_data_t *current_search_space; + file_recovery_t file_recovery; + memset ( &file_recovery, 0, sizeof(file_recovery) ); + reset_file_recovery ( &file_recovery ); + file_recovery.blocksize = blocksize; + + buffer_size = blocksize + READ_SIZE; + buffer_start = (unsigned char *)MALLOC(buffer_size); + buffer_olddata = buffer_start; + buffer = buffer_olddata + blocksize; + + start_time = time(NULL); + previous_time = start_time; + next_checkpoint = ( start_time + 5 ) * 60; + + memset ( buffer_olddata, 0, blocksize ); + current_search_space = td_list_first_entry ( &list_search_space->list, alloc_data_t, list ); + offset = set_search_start ( recovery->params, ¤t_search_space, list_search_space ); + + if ( recovery->options->verbose > 0 ) + info_list_search_space ( list_search_space, current_search_space, recovery->params->disk->sector_size, 0, recovery->options->verbose ); + + if ( recovery->options->verbose > 1 ) + { + log_verbose ( "Reading sector %10llu/%llu\n", + (unsigned long long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size ), + (unsigned long long)( (recovery->params->partition->part_size-1) / recovery->params->disk->sector_size) ); + } + + recovery->params->disk->pread ( recovery->params->disk, buffer, READ_SIZE, offset ); + header_ignored(NULL); + + while ( current_search_space != list_search_space ) + { + uint64_t old_offset = offset; + pfstatus_t file_recovered = PFSTATUS_BAD; + data_check_t data_check_status = DC_SCAN; + +#ifdef DEBUG + log_debug ( "sector %llu\n", + (unsigned long long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size) ); + + if ( !(current_search_space->start <= offset && offset <= current_search_space->end) ) + { + log_critical ( "BUG: offset=%llu not in [%llu-%llu]\n", + (unsigned long long)(offset / recovery->params->disk->sector_size), + (unsigned long long)(current_search_space->start / recovery->params->disk->sector_size), + (unsigned long long)(current_search_space->end / recovery->params->disk->sector_size) ); + + log_close(); + exit(1); + } +#endif + + ind_stop = photorec_check_header ( &file_recovery, recovery->params, recovery->options, list_search_space, buffer, &file_recovered, offset ); + + if ( file_recovery.file_stat != NULL ) + { + /* try to skip ext2/ext3 indirect block */ + if ( (recovery->params->status == STATUS_EXT2_ON || recovery->params->status == STATUS_EXT2_ON_SAVE_EVERYTHING ) && + file_recovery.file_size >= 12*blocksize && ind_block(buffer,blocksize) != 0 ) + { + file_block_append ( &file_recovery, list_search_space, ¤t_search_space, &offset, blocksize, 0 ); + data_check_status = DC_CONTINUE; + + if ( recovery->options->verbose > 1 ) + { + log_verbose ( "Skipping sector %10lu/%lu\n", + (unsigned long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size), + (unsigned long)( (recovery->params->partition->part_size-1) / recovery->params->disk->sector_size) ); + } + + memcpy(buffer, buffer_olddata, blocksize); + } + else + { + if ( file_recovery.handle != NULL ) + { + if ( fwrite ( buffer, blocksize, 1, file_recovery.handle ) < 1 ) + { + log_critical ( "Cannot write to file %s after %llu bytes: %s\n", + file_recovery.filename, (long long unsigned)file_recovery.file_size, strerror(errno) ); + + if( errno == EFBIG ) /* File is too big for the destination filesystem */ + { + data_check_status = DC_STOP; + } + else /* Warn the user */ + { + ind_stop = PSTATUS_ENOSPC; + recovery->params->offset = file_recovery.location.start; + } + } + } + + if ( ind_stop == PSTATUS_OK ) + { + file_block_append ( &file_recovery, list_search_space, ¤t_search_space, &offset, blocksize, 1 ); + + if ( file_recovery.data_check != NULL ) + data_check_status = file_recovery.data_check ( buffer_olddata, 2 * blocksize, &file_recovery ); + else + data_check_status = DC_CONTINUE; + + file_recovery.file_size += blocksize; + + if ( data_check_status == DC_STOP ) + { + if ( recovery->options->verbose > 1 ) log_trace ( "EOF found\n" ); + } + } + } + + if ( data_check_status != DC_STOP && data_check_status != DC_ERROR && file_recovery.file_stat->file_hint->max_filesize > 0 && file_recovery.file_size >= file_recovery.file_stat->file_hint->max_filesize ) + { + data_check_status = DC_STOP; + + log_verbose ( "File should not be bigger than %llu, stop adding data\n", + (long long unsigned)file_recovery.file_stat->file_hint->max_filesize ); + } + + if ( data_check_status != DC_STOP && data_check_status != DC_ERROR && file_recovery.file_size + blocksize >= PHOTOREC_MAX_SIZE_32 && is_fat(recovery->params->partition) ) + { + data_check_status = DC_STOP; + + log_verbose ( "File should not be bigger than %llu, stop adding data\n", + (long long unsigned)file_recovery.file_stat->file_hint->max_filesize ); + } + + if ( data_check_status == DC_STOP || data_check_status == DC_ERROR ) + { + if ( data_check_status == DC_ERROR ) + file_recovery.file_size = 0; + + file_recovered = file_finish2 ( &file_recovery, recovery->params, recovery->options->paranoid, list_search_space ); + + if ( recovery->options->lowmem > 0 ) forget ( list_search_space,current_search_space ); + } + } + + if ( ind_stop != PSTATUS_OK ) + { + log_info ( "PhotoRec has been stopped\n" ); + file_recovery_aborted ( &file_recovery, recovery->params, list_search_space ); + free ( buffer_start ); + return ind_stop; + } + + if ( file_recovered == PFSTATUS_BAD ) + { + if ( data_check_status == DC_SCAN ) + { + if ( file_recovered_old == PFSTATUS_OK ) + { + offset_before_back=offset; + + if ( back < 5 && get_prev_file_header ( list_search_space, ¤t_search_space, &offset ) == 0 ) + { + back++; + } + else + { + back = 0; + get_prev_location_smart ( list_search_space, ¤t_search_space, &offset, file_recovery.location.start ); + } + } + else + { + get_next_sector ( list_search_space, ¤t_search_space, &offset, blocksize ); + + if ( offset > offset_before_back ) back = 0; + } + } + } + else if ( file_recovered == PFSTATUS_OK_TRUNCATED ) /* try to recover the previous file, otherwise stay at the current location */ + { + offset_before_back = offset; + + if ( back < 5 && get_prev_file_header ( list_search_space, ¤t_search_space, &offset) == 0 ) + { + back++; + } + else + { + back = 0; + get_prev_location_smart ( list_search_space, ¤t_search_space, &offset, file_recovery.location.start ); + } + } + + if ( current_search_space == list_search_space ) + { +#ifdef DEBUG_GET_NEXT_SECTOR + log_trace ( "current_search_space==list_search_space=%p (prev=%p,next=%p)\n", + current_search_space, current_search_space->list.prev, current_search_space->list.next ); + + log_trace ( "End of media\n" ); +#endif + + file_recovered = file_finish2 ( &file_recovery, recovery->params, recovery->options->paranoid, list_search_space ); + + if ( file_recovered != PFSTATUS_BAD ) + get_prev_location_smart ( list_search_space, ¤t_search_space, &offset, file_recovery.location.start ); + + if ( recovery->options->lowmem > 0 ) + forget ( list_search_space,current_search_space ); + } + + buffer_olddata += blocksize; + buffer += blocksize; + + if ( file_recovered != PFSTATUS_BAD || old_offset + blocksize != offset || buffer + read_size > buffer_start + buffer_size ) + { + if ( file_recovered != PFSTATUS_BAD ) + memset ( buffer_start, 0, blocksize ); + else + memcpy ( buffer_start, buffer_olddata, blocksize ); + + buffer_olddata = buffer_start; + buffer = buffer_olddata + blocksize; + + if ( recovery->options->verbose > 1 ) + { + log_verbose ( "Reading sector %10llu/%llu\n", + (unsigned long long)( (offset - recovery->params->partition->part_offset) / recovery->params->disk->sector_size ), + (unsigned long long)( (recovery->params->partition->part_size-1) / recovery->params->disk->sector_size) ); + } + + if ( recovery->params->disk->pread ( recovery->params->disk, buffer, READ_SIZE, offset ) != READ_SIZE ) + { + } + + if ( ind_stop == PSTATUS_OK ) + { + const time_t current_time = time(NULL); + + if ( current_time > previous_time ) + { + recovery->params->offset = offset; + previous_time = current_time; + + while ( gtk_events_pending () ) gtk_main_iteration (); + + if ( recovery->stop_recovery ) + { + log_info ( "GRecovery has been stopped\n" ); + + file_recovery_aborted ( &file_recovery, recovery->params, list_search_space ); + free(buffer_start); + + return PSTATUS_STOP; + } + + if ( current_time >= next_checkpoint ) + next_checkpoint = regular_session_save ( list_search_space, recovery->params, recovery->options, current_time ); + } + } + } + + file_recovered_old = file_recovered; + + } + + free ( buffer_start ); + + return ind_stop; +} + +static int photorec ( alloc_data_t *list_search_space, Recovery *recovery ) +{ + pstatus_t ind_stop = PSTATUS_OK; + + const unsigned int blocksize_is_known = recovery->params->blocksize; + + params_reset ( recovery->params, recovery->options ); + recovery->params->dir_num = photorec_mkdir ( recovery->params->recup_dir, recovery->params->dir_num ); + + for ( recovery->params->pass=0; recovery->params->status != STATUS_QUIT; recovery->params->pass++ ) + { + switch ( recovery->params->status ) + { + case STATUS_UNFORMAT: + break; + + case STATUS_FIND_OFFSET: + { + uint64_t start_offset = 0; + + if ( blocksize_is_known > 0 ) + { + ind_stop = PSTATUS_OK; + + if ( !td_list_empty ( &list_search_space->list ) ) + start_offset = ( td_list_entry ( list_search_space->list.next, alloc_data_t, list ) )->start % recovery->params->blocksize; + } + else + { + ind_stop = photorec_find_blocksize ( list_search_space, recovery ); + recovery->params->blocksize = find_blocksize ( list_search_space, recovery->params->disk->sector_size, &start_offset ); + } + + update_blocksize(recovery->params->blocksize, list_search_space, start_offset); + } + break; + + case STATUS_EXT2_ON_BF: + case STATUS_EXT2_OFF_BF: + break; + + default: + ind_stop=photorec_aux ( list_search_space, recovery ); + break; + } + + session_save ( list_search_space, recovery->params, recovery->options ); + + switch ( ind_stop ) + { + case PSTATUS_EACCES: + case PSTATUS_ENOSPC: + { + g_autofree char *directory = recovery_file_open ( "Not enough space! Select Folder", + recovery->params->recup_dir, "gtk-open", "document-open", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ); + + if ( !directory ) + { + recovery->params->status = STATUS_QUIT; + } + else + { + free ( recovery->params->recup_dir ); + recovery->params->recup_dir = g_strconcat ( directory, "/", DEFAULT_RECUP_DIR, NULL ); + recovery->params->dir_num = photorec_mkdir ( recovery->params->recup_dir, recovery->params->dir_num ); + } + } + break; + + case PSTATUS_OK: + status_inc ( recovery->params, recovery->options ); + if ( recovery->params->status == STATUS_QUIT ) unlink ( "photorec.ses" ); + break; + + case PSTATUS_STOP: + recovery->params->status = STATUS_QUIT; + break; + } + + update_stats ( recovery->params->file_stats, list_search_space ); + } + + free_search_space ( list_search_space ); + free_header_check (); + + free ( recovery->params->file_stats ); + recovery->params->file_stats = NULL; + + return 0; +} + +void recovery_search_update ( GtkLabel *prg_label, GtkProgressBar *prg_bar, Recovery *recovery ) +{ + if ( recovery->selt_disk == NULL || recovery->selt_part == NULL ) return; + + const partition_t *partition = recovery->params->partition; + const unsigned int sector_size = recovery->params->disk->sector_size; + + char tmp[128], tmp_a[256]; + + if ( recovery->params->status == STATUS_QUIT ) + { + sprintf ( tmp, "%s", "Recovery completed" ); + } + else if ( recovery->params->status == STATUS_EXT2_ON_BF || recovery->params->status == STATUS_EXT2_OFF_BF ) + { + const unsigned long sectors_remaining = ( recovery->params->offset - partition->part_offset ) / sector_size; + sprintf ( tmp, "Bruteforce %lu sectors remaining (test %u)", sectors_remaining, recovery->params->pass ); + } + else + { + const unsigned long long sector_current = ( recovery->params->offset>partition->part_offset && recovery->params->offset < partition->part_size ? + ( ( recovery->params->offset-partition->part_offset ) / sector_size ) : 0 ); + + const unsigned long long sector_total = partition->part_size / sector_size; + sprintf ( tmp, "Pass %u - Sector %llu / %llu", recovery->params->pass, sector_current, sector_total ); + } + + if ( recovery->params->status==STATUS_FIND_OFFSET ) + sprintf ( tmp_a, "%s %u/10 headers found", tmp, recovery->params->file_nbr ); + else + sprintf ( tmp_a, "%s %u files found", tmp, recovery->params->file_nbr ); + + gtk_label_set_text ( prg_label, tmp_a ); + + if ( recovery->params->status == STATUS_QUIT ) + { + gtk_progress_bar_set_fraction ( prg_bar, 1.0 ); + } + else if ( recovery->params->status == STATUS_FIND_OFFSET ) + { + gtk_progress_bar_set_fraction ( prg_bar, (double)( recovery->params->file_nbr ) / 100 ); + } + else + { + double val = (double)( ( recovery->params->offset - partition->part_offset ) * 100 / partition->part_size ); + gtk_progress_bar_set_fraction ( prg_bar, val / 100 ); + } +} + +gboolean recovery_done ( Recovery *recovery ) +{ + return recovery->recovery_done; +} + +void recovery_stop ( Recovery *recovery ) +{ + recovery->stop_recovery = TRUE; +} + +void recovery_search ( uint8_t ext2, uint8_t free_space, const char *dir, GtkWindow *window, Recovery *recovery ) +{ + if ( recovery->selt_disk == NULL || recovery->selt_part == NULL ) { recovery_no_disk_warn ( window, recovery ); return; } + + if ( !recovery->recovery_done ) { recovery_stop ( recovery ); return; } + + recovery->params->recup_dir = g_strconcat ( dir, "/", DEFAULT_RECUP_DIR, NULL ); + recovery->params->carve_free_space_only = free_space; + recovery->params->disk = recovery->selt_disk; + recovery->params->partition = recovery->selt_part; + + log_partition ( recovery->selt_disk, recovery->selt_part ); + + recovery->options->mode_ext2 = ext2; + + alloc_data_t list_search_space; + TD_INIT_LIST_HEAD ( &list_search_space.list ); + + if ( td_list_empty ( &list_search_space.list ) ) + init_search_space ( &list_search_space, recovery->params->disk, recovery->params->partition ); + + if ( recovery->params->carve_free_space_only > 0 ) + recovery->params->blocksize = remove_used_space ( recovery->params->disk, recovery->params->partition, &list_search_space ); + + recovery->recovery_done = FALSE; + recovery->stop_recovery = FALSE; + + photorec ( &list_search_space, recovery ); + + recovery->recovery_done = TRUE; + + free ( recovery->params->recup_dir ); + recovery->params->recup_dir = NULL; +} + +void recovery_set_list_part ( GtkTreeView *treeview, Recovery *recovery ) +{ + if ( recovery->list_disk == NULL ) return; + + list_part_t *element; + + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model ( treeview ); + + gtk_list_store_clear ( GTK_LIST_STORE ( model ) ); + + for ( element = recovery->list_part; element != NULL; element = element->next ) + { + const partition_t *pt = element->part; + + if ( pt->status == STATUS_EXT_IN_EXT ) continue; + + const arch_fnct_t *arch=pt->arch; + gboolean is_n = FALSE, is_f = FALSE; + char bufa [1024], bufn[256], buff[256]; + + if ( pt->partname[0] != '\0' ) { sprintf ( bufn, "%s", pt->partname ); is_n = TRUE; } + if ( pt->fsname[0] != '\0' ) { sprintf ( buff, "%s", pt->fsname ); is_f = TRUE; } + + sprintf ( bufa, "%s %s", ( is_f ) ? buff : " ", ( is_n ) ? bufn : " " ); + + char buft[8]; buft[0] = '\0'; + sprintf ( buft, " %c ", get_partition_status ( pt ) ); + + char *sizeinfo = g_format_size ( pt->part_size ); + + gtk_list_store_append ( GTK_LIST_STORE ( model ), &iter ); + gtk_list_store_set ( GTK_LIST_STORE ( model ), &iter, + 0, ( pt->order == NO_ORDER ) ? 0 : pt->order, + 1, buft, + 2, ( arch->get_partition_typename ( pt ) != NULL ) ? arch->get_partition_typename ( pt ) : "Unknown", + 3, ( pt->upart_type > 0 ) ? arch_none.get_partition_typename(pt) : " ", + 4, sizeinfo, + 5, bufa, + -1 ); + + free ( sizeinfo ); + } +} + +void recovery_part_changed ( uint num, uint order, Recovery *recovery ) +{ + uint n = 0; + list_part_t *tmp; + + for ( tmp = recovery->list_part; tmp != NULL; tmp = tmp->next ) + { + partition_t *part = tmp->part; + + if ( part->status == STATUS_EXT_IN_EXT ) continue; + + if ( part->order == NO_ORDER ) + { if ( n == num ) recovery->selt_part = part; } + else + { if ( part->order == order ) { recovery->selt_part = part; break; } } + + n++; + } +} + +static void recovery_set_disk ( disk_t *disk, Recovery *recovery ) +{ + if( disk == NULL ) return; + + recovery->selt_disk = disk; + recovery->selt_part = NULL; + + autodetect_arch ( recovery->selt_disk, &arch_none ); + + log_info ( "%s\n", recovery->selt_disk->description_short ( recovery->selt_disk ) ); + + part_free_list ( recovery->list_part ); + recovery->list_part = init_list_part ( recovery->selt_disk, NULL ); + + /* If only whole disk is listed, select it */ + /* If there is the whole disk and only one partition, select the partition */ + if ( recovery->list_part != NULL ) + { + if ( recovery->list_part->next == NULL ) + recovery->selt_part = recovery->list_part->part; + else if ( recovery->list_part->next->next == NULL ) + recovery->selt_part = recovery->list_part->next->part; + } + + log_all_partitions ( recovery->selt_disk, recovery->list_part ); +} + +gboolean recovery_add_disk ( const char *disk, Recovery *recovery ) +{ + gboolean ret = FALSE; + + disk_t *new_disk = NULL; + + recovery->list_disk = insert_new_disk_aux ( recovery->list_disk, file_test_availability ( disk, recovery->options->verbose, + TESTDISK_O_RDONLY | TESTDISK_O_READAHEAD_32K ), &new_disk ); + + if ( new_disk != NULL ) { recovery_set_disk ( new_disk, recovery ); ret = TRUE; } + + return ret; +} + +void recovery_disk_changed ( uint num, Recovery *recovery ) +{ + uint i = 0; + list_disk_t *element_disk; + + for ( element_disk = recovery->list_disk, i = 0; element_disk != NULL; element_disk = element_disk->next, i++ ) + { + if ( i == num ) + { + recovery_set_disk ( element_disk->disk, recovery ); + + return; + } + } +} + +void recovery_set_list_disk ( GtkComboBoxText *combo, Recovery *recovery ) +{ + int i = 0; + list_disk_t *element_disk; + + gtk_combo_box_text_remove_all ( combo ); + + for ( element_disk = recovery->list_disk, i = 0; element_disk != NULL; element_disk = element_disk->next, i++ ) + { + disk_t *disk = element_disk->disk; + + const char *text = disk->description_short ( disk ); + gtk_combo_box_text_append_text ( combo, text ); + + if ( disk == recovery->selt_disk ) gtk_combo_box_set_active ( GTK_COMBO_BOX ( combo ), i ); + } + + if ( !i ) { gtk_combo_box_text_append_text ( combo, "None" ); gtk_combo_box_set_active ( GTK_COMBO_BOX ( combo ), i ); } + + gtk_combo_box_text_append_text ( combo, "Add disk" ); +} + +static void recovery_save_list_formats ( GtkTreeView *treeview, Recovery *recovery ) +{ + uint i = 0; + file_enable_t *file_enable; + + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model ( treeview ); + + if ( !gtk_tree_model_get_iter_first ( model, &iter ) ) return; + + for ( i = 0, file_enable = array_file_enable; file_enable->file_hint != NULL; i++, file_enable++ ) + { + gboolean set = FALSE; + gtk_tree_model_get ( model, &iter, 1, &set, -1 ); + + file_enable->enable = ( set ) ? 1 : 0; + + if ( !gtk_tree_model_iter_next ( model, &iter ) ) break; + } +} + +static void recovery_reset_list_formats ( GtkTreeView *treeview, Recovery *recovery ) +{ + uint i = 0; + file_enable_t *file_enable; + + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model ( treeview ); + + if ( !gtk_tree_model_get_iter_first ( model, &iter ) ) return; + + for ( i = 0, file_enable = array_file_enable; file_enable->file_hint != NULL; i++, file_enable++ ) + { + gtk_list_store_set ( GTK_LIST_STORE ( model ), &iter, 1, FALSE, -1 ); + + if ( !gtk_tree_model_iter_next ( model, &iter ) ) break; + } +} + +static void recovery_restore_list_formats ( GtkTreeView *treeview, Recovery *recovery ) +{ + uint i = 0; + file_enable_t *file_enable; + + GtkTreeIter iter; + GtkTreeModel *model = gtk_tree_view_get_model ( treeview ); + + if ( !gtk_tree_model_get_iter_first ( model, &iter ) ) return; + + for ( i = 0, file_enable = array_file_enable; file_enable->file_hint != NULL; i++, file_enable++ ) + { + gboolean set = ( file_enable->file_hint->enable_by_default ) ? TRUE : FALSE; + + gtk_list_store_set ( GTK_LIST_STORE ( model ), &iter, 1, set, -1 ); + + if ( !gtk_tree_model_iter_next ( model, &iter ) ) break; + } +} + +static void recovery_formats_win_handler ( FormatsWin *frmt, uint8_t num, GObject *obj, Recovery *recovery ) +{ + GtkTreeView *treeview = GTK_TREE_VIEW ( obj ); + + if ( num == SG_SAVE ) recovery_save_list_formats ( treeview, recovery ); + if ( num == SG_RESET ) recovery_reset_list_formats ( treeview, recovery ); + if ( num == SG_RESTORE ) recovery_restore_list_formats ( treeview, recovery ); +} + +void recovery_formats_win ( Recovery *recovery ) +{ + FormatsWin *frmt = formats_win_new (); + g_signal_connect ( frmt, "formats-set-data", G_CALLBACK ( recovery_formats_win_handler ), recovery ); + + uint i = 1; + file_enable_t *file_enable; + + for ( file_enable = array_file_enable; file_enable->file_hint != NULL; file_enable++ ) + { + char descr[128]; + + sprintf ( descr, "%-4s %s", + ( file_enable->file_hint->extension != NULL ? file_enable->file_hint->extension : "" ), file_enable->file_hint->description ); + + gboolean set = ( file_enable->enable ) ? TRUE : FALSE; + + formats_win_treeview_append ( i++, set, descr, frmt ); + } +} + +static void recovery_init_disk ( Recovery *recovery ) +{ + list_disk_t *element_disk; + + const int verbose = 0; + const int testdisk_mode = TESTDISK_O_RDONLY | TESTDISK_O_READAHEAD_32K; + + recovery->list_disk = hd_parse ( NULL, verbose, testdisk_mode ); + + hd_update_all_geometry ( recovery->list_disk, verbose ); + + /* Activate the cache, even if photorec has its own */ + for ( element_disk = recovery->list_disk; element_disk != NULL; element_disk = element_disk->next ) + element_disk->disk = new_diskcache ( element_disk->disk, (uint)testdisk_mode ); + + if ( recovery->list_disk ) recovery_set_disk ( recovery->list_disk->disk, recovery ); +} + +static void recovery_init ( Recovery *recovery ) +{ + recovery->list_disk = NULL; + recovery->selt_disk = NULL; + recovery->list_part = NULL; + recovery->selt_part = NULL; + + recovery->params = ( struct ph_param * )MALLOC ( sizeof ( *recovery->params ) ); + recovery->params->recup_dir = NULL; + recovery->params->cmd_device = NULL; + recovery->params->cmd_run = NULL; + recovery->params->carve_free_space_only = 1; + recovery->params->disk = NULL; + recovery->params->partition = NULL; + + recovery->options = ( struct ph_options * )MALLOC ( sizeof ( *recovery->options ) ); + recovery->options->paranoid = 1; + recovery->options->keep_corrupted_file = 0; + recovery->options->mode_ext2 = 0; + recovery->options->expert = 0; + recovery->options->lowmem = 0; + recovery->options->verbose = 0; + recovery->options->list_file_format = array_file_enable; + reset_array_file_enable ( recovery->options->list_file_format ); + + recovery->recovery_done = TRUE; + recovery->stop_recovery = FALSE; + + recovery_init_disk ( recovery ); +} + +static void recovery_finalize ( GObject *object ) +{ + Recovery *recovery = RECOVERY_OBJECT ( object ); + + free ( recovery->params ); + free ( recovery->options ); + + G_OBJECT_CLASS ( recovery_parent_class )->finalize ( object ); +} + +static void recovery_class_init ( RecoveryClass *class ) +{ + GObjectClass *oclass = G_OBJECT_CLASS (class); + + oclass->finalize = recovery_finalize; +} + +Recovery * recovery_new ( void ) +{ + Recovery *recovery = g_object_new ( RECOVERY_TYPE_OBJECT, NULL ); + + return recovery; +} diff --git a/gtk/src/recovery.h b/gtk/src/recovery.h new file mode 100644 index 0000000..2835f67 --- /dev/null +++ b/gtk/src/recovery.h @@ -0,0 +1,34 @@ +/* +* Copyright 2021 Stepan Perun +* This program is free software. +* +* License: Gnu General Public License GPL-2 +* file:///usr/share/common-licenses/GPL-2 +* http://www.gnu.org/licenses/gpl-2.0.html +*/ + +#pragma once + +#include + +#define RECOVERY_TYPE_OBJECT recovery_get_type () + +G_DECLARE_FINAL_TYPE ( Recovery, recovery, RECOVERY, OBJECT, GObject ) + +Recovery * recovery_new ( void ); + +void recovery_formats_win ( Recovery * ); + +void recovery_disk_changed ( uint , Recovery * ); +void recovery_set_list_disk ( GtkComboBoxText *, Recovery * ); + +void recovery_part_changed ( uint , uint , Recovery * ); +void recovery_set_list_part ( GtkTreeView *, Recovery * ); + +void recovery_stop ( Recovery * ); +void recovery_search ( uint8_t , uint8_t , const char *, GtkWindow *, Recovery * ); +void recovery_search_update ( GtkLabel *, GtkProgressBar *, Recovery * ); + +gboolean recovery_done ( Recovery * ); +gboolean recovery_add_disk ( const char *, Recovery * ); + diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..10c3e32 --- /dev/null +++ b/include/common.h @@ -0,0 +1,667 @@ +/* + + File: common.h + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _COMMON_H +#define _COMMON_H +#ifdef __cplusplus +extern "C" { +#endif +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_NCURSES +#endif +#if defined(__FRAMAC__) && defined(HAVE_STRING_H) +#include +#endif + +typedef struct efi_guid_s efi_guid_t; +struct efi_guid_s +{ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} __attribute__ ((gcc_struct, __packed__)); + +#define DEFAULT_SECTOR_SIZE 0x200u + +#define DISKNAME_MAX 64 +#define DISKDESCRIPTION_MAX 128 +/* PARTITION TYPE */ +#define P_NO_OS 0x00 +#define P_12FAT 0x01 +#define P_16FAT 0x04 +#define P_EXTENDED 0x05 +#define P_16FATBD 0x06 +#define P_NTFS 0x07 +#define P_HPFS 0x07 +#define P_EXFAT 0x07 +#define P_OS2MB 0x0A +#define P_32FAT 0x0B +#define P_32FAT_LBA 0x0C +#define P_16FATBD_LBA 0x0E +#define P_EXTENDX 0x0F +#define P_12FATH 0x11 +#define P_16FATH 0x14 +#define P_16FATBDH 0x16 +#define P_NTFSH 0x17 +#define P_32FATH 0x1B +#define P_32FAT_LBAH 0x1C +#define P_16FATBD_LBAH 0x1E +#define P_SYSV 0x63 +#define P_NETWARE 0x65 +#define P_OLDLINUX 0x81 +#define P_LINSWAP 0x82 +#define P_LINUX 0x83 +#define P_LINUXEXTENDX 0x85 +#define P_LVM 0x8E +#define P_FREEBSD 0xA5 +#define P_OPENBSD 0xA6 +#define P_NETBSD 0xA9 +#define P_HFS 0xAF +#define P_HFSP 0xAF +#define P_SUN 0xBF +#define P_BEOS 0xEB +#define P_VMFS 0xFB +#define P_RAID 0xFD +#define P_UNK 255 +#define NO_ORDER 255 +/* Partition SUN */ +#define PSUN_BOOT 1 +#define PSUN_ROOT 2 +#define PSUN_SWAP 3 +#define PSUN_USR 4 +#define PSUN_WHOLE_DISK 5 +#define PSUN_STAND 6 +#define PSUN_VAR 7 +#define PSUN_HOME 8 +#define PSUN_ALT 9 +#define PSUN_CACHEFS 10 +#define PSUN_LINSWAP P_LINSWAP +#define PSUN_LINUX P_LINUX +#define PSUN_LVM P_LVM +#define PSUN_RAID P_RAID +#define PSUN_UNK 255 + +#define PHUMAX_PARTITION 1 + +#define PMAC_DRIVER43 1 +#define PMAC_DRIVERATA 2 +#define PMAC_DRIVERIO 3 +#define PMAC_FREE 4 +#define PMAC_FWDRIVER 5 +#define PMAC_SWAP 0x82 +#define PMAC_LINUX 0x83 +#define PMAC_BEOS 0xEB +#define PMAC_HFS 0xAF +#define PMAC_MAP 6 +#define PMAC_PATCHES 7 +#define PMAC_UNK 8 +#define PMAC_NewWorld 9 +#define PMAC_DRIVER 10 +#define PMAC_MFS 11 +#define PMAC_PRODOS 12 +#define PMAC_FAT32 13 + +#define PXBOX_UNK 0 +#define PXBOX_FATX 1 + +#define GPT_ENT_TYPE_UNUSED \ + ((const efi_guid_t){le32(0x00000000),le16(0x0000),le16(0x0000),0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}) +#define GPT_ENT_TYPE_EFI \ + ((const efi_guid_t){le32(0xc12a7328),le16(0xf81f),le16(0x11d2),0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}) +/* Extended Boot Partition */ +#define GPT_ENT_TYPE_EBP \ + ((const efi_guid_t){le32(0xbc13c2ff),le16(0x59e6),le16(0x4262),0xa3,0x52,{0xb2,0x75,0xfd,0x6f,0x71,0x72}}) +#define GPT_ENT_TYPE_MBR \ + ((const efi_guid_t){le32(0x024dee41),le16(0x33e7),le16(0x11d3),0x9d,0x69,{0x00,0x08,0xc7,0x81,0xf3,0x9f}}) +#define GPT_ENT_TYPE_FREEBSD \ + ((const efi_guid_t){le32(0x516e7cb4),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_SWAP \ + ((const efi_guid_t){le32(0x516e7cb5),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_UFS \ + ((const efi_guid_t){le32(0x516e7cb6),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_ZFS \ + ((const efi_guid_t){le32(0x516e7cb),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +/* + * The following is unused but documented here to avoid reuse. + * + * GPT_ENT_TYPE_FREEBSD_UFS2 \ + * ((const efi_guid_t){le32(0x516e7cb7),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) + */ + +#define GPT_ENT_TYPE_FREEBSD_VINUM \ + ((const efi_guid_t){le32(0x516e7cb8),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) + + +#define GPT_ENT_TYPE_MS_BASIC_DATA \ + ((const efi_guid_t){le32(0xebd0a0a2),le16(0xb9e5),le16(0x4433),0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}) +#define GPT_ENT_TYPE_MS_LDM_DATA \ + ((const efi_guid_t){le32(0xaf9b60a0),le16(0x1431),le16(0x4f62),0xbc,0x68,{0x33,0x11,0x71,0x4a,0x69,0xad}}) +#define GPT_ENT_TYPE_MS_LDM_METADATA \ + ((const efi_guid_t){le32(0x5808c8aa),le16(0x7e8f),le16(0x42e0),0x85,0xd2,{0xe1,0xe9,0x04,0x34,0xcf,0xb3}}) +#define GPT_ENT_TYPE_MS_RECOVERY \ + ((const efi_guid_t){le32(0xde94bba4),le16(0x06d1),le16(0x4d40),0xa1,0x6a,{0xbf,0xd5,0x01,0x79,0xd6,0xac}}) +#define GPT_ENT_TYPE_MS_RESERVED \ + ((const efi_guid_t){le32(0xe3c9e316),le16(0x0b5c),le16(0x4db8),0x81,0x7d,{0xf9,0x2d,0xf0,0x02,0x15,0xae}}) +#define GPT_ENT_TYPE_MS_SPACES \ + ((const efi_guid_t){le32(0xe75caf8f),le16(0xf680),le16(0x4cee),0xaf,0xa3,{0xb0,0x01,0xe5,0x6e,0xfc,0x2d}}) + +#define GPT_ENT_TYPE_LINUX_DATA \ + ((const efi_guid_t){le32(0x0fc63daf),le16(0x8483),le16(0x4772),0x8e,0x79,{0x3d,0x69,0xd8,0x47,0x7d,0xe4}}) +#define GPT_ENT_TYPE_LINUX_HOME \ + ((const efi_guid_t){le32(0x933ac7e1),le16(0x2eb4),le16(0x4f13),0xb8,0x44,{0x0e,0x14,0xe2,0xae,0xf9,0x15}}) +#define GPT_ENT_TYPE_LINUX_LVM \ + ((const efi_guid_t){le32(0xe6d6d379),le16(0xf507),le16(0x44c2),0xa2,0x3c,{0x23,0x8f,0x2a,0x3d,0xf9,0x28}}) +#define GPT_ENT_TYPE_LINUX_RAID \ + ((const efi_guid_t){le32(0xa19d880f),le16(0x05fc),le16(0x4d3b),0xa0,0x06,{0x74,0x3f,0x0f,0x84,0x91,0x1e}}) +#define GPT_ENT_TYPE_LINUX_RESERVED \ + ((const efi_guid_t){le32(0x8da63339),le16(0x0007),le16(0x60c0),0xc4,0x36,{0x08,0x3a,0xc8,0x23,0x09,0x08}}) +#define GPT_ENT_TYPE_LINUX_SRV \ + ((const efi_guid_t){le32(0x3b8f8425),le16(0x20e0),le16(0x4f3b),0x90,0x7f,{0x1a,0x25,0xa7,0x6f,0x98,0xe8}}) +#define GPT_ENT_TYPE_LINUX_SWAP \ + ((const efi_guid_t){le32(0x0657fd6d),le16(0xa4ab),le16(0x43c4),0x84,0xe5,{0x09,0x33,0xc8,0x4b,0x4f,0x4f}}) + +#define GPT_ENT_TYPE_HPUX_DATA \ + ((const efi_guid_t){le32(0x75894c1e),le16(0x3aeb),le16(0x11d3),0xb7,0xc1,{0x7b,0x03,0xa0,0x00,0x00,0x00}}) +#define GPT_ENT_TYPE_HPUX_SERVICE \ + ((const efi_guid_t){le32(0xe2a1e728),le16(0x32e3),le16(0x11d6),0xa6,0x82,{0x7b,0x03,0xa0,0x00,0x00,0x00}}) + +#define GPT_ENT_TYPE_APPLE_CORE_STORAGE \ + ((const efi_guid_t){le32(0x53746F72),le16(0x6167),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_APFS \ + ((const efi_guid_t){le32(0x7c3457ef),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_BOOT \ + ((const efi_guid_t){le32(0x426f6f74),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_HFS \ + ((const efi_guid_t){le32(0x48465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_LABEL \ + ((const efi_guid_t){le32(0x4c616265),le16(0x6c00),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_RAID \ + ((const efi_guid_t){le32(0x52414944),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_RAID_OFFLINE \ + ((const efi_guid_t){le32(0x52414944),le16(0x5f4f),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_TV_RECOVERY \ + ((const efi_guid_t){le32(0x5265636f),le16(0x7665),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_UFS \ + ((const efi_guid_t){le32(0x55465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) + +#define GPT_ENT_TYPE_SOLARIS_BACKUP \ + ((const efi_guid_t){le32(0x6a8b642b),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_BOOT \ + ((const efi_guid_t){le32(0x6a82cb45),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_ROOT \ + ((const efi_guid_t){le32(0x6a85cf4d),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_SWAP \ + ((const efi_guid_t){le32(0x6a87c46f),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_USR \ + ((const efi_guid_t){le32(0x6a898cc3),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_MAC_ZFS GPT_ENT_TYPE_SOLARIS_USR +#define GPT_ENT_TYPE_SOLARIS_VAR \ + ((const efi_guid_t){le32(0x6a8ef2e9),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_HOME \ + ((const efi_guid_t){le32(0x6a90ba39),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_EFI_ALTSCTR \ + ((const efi_guid_t){le32(0x6a9283a5),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED1 \ + ((const efi_guid_t){le32(0x6a945a3b),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED2 \ + ((const efi_guid_t){le32(0x6a9630d1),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED3 \ + ((const efi_guid_t){le32(0x6a980767),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED4 \ + ((const efi_guid_t){le32(0x6a96237f),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED5 \ + ((const efi_guid_t){le32(0x6a8d2ac7),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) + +#define GPT_ENT_TYPE_BEOS_BFS \ + ((const efi_guid_t){le32(0x42465331),le16(0x3ba3),le16(0x10f1),0x80,0x2a,{0x48,0x61,0x69,0x6b,0x75,0x21}}) + +#define TESTDISK_O_RDONLY 00 +#define TESTDISK_O_RDWR 02 +#define TESTDISK_O_DIRECT 040000 +#define TESTDISK_O_READAHEAD_8K 04 +#define TESTDISK_O_READAHEAD_32K 010 +#define TESTDISK_O_ALL 020 + +enum upart_type { + UP_UNK=0, + UP_APFS, + UP_BEOS, + UP_BTRFS, + UP_CRAMFS, + UP_EXFAT, + UP_EXT2, + UP_EXT3, + UP_EXT4, + UP_EXTENDED, + UP_FAT12, + UP_FAT16, + UP_FAT32, + UP_FATX, + UP_FREEBSD, + UP_F2FS, + UP_GFS2, + UP_HFS, + UP_HFSP, + UP_HFSX, + UP_HPFS, + UP_ISO, + UP_JFS, + UP_LINSWAP, + UP_LINSWAP2, + UP_LINSWAP_8K, + UP_LINSWAP2_8K, + UP_LINSWAP2_8KBE, + UP_LUKS, + UP_LVM, + UP_LVM2, + UP_MD, + UP_MD1, + UP_NETWARE, + UP_NTFS, + UP_OPENBSD, + UP_OS2MB, + UP_ReFS, + UP_RFS, + UP_RFS2, + UP_RFS3, + UP_RFS4, + UP_SUN, + UP_SYSV4, + UP_UFS, + UP_UFS2, + UP_UFS_LE, + UP_UFS2_LE, + UP_VMFS, + UP_WBFS, + UP_XFS, + UP_XFS2, + UP_XFS3, + UP_XFS4, + UP_XFS5, + UP_ZFS}; +typedef enum upart_type upart_type_t; +enum status_type { STATUS_DELETED, STATUS_PRIM, STATUS_PRIM_BOOT, STATUS_LOG, STATUS_EXT, STATUS_EXT_IN_EXT}; +typedef enum status_type status_type_t; +enum errcode_type {BAD_NOERR, BAD_SS, BAD_ES, BAD_SH, BAD_EH, BAD_EBS, BAD_RS, BAD_SC, BAD_EC, BAD_SCOUNT}; +typedef enum errcode_type errcode_type_t; + +#define AFF_PART_BASE 0 +#define AFF_PART_ORDER 1 +#define AFF_PART_STATUS 2 + +#define UNIT_DEFAULT 0 +#define UNIT_SECTOR 1 +#define UNIT_CHS 2 + +typedef struct param_disk_struct disk_t; +typedef struct partition_struct partition_t; +/*@ + predicate valid_partition(partition_t *part) = (\valid_read(part)); + @*/ + +typedef struct CHS_struct CHS_t; +typedef struct +{ + unsigned long int cylinders; + unsigned int heads_per_cylinder; + unsigned int sectors_per_head; + unsigned int bytes_per_sector; /* WARN: may be uninitialized */ +} CHSgeometry_t; + +struct CHS_struct +{ + unsigned long int cylinder; + unsigned int head; + unsigned int sector; +}; + +typedef struct list_part_struct list_part_t; +struct list_part_struct +{ + partition_t *part; + list_part_t *prev; + list_part_t *next; + int to_be_removed; +}; +/*@ + predicate valid_list_part(list_part_t *list) = ((list == \null) || (\valid_read(list) && valid_list_part(list->next))); + @*/ + +typedef struct list_disk_struct list_disk_t; +struct list_disk_struct +{ + disk_t *disk; + list_disk_t *prev; + list_disk_t *next; +}; + +/*@ +inductive ld_reachable{L} (list_disk_t* root, list_disk_t* node) +{ + case root_ld_reachable{L}: + \forall list_disk_t *root; ld_reachable(root,root); + case next_ld_reachable{L}: + \forall list_disk_t *root, *node; \valid(root) ==> ld_reachable(root->next, node) ==> ld_reachable(root,node); +} +*/ + +/*@ predicate ld_finite{L}(list_disk_t* root) = ld_reachable(root,\null); */ + +struct systypes { + const unsigned int part_type; + const char *name; +}; + +struct arch_fnct_struct +{ + const char *part_name; + const char *part_name_option; + const char *msg_part_type; + list_part_t *(*read_part)(disk_t *disk, const int verbose,const int saveheader); + int (*write_part)(disk_t *disk, const list_part_t *list_part, const int ro, const int verbose); + list_part_t *(*init_part_order)(const disk_t *disk, list_part_t *list_part); + /* geometry must be initialized to 0,0,0 in get_geometry_from_mbr()*/ + int (*get_geometry_from_mbr)(const unsigned char *buffer, const int verbose, CHSgeometry_t *geometry); + int (*check_part)(disk_t *disk,const int verbose,partition_t *partition, const int saveheader); + int (*write_MBR_code)(disk_t *disk); + void (*set_prev_status)(const disk_t *disk, partition_t *partition); + void (*set_next_status)(const disk_t *disk, partition_t *partition); + int (*test_structure)(const list_part_t *list_part); + unsigned int (*get_part_type)(const partition_t *partition); + int (*set_part_type)(partition_t *partition, unsigned int part_type); + void (*init_structure)(const disk_t *disk,list_part_t *list_part, const int verbose); + int (*erase_list_part)(disk_t *disk); + const char *(*get_partition_typename)(const partition_t *partition); + int (*is_part_known)(const partition_t *partition); +}; + +typedef struct arch_fnct_struct arch_fnct_t; + +/*@ + predicate valid_arch(arch_fnct_t *arch) = ( + \valid_read(arch) && + (arch->get_geometry_from_mbr==\null || \valid_function(arch->get_geometry_from_mbr)) + ); + @*/ + +struct param_disk_struct +{ + char description_txt[DISKDESCRIPTION_MAX]; + char description_short_txt[DISKDESCRIPTION_MAX]; + CHSgeometry_t geom; /* logical CHS */ + uint64_t disk_size; + char *device; + char *model; + char *serial_no; + char *fw_rev; + const char *(*description)(disk_t *disk); + const char *(*description_short)(disk_t *disk); + int (*pread)(disk_t *disk, void *buf, const unsigned int count, const uint64_t offset); + int (*pwrite)(disk_t *disk, const void *buf, const unsigned int count, const uint64_t offset); + int (*sync)(disk_t *disk); + void (*clean)(disk_t *disk); + const arch_fnct_t *arch; + const arch_fnct_t *arch_autodetected; + void *data; + uint64_t disk_real_size; + uint64_t user_max; + uint64_t native_max; + uint64_t dco; + uint64_t offset; /* offset to first sector, may be modified in the futur to handle broken raid */ + void *rbuffer; + void *wbuffer; + unsigned int rbuffer_size; + unsigned int wbuffer_size; + int write_used; + int autodetect; + int access_mode; + int unit; + unsigned int sector_size; +}; + +/*@ + predicate valid_disk(disk_t *disk) = ((disk == \null) || + (\valid_read(disk) && + \freeable(disk) && + valid_read_string(disk->device) && + \freeable(disk->device) && + \valid_function(disk->clean) && + \valid_function(disk->description) && + (disk->model == \null || \freeable(disk->model)) && + (disk->model == \null || valid_read_string(disk->model)) && + (disk->serial_no == \null || \freeable(disk->serial_no)) && + (disk->fw_rev == \null || \freeable(disk->fw_rev)) && + (disk->data == \null || \freeable(disk->data)) && + (disk->rbuffer == \null || (\freeable(disk->rbuffer) && disk->rbuffer_size > 0)) && + (disk->wbuffer == \null || (\freeable(disk->wbuffer) && disk->wbuffer_size > 0)) && + valid_arch(disk->arch) && + disk->sector_size > 0 + )); +*/ +/*@ predicate valid_list_disk(list_disk_t* root) = ((root == \null) || (\valid_read(root))); */ + +/* TODO predicate valid_list_disk{L}(list_disk_t* root) = + \forall list_disk_t *node; \valid(node) && ld_reachable(root,node) ==> \valid(node->disk); + */ + + +struct partition_struct +{ + char fsname[128]; + char partname[128]; + char info[128]; + uint64_t part_offset; + uint64_t part_size; + uint64_t sborg_offset; + uint64_t sb_offset; + unsigned int sb_size; + unsigned int blocksize; + efi_guid_t part_uuid; + efi_guid_t part_type_gpt; + unsigned int part_type_humax; + unsigned int part_type_i386; + unsigned int part_type_mac; + unsigned int part_type_sun; + unsigned int part_type_xbox; + upart_type_t upart_type; + status_type_t status; + unsigned int order; + errcode_type_t errcode; + const arch_fnct_t *arch; + /* NTFS => utils_cluster_in_use */ + /* ext2/ext3/ext4 */ +#if 0 + int (*is_allocated)(disk_t *disk, const partition_t *partition, const uint64_t offset); + void *free_is_allocated(void); +#endif +}; + +typedef struct my_data_struct my_data_t; +struct my_data_struct +{ + disk_t *disk_car; + const partition_t *partition; + uint64_t offset; +}; + +/*@ + @ requires size > 0; + @ ensures \valid(((char *)\result)+(0..size-1)); + @ ensures zero_initialization: \subset(((char *)\result)[0..size-1], {0}); + @ assigns __fc_heap_status; + @*/ +void *MALLOC(size_t size); + +/*@ + @ assigns \nothing; + @*/ +unsigned int up2power(const unsigned int number); + +/*@ + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(src + (0 .. max_size-1)); + @*/ +void set_part_name(partition_t *partition, const char *src, const unsigned int max_size); + +/*@ + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(src + (0 .. max_size-1)); + @*/ +void set_part_name_chomp(partition_t *partition, const unsigned char *src, const unsigned int max_size); + +/*@ + @ requires valid_read_string(str); + @ ensures \result == \null || valid_read_string(\result); + @*/ +char* strip_dup(char* str); + +/*@ assigns \nothing; */ +time_t date_dos2unix(const unsigned short f_time,const unsigned short f_date); + +void set_secwest(void); + +/*@ assigns \nothing; */ +time_t td_ntfs2utc (int64_t ntfstime); +#ifndef BSD_MAXPARTITIONS +#define BSD_MAXPARTITIONS 8 +#endif +#ifndef OPENBSD_MAXPARTITIONS +#define OPENBSD_MAXPARTITIONS 16 +#endif + +#define __swab16(x) (((((uint16_t)x)&(uint16_t)0xff00)>>8) | \ + (((uint16_t)(x)&(uint16_t)0x00ff)<<8)) + +#define __swab24(x) ((((x) & 0x000000ffUL) << 16) | \ + ((x) & 0x0000ff00UL) | \ + (((x) & 0x00ff0000UL) >> 16)) + +#define __swab32(x) ((((uint32_t)(x)&(uint32_t)0xff000000UL)>>24) | \ + (((uint32_t)(x)&(uint32_t)0x00ff0000UL)>>8) | \ + (((uint32_t)(x)&(uint32_t)0x0000ff00UL)<<8) | \ + (((uint32_t)(x)&(uint32_t)0x000000ffUL)<<24)) + +#define __swab64(x) ((((uint64_t)(x)&(uint64_t)0xff00000000000000ULL)>>56) | \ + (((uint64_t)(x)&(uint64_t)0x00ff000000000000ULL)>>40) | \ + (((uint64_t)(x)&(uint64_t)0x0000ff0000000000ULL)>>24) | \ + (((uint64_t)(x)&(uint64_t)0x000000ff00000000ULL)>>8) | \ + (((uint64_t)(x)&(uint64_t)0x00000000ff000000ULL)<<8) | \ + (((uint64_t)(x)&(uint64_t)0x0000000000ff0000ULL)<<24) | \ + (((uint64_t)(x)&(uint64_t)0x000000000000ff00ULL)<<40) | \ + (((uint64_t)(x)&(uint64_t)0x00000000000000ffULL)<<56)) + +#ifdef TESTDISK_LSB +#define be16(x) (__swab16(x)) +#define be24(x) (__swab24(x)) +#define be32(x) (__swab32(x)) +#define be64(x) (__swab64(x)) +#define le16(x) (x) /* x as little endian */ +#define le24(x) (x) +#define le32(x) (x) +#define le64(x) (x) +#else /* bigendian */ +#define be16(x) (x) +#define be24(x) (x) +#define be32(x) (x) +#define be64(x) (x) +#define le16(x) (__swab16(x)) +#define le24(x) (__swab24(x)) +#define le32(x) (__swab32(x)) +#define le64(x) (__swab64(x)) +#endif +#ifndef HAVE_SNPRINTF +int snprintf(char *str, size_t size, const char *format, ...); +#endif +#ifndef HAVE_VSNPRINTF +#include +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif +#ifndef HAVE_STRNCASECMP +int strncasecmp(const char * s1, const char * s2, size_t len); +#endif +#ifndef HAVE_STRCASESTR +char * strcasestr (const char *haystack, const char *needle); +#endif +#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__) && !defined(__FRAMAC__) +/*@ + @ requires valid_timer: \valid_read(timep); + @ requires \valid(result); + @*/ +struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif +/* + * td_min()/td_max() macros that also do + * strict type-checking.. See the + * "unnecessary" pointer comparison. + * Comes from Linux kernel + */ +#define td_min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define td_max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires valid_read_string(cmd); + @ requires \separated(cmd+(..), current_cmd, *current_cmd); + @ requires strlen(cmd) == n; + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @ ensures \result != 0 ==> *current_cmd == \old(*current_cmd); + @*/ +// ensures \result == 0 ==> *current_cmd == \old(*current_cmd) + n; +// assigns \result \from indirect:(*current_cmd)[0 .. n-1], indirect:cmd[0 ..n-1], indirect:n; +int check_command(char **current_cmd, const char *cmd, const size_t n); + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires \separated(current_cmd, *current_cmd); + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @*/ +void skip_comma_in_command(char **current_cmd); + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires \separated(current_cmd, *current_cmd); + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @*/ +uint64_t get_int_from_command(char **current_cmd); +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..95b5c0e --- /dev/null +++ b/include/config.h @@ -0,0 +1,634 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define to 1 if DFXML log is enabled */ +#define ENABLE_DFXML 1 + +/* Define to 1 if the ncurses mouse interface is enabled */ +/* #undef ENABLE_MOUSE */ + +/* Define to 1 if you have the `assume_default_colors' function. */ +#define HAVE_ASSUME_DEFAULT_COLORS 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `atoll' function. */ +#define HAVE_ATOLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_BYTESWAP_H 1 + +/* Define to 1 if you have the `chdir' function. */ +#define HAVE_CHDIR 1 + +/* Define to 1 if you have the `chmod' function. */ +#define HAVE_CHMOD 1 + +/* Define to 1 if you have the header file. */ +// #define HAVE_CURSES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CYGWIN_FS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CYGWIN_VERSION_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DAL_FILE_DAL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DAL_FILE_H */ + +/* Define to 1 if `block_size' is a member of `dal_t'. */ +/* #undef HAVE_DAL_T_BLOCK_SIZE */ + +/* Define to 1 if `entity' is a member of `dal_t'. */ +/* #undef HAVE_DAL_T_ENTITY */ + +/* Define to 1 if `error' is a member of `dal_t'. */ +/* #undef HAVE_DAL_T_ERROR */ + +/* Define to 1 if `name' is a member of `dal_t'. */ +/* #undef HAVE_DAL_T_NAME */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DDK_NTDDSTOR_H */ + +/* Define to 1 if you have the `delscreen' function. */ +/* #undef HAVE_DELSCREEN */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the `dirname' function. */ +#define HAVE_DIRNAME 1 + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `execv' function. */ +#define HAVE_EXECV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXT2FS_EXT2FS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_EXT2FS_EXT2_FS_H 1 + +/* Define to 1 if you have the `ext2fs_get_generic_bitmap_start' function. */ +#define HAVE_EXT2FS_GET_GENERIC_BITMAP_START 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +#define HAVE_FDATASYNC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FEATURES_H 1 + +/* Define to 1 if you have the `fseeko' function. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fsync' function. */ +#define HAVE_FSYNC 1 + +/* Define to 1 if you have the `ftello' function. */ +#define HAVE_FTELLO 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the `getpwuid' function. */ +#define HAVE_GETPWUID 1 + +/* Define if you have this function */ +/* #undef HAVE_GICONV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GICONV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GLOB_H 1 + +/* Define if you have this function */ +#define HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ICONV_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_JPEGLIB_H 1 + +/* Define to 1 if you have the com_err library (-lcom_err). */ +#define HAVE_LIBCOMM_ERR 1 + +/* Define to 1 if you have the ewf library (-lewf). */ +/* #undef HAVE_LIBEWF */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBEWF_H */ + +/* Define to 1 if you have the `libewf_handle_read_buffer_at_offset' function. + */ +/* #undef HAVE_LIBEWF_HANDLE_READ_BUFFER_AT_OFFSET */ + +/* Define to 1 if libewf_handle_t is available */ +/* #undef HAVE_LIBEWF_HANDLE_T */ + +/* Define to 1 if you have the `libewf_handle_write_buffer_at_offset' + function. */ +/* #undef HAVE_LIBEWF_HANDLE_WRITE_BUFFER_AT_OFFSET */ + +/* Define to 1 if you have the ext2fs library (-lext2fs). */ +#define HAVE_LIBEXT2FS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the jpeg library (-ljpeg). */ +#define HAVE_LIBJPEG 1 + +/* Define to 1 if you have the ntfs library (-lntfs). */ +/* #undef HAVE_LIBNTFS */ + +/* Define to 1 if you have the ntfs3g library (-lntfs3g). */ +#define HAVE_LIBNTFS3G 1 + +/* Define to 1 if you have the reiserfs library (-lreiserfs). */ +/* #undef HAVE_LIBREISERFS */ + +/* Define to 1 if you have the z library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_FS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_HDREG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LINUX_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the `memalign' function. */ +#define HAVE_MEMALIGN 1 + +/* Define to 1 if you have the `memchr' function. */ +#define HAVE_MEMCHR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the `mousemask' function. */ +/* #undef HAVE_MOUSEMASK */ + +/* Define to 1 if you have one of the ncursesw/ncurses/pdcurses/curses + library. */ +// #define HAVE_NCURSES 1 + +/* Define to 1 if you have the header file. */ +// #define HAVE_NCURSESW_CURSES_H 1 + +/* Define to 1 if you have the header file. */ +// #define HAVE_NCURSESW_NCURSES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NCURSES_CURSES_H */ + +/* Define to 1 if you have the header file. */ +// #define HAVE_NCURSES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NCURSES_NCURSES_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NTFS_3G_ATTRIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NTFS_3G_VOLUME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTFS_ATTRIB_H */ + +/* Define to 1 if you have the `ntfs_libntfs_version' function. */ +/* #undef HAVE_NTFS_LIBNTFS_VERSION */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTFS_VERSION_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NTFS_VOLUME_H */ + +/* Define to 1 if you have the `ntfs_volume_startup' function. */ +#define HAVE_NTFS_VOLUME_STARTUP 1 + +/* Define to 0 if off64_t is not available */ +#define HAVE_OFF64_T 1 + +/* Define to 1 if you have the `posix_fadvise' function. */ +#define HAVE_POSIX_FADVISE 1 + +/* Define to 1 if you have the `posix_memalign' function. */ +#define HAVE_POSIX_MEMALIGN 1 + +/* Define to 1 if you have the `pread' function. */ +#define HAVE_PREAD 1 + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have the `pwrite' function. */ +#define HAVE_PWRITE 1 + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `reiserfs_fs_open_fast' function. */ +/* #undef HAVE_REISERFS_FS_OPEN_FAST */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SCSI_SCSI_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCSI_SCSI_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SCSI_SG_H 1 + +/* Define to 1 if you have the `setenv' function. */ +#define HAVE_SETENV 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SETJMP_H 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `signal' function. */ +#define HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `sleep' function. */ +#define HAVE_SLEEP 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcasestr' function. */ +#define HAVE_STRCASESTR 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strptime' function. */ +#define HAVE_STRPTIME 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the `strtoull' function. */ +#define HAVE_STRTOULL 1 + +/* Define to 1 if `dev' is a member of `struct dal_ops'. */ +/* #undef HAVE_STRUCT_DAL_OPS_DEV */ + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if `read_blk64' is a member of `struct struct_io_manager'. */ +#define HAVE_STRUCT_STRUCT_IO_MANAGER_READ_BLK64 1 + +/* Define to 1 if `set_option' is a member of `struct struct_io_manager'. */ +#define HAVE_STRUCT_STRUCT_IO_MANAGER_SET_OPTION 1 + +/* Define to 1 if `write_blk64' is a member of `struct struct_io_manager'. */ +#define HAVE_STRUCT_STRUCT_IO_MANAGER_WRITE_BLK64 1 + +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM_TM_GMTOFF */ + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#define HAVE_ST_BLOCKS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_CYGWIN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISKLABEL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISK_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DKIO_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_UUID_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VTOC_H */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the tinfo library (-ltinfo). */ +#define HAVE_TINFO 1 + +/* Define to 1 if you have the `touchwin' function. */ +/* #undef HAVE_TOUCHWIN */ + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `uuidgen' function. */ +/* #undef HAVE_UUIDGEN */ + +/* Define to 1 if you have the `uuid_create' function. */ +/* #undef HAVE_UUID_CREATE */ + +/* Define to 1 if you have the `uuid_generate' function. */ +#define HAVE_UUID_GENERATE 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UUID_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UUID_UUID_H 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_W32API_DDK_NTDDDISK_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_W32API_WINIOCTL_H */ + +/* Define to 1 if you have the `wctomb' function. */ +#define HAVE_WCTOMB 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINBASE_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDEF_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINIOCTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H 1 + +/* Define if libewf_get_bytes_per_sector takes two parameters. */ +/* #undef LIBEWF_GET_BYTES_PER_SECTOR_HAVE_TWO_ARGUMENTS */ + +/* Define if libewf_get_media_size takes two parameters. */ +/* #undef LIBEWF_GET_MEDIA_SIZE_HAVE_TWO_ARGUMENTS */ + +/* Disable the assert error checking */ +/* #undef NDEBUG */ + +/* Define if ntfs_mbstoucs takes two parameters. */ +#define NTFS_MBSTOUCS_HAVE_TWO_ARGUMENTS 1 + +/* Name of package */ +#define PACKAGE "testdisk" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "grenier@cgsecurity.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "testdisk" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "testdisk 7.2-WIP" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "testdisk" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "7.2-WIP" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define to 1 to record compilation date */ +/* #undef RECORD_COMPILATION_DATE */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Path to sudo for privileged operations */ +/* #undef SUDO_BIN */ + +/* Define for BSD target */ +/* #undef TARGET_BSD */ + +/* Define for LINUX target */ +#define TARGET_LINUX 1 + +/* Define for SOLARIS target */ +/* #undef TARGET_SOLARIS */ + +/* Date of release */ +#define TESTDISKDATE "May 2021" + +/* Define to 1 if your processor stores words with the least significant byte + first (like Intel and VAX, unlike Motorola and SPARC). */ +#define TESTDISK_LSB 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Version number of package */ +#define VERSION "7.2-WIP" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* enable compile-time and run-time bounds-checking, and some warnings */ +#define _FORTIFY_SOURCE 2 + +/* Enable GNU extensions */ +#define _GNU_SOURCE 1 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define for freebsd4 target and progsreiserfs compatibility */ +/* #undef __freebsd__ */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/include/filegen.h b/include/filegen.h new file mode 100644 index 0000000..c8e23af --- /dev/null +++ b/include/filegen.h @@ -0,0 +1,435 @@ +/* + + File: filegen.h + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _TESTDISK_FILEGEN_H +#define _TESTDISK_FILEGEN_H +#ifdef __cplusplus +extern "C" { +#endif +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#include "list.h" +#include + +#if defined(DJGPP) +#define PHOTOREC_MAX_FILE_SIZE (((uint64_t)1<<31)-1) +#else +#define PHOTOREC_MAX_FILE_SIZE (((uint64_t)1<<41)-1) +#endif +#define PHOTOREC_MAX_SIZE_16 (((uint64_t)1<<15)-1) +#define PHOTOREC_MAX_SIZE_32 (((uint64_t)1<<31)-1) +#define PHOTOREC_MAX_SIG_OFFSET 65535 +#define PHOTOREC_MAX_SIG_SIZE 4095 + +typedef enum { DC_SCAN=0, DC_CONTINUE=1, DC_STOP=2, DC_ERROR=3} data_check_t; +typedef struct file_hint_struct file_hint_t; +typedef struct file_stat_struct file_stat_t; +typedef struct file_recovery_struct file_recovery_t; +typedef struct file_enable_struct file_enable_t; + +struct file_hint_struct +{ + const char *extension; + const char *description; + const uint64_t max_filesize; + const int recover; + const unsigned int enable_by_default; + void (*register_header_check)(file_stat_t *file_stat); +}; + +typedef struct +{ + struct td_list_head list; + uint64_t start; + uint64_t end; + file_stat_t *file_stat; + unsigned int data; +} alloc_data_t; + +struct file_enable_struct +{ + const file_hint_t *file_hint; + unsigned int enable; +}; + +struct file_stat_struct +{ + unsigned int not_recovered; + unsigned int recovered; + const file_hint_t *file_hint; +}; + +struct file_recovery_struct +{ + char filename[2048]; + alloc_list_t location; + file_stat_t *file_stat; + FILE *handle; + time_t time; + uint64_t file_size; + const char *extension; + uint64_t min_filesize; + uint64_t offset_ok; + uint64_t offset_error; + uint64_t extra; /* extra bytes between offset_ok and offset_error */ + uint64_t calculated_file_size; + data_check_t (*data_check)(const unsigned char*buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); + /* data_check modifies file_recovery->calculated_file_size, it can also update data_check, file_check, offset_error, offset_ok, time */ + /* side effect for data_check_flv */ + void (*file_check)(file_recovery_t *file_recovery); + void (*file_rename)(file_recovery_t *file_recovery); + uint64_t checkpoint_offset; + int checkpoint_status; /* 0=suspend at offset_checkpoint if offset_checkpoint>0, 1=resume at offset_checkpoint */ + unsigned int blocksize; + unsigned int flags; + unsigned int data_check_tmp; +}; + +typedef struct +{ + struct td_list_head list; + const void *value; + unsigned int length; + unsigned int offset; + int (*header_check)(const unsigned char *buffer, const unsigned int buffer_size, + const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new); + file_stat_t *file_stat; +} file_check_t; + +typedef struct +{ + file_check_t file_checks[256]; + struct td_list_head list; + unsigned int offset; +} file_check_list_t; + +#define NL_BARENL (1 << 0) +#define NL_CRLF (1 << 1) +#define NL_BARECR (1 << 2) + +/*@ + predicate valid_file_hint(file_hint_t *file_hint) = (\valid_read(file_hint) && valid_read_string(file_hint->description)); + + predicate valid_file_stat(file_stat_t *file_stat) = (\valid_read(file_stat) && valid_file_hint(file_stat->file_hint)); + + predicate valid_file_recovery(file_recovery_t *file_recovery) = (\valid_read(file_recovery) && + valid_read_string((const char *)file_recovery->filename) && + (file_recovery->file_stat == \null || valid_file_stat(file_recovery->file_stat)) && + (file_recovery->handle == \null || \valid(file_recovery->handle)) && + (file_recovery->extension == \null || valid_read_string(file_recovery->extension)) && + (file_recovery->data_check == \null || \valid_function(file_recovery->data_check)) && + (file_recovery->file_check == \null || \valid_function(file_recovery->file_check)) && + (file_recovery->file_rename == \null || \valid_function(file_recovery->file_rename)) && + \separated(file_recovery, file_recovery->extension) && + \separated(file_recovery, file_recovery->handle) && + \initialized(&file_recovery->calculated_file_size) && + \initialized(&file_recovery->file_check) && + \initialized(&file_recovery->file_size) && + \initialized(&file_recovery->min_filesize) && + \initialized(&file_recovery->time) + ); + + predicate valid_list_search_space(alloc_data_t *list) = (\valid_read(list) && \valid(list->list.prev) && \valid_read(list->list.next)); + + predicate valid_header_check_param(unsigned char *buffer, unsigned int buffer_size, unsigned int safe_header_only, file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) =( + buffer_size > 0 && + \valid_read(buffer+(0..buffer_size-1)) && + \initialized(buffer+(0..buffer_size-1)) && + valid_file_recovery(file_recovery) && + \valid(file_recovery_new) && + file_recovery_new->blocksize > 0 && + file_recovery_new->blocksize <= buffer_size && + \separated(buffer+(..), file_recovery, file_recovery_new) + ); + + predicate valid_header_check_result(int res, file_recovery_t *file_recovery_new) =( + (res == 0 || res == 1) && + (res != 0 ==> valid_file_recovery(file_recovery_new)) && + (res != 0 ==> (file_recovery_new->file_stat == \null)) && + (res != 0 ==> (file_recovery_new->handle == \null)) + ); + + predicate valid_file_check_param(file_recovery_t *file_recovery) = ( + \valid(file_recovery) && + \valid(file_recovery->handle) && + valid_file_recovery(file_recovery) && + \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source) + ); + + predicate valid_file_check_result(file_recovery_t *file_recovery) = ( + valid_file_recovery(file_recovery) && + \valid(file_recovery->handle) + ); + + predicate valid_data_check_param(unsigned char *buffer, unsigned int buffer_size, file_recovery_t *file_recovery) = ( + buffer_size > 0 && + (buffer_size&1)==0 && + \valid_read(buffer+(0..buffer_size-1)) && + \initialized(buffer+(0..buffer_size-1)) && + \valid(file_recovery) && + valid_file_recovery(file_recovery) && + file_recovery->calculated_file_size <= PHOTOREC_MAX_FILE_SIZE && + \separated(buffer + (..), file_recovery) + ); + + predicate valid_data_check_result(data_check_t res, file_recovery_t *file_recovery) = ( + (res == DC_CONTINUE || res == DC_STOP || res == DC_ERROR) && + valid_file_recovery(file_recovery) + ); + + predicate valid_file_rename_param(file_recovery_t *file_recovery) = ( + \valid(file_recovery) && + valid_file_recovery(file_recovery) && + \separated(file_recovery, &errno, &Frama_C_entropy_source) + ); + predicate valid_file_rename_result(file_recovery_t *file_recovery) = ( + \valid(file_recovery) && + valid_file_recovery(file_recovery) + ); + + predicate valid_register_header_check(file_stat_t *file_stat) = ( + \valid(file_stat) + ); + @*/ +void free_header_check(void); + +/*@ + @ requires \valid(file_recovery); + @ requires \valid(file_recovery->handle); + @ requires valid_file_recovery(file_recovery); + @ requires valid_file_check_param(file_recovery); + @ requires \separated(file_recovery, file_recovery->handle, &errno, &Frama_C_entropy_source); + @ ensures file_recovery->handle == \old(file_recovery->handle); + @ assigns *file_recovery->handle, errno, Frama_C_entropy_source, file_recovery->file_size; + @*/ +// TODO ensures valid_file_check_result(file_recovery); +void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode); + +/*@ + @ requires \valid(handle); + @ requires 0 < footer_length <4096; + @ requires \valid_read((char *)footer+(0..footer_length-1)); + @ requires \separated(handle, (char *)footer + (..), &errno, &Frama_C_entropy_source); + @ assigns *handle, errno, Frama_C_entropy_source; + @*/ +uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const unsigned int footer_length); + +/*@ + @ requires 0 < footer_length < 4096; + @ requires \valid_read((char *)footer+(0..footer_length-1)); + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +void file_search_footer(file_recovery_t *file_recovery, const void*footer, const unsigned int footer_length, const unsigned int extra_length); + +/*@ + @ requires file_recovery->data_check == &data_check_size; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures \result == DC_STOP || \result == DC_CONTINUE; + @ ensures file_recovery->data_check == &data_check_size; + @ assigns \nothing; + @*/ +data_check_t data_check_size(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); + +/*@ + @ requires file_recovery->file_check == &file_check_size; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +void file_check_size(file_recovery_t *file_recovery); + +/*@ + @ requires file_recovery->file_check == &file_check_size_min; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +void file_check_size_min(file_recovery_t *file_recovery); + +/*@ + @ requires file_recovery->file_check == &file_check_size_max; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +void file_check_size_max(file_recovery_t *file_recovery); + +/*@ + requires \valid(file_recovery); + ensures file_recovery->filename[0]=='\0'; + ensures file_recovery->time==0; + ensures file_recovery->file_stat==\null; + ensures file_recovery->handle==\null; + ensures file_recovery->file_size==0; + ensures file_recovery->location.list.prev==&file_recovery->location.list; + ensures file_recovery->location.list.next==&file_recovery->location.list; + ensures file_recovery->location.end==0; + ensures file_recovery->location.data==0; + ensures file_recovery->extension==\null; + ensures file_recovery->min_filesize==0; + ensures file_recovery->calculated_file_size==0; + ensures file_recovery->data_check==\null; + ensures file_recovery->file_check==\null; + ensures file_recovery->file_rename==\null; + ensures file_recovery->offset_error==0; + ensures file_recovery->offset_ok==0; + ensures file_recovery->checkpoint_status==0; + ensures file_recovery->checkpoint_offset==0; + ensures file_recovery->flags==0; + ensures file_recovery->extra==0; + ensures file_recovery->data_check_tmp==0; + assigns file_recovery->filename[0]; + assigns file_recovery->time; + assigns file_recovery->file_stat; + assigns file_recovery->handle; + assigns file_recovery->file_size; + assigns file_recovery->location.list.prev; + assigns file_recovery->location.list.next; + assigns file_recovery->location.end; + assigns file_recovery->location.data; + assigns file_recovery->extension; + assigns file_recovery->min_filesize; + assigns file_recovery->calculated_file_size; + assigns file_recovery->data_check; + assigns file_recovery->file_check; + assigns file_recovery->file_rename; + assigns file_recovery->offset_error; + assigns file_recovery->offset_ok; + assigns file_recovery->checkpoint_status; + assigns file_recovery->checkpoint_offset; + assigns file_recovery->flags; + assigns file_recovery->extra; + assigns file_recovery->data_check_tmp; +*/ +// ensures valid_file_recovery(file_recovery); +void reset_file_recovery(file_recovery_t *file_recovery); + +/*@ + @ requires offset <= PHOTOREC_MAX_SIG_OFFSET; + @ requires 0 < length <= PHOTOREC_MAX_SIG_SIZE; + @ requires offset + length <= PHOTOREC_MAX_SIG_OFFSET; + @ requires \valid_read((const char *)value+(0..length-1)); + @ requires \valid_function(header_check); + @ requires \valid(file_stat); + @*/ +void register_header_check(const unsigned int offset, const void *value, const unsigned int length, + int (*header_check)(const unsigned char *buffer, const unsigned int buffer_size, + const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new), + file_stat_t *file_stat); + +/*@ + @ requires \valid(files_enable); + @*/ +file_stat_t * init_file_stats(file_enable_t *files_enable); + +/*@ + @ requires \valid(file_recovery); + @ requires valid_file_recovery(file_recovery); + @ requires \valid_read((char *)buffer+(0..buffer_size-1)); + @ requires new_ext==\null || valid_read_string(new_ext); + @ ensures valid_file_recovery(file_recovery); + @*/ +int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext); + +/*@ + @ requires \valid(file_recovery); + @ requires new_ext==\null || valid_read_string(new_ext); + @ requires valid_file_recovery(file_recovery); + @ requires \valid_read((char *)buffer+(0..buffer_size-1)); + @ ensures valid_file_recovery(file_recovery); + @*/ +int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext); + +void header_ignored_cond_reset(uint64_t start, uint64_t end); + +/*@ + @ requires file_recovery_new==\null || valid_file_recovery(file_recovery_new); + @*/ +void header_ignored(const file_recovery_t *file_recovery_new); + +/*@ + @ requires separation: \separated(file_recovery, file_recovery->handle, file_recovery_new, &errno); + @ requires \valid_read(file_recovery); + @ requires \valid_read(file_recovery_new); + @ requires valid_file_recovery(file_recovery); + @ requires valid_file_recovery(file_recovery_new); + @ requires \valid_function(file_recovery->file_check); + @ requires \initialized(&file_recovery->file_check); + @ requires \initialized(&file_recovery->handle); + @ ensures \result == 0 || \result == 1; + @*/ +// ensures valid_file_recovery(file_recovery); +// ensures valid_file_recovery(file_recovery_new); +int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new); + +/*@ + requires valid_stream: \valid(stream); + requires whence_enum: whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END; + requires \separated(&errno, stream); + assigns *stream, \result, errno; +*/ +// assigns *stream \from *stream, indirect:offset, indirect:whence; +// assigns \result, errno \from indirect:*stream, indirect:offset, indirect:whence; +int my_fseek(FILE *stream, off_t offset, int whence); + +/*@ + @ requires \valid_read(date_asc + (0 .. 11)); + @ assigns \nothing; + @*/ +time_t get_time_from_YYMMDDHHMMSS(const char *date_asc); + +/*@ + @ requires \valid_read(date_asc + (0 .. 18)); + @ assigns \nothing; + @*/ +time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const unsigned char *date_asc); + +/*@ + @ requires \valid_read(date_asc + (0 .. 16)); + @ assigns \nothing; + @*/ +time_t get_time_from_YYYY_MM_DD_HHMMSS(const char *date_asc); + +/*@ + @ requires \valid_read(date_asc + (0 .. 14)); + @ assigns \nothing; + @*/ +time_t get_time_from_YYYYMMDD_HHMMSS(const char *date_asc); + +/*@ + @ requires \valid_read(list_search_space); + @ requires \valid(current_search_space); + @ requires \valid(offset); + @ requires \separated(list_search_space, current_search_space, offset); + @*/ +void get_prev_location_smart(const alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset, const uint64_t prev_location); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/fnctdsk.h b/include/fnctdsk.h new file mode 100644 index 0000000..0d74bf2 --- /dev/null +++ b/include/fnctdsk.h @@ -0,0 +1,254 @@ +/* + + File: fnctdsk.h + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FNCTDSK_H +#define _FNCTDSK_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ assigns \nothing; + @*/ +unsigned long int C_H_S2LBA(const disk_t *disk_car,const unsigned int C, const unsigned int H, const unsigned int S); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(CHS); + @ assigns \nothing; + @*/ +uint64_t CHS2offset(const disk_t *disk_car, const CHS_t*CHS); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->geom.sectors_per_head > 0; + @ assigns \nothing; + @ ensures 0 < \result <= disk_car->geom.sectors_per_head; + @*/ +unsigned int offset2sector(const disk_t *disk_car, const uint64_t offset); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->geom.sectors_per_head > 0; + @ requires disk_car->geom.heads_per_cylinder > 0; + @ assigns \nothing; + @ ensures \result <= disk_car->geom.heads_per_cylinder; + @*/ +unsigned int offset2head(const disk_t *disk_car, const uint64_t offset); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->geom.sectors_per_head > 0; + @ requires disk_car->geom.heads_per_cylinder > 0; + @ assigns \nothing; + @*/ +unsigned int offset2cylinder(const disk_t *disk_car, const uint64_t offset); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(CHS); + @ requires disk_car->sector_size > 0; + @ requires disk_car->geom.sectors_per_head > 0; + @ requires disk_car->geom.heads_per_cylinder > 0; + @ requires \separated(disk_car, CHS); + @ assigns CHS->cylinder,CHS->head,CHS->sector; + @*/ +void offset2CHS(const disk_t *disk_car,const uint64_t offset, CHS_t*CHS); + +/*@ + @ requires list_disk==\null || valid_disk(list_disk->disk); + @ requires valid_list_disk(list_disk); + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires valid_list_disk(list_disk); + @ requires disk==\null || \separated(disk, \union(list_disk, the_disk)); + @ requires the_disk==\null || (\valid_read(the_disk) && valid_disk(*the_disk) && \separated(the_disk, \union(list_disk, disk))); + @*/ +// ensures \result==\null || (\valid(\result) && valid_disk(\result->disk)); +// ensures valid_list_disk(\result); +// ensures disk==\null ==> \result == list_disk; +// ensures the_disk==\null || (\valid_read(the_disk) && valid_disk(*the_disk)); +list_disk_t *insert_new_disk_aux(list_disk_t *list_disk, disk_t *disk, disk_t **the_disk); + +/*@ + @ requires list_disk==\null || valid_disk(list_disk->disk); + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires valid_list_disk(list_disk); + @ requires (list_disk==\null && disk_car==\null) || \separated(list_disk, disk_car); + @*/ +// ensures \result==\null || (\valid(\result) && valid_disk(\result->disk)); +// ensures disk_car==\null ==> \result == list_disk; +// ensures valid_list_disk(\result); +list_disk_t *insert_new_disk(list_disk_t *list_disk, disk_t *disk_car); + +/*@ + @ requires list_part == \null || \valid(list_part); + @ requires valid_list_part(list_part); + @ requires valid_partition(part); + @ requires \valid(insert_error); + @ requires (list_part==\null && part==\null) || \separated(list_part, part); + @ requires insert_error==\null || \valid(insert_error); + @*/ +// ensures valid_list_part(\result); +list_part_t *insert_new_partition(list_part_t *list_part, partition_t *part, const int force_insert, int *insert_error); + +/*@ + @ requires \valid(list_part); + @ requires valid_list_part(list_part); + @ ensures valid_list_part(\result); + @*/ +list_part_t *sort_partition_list(list_part_t *list_part); + +/*@ + @ requires \valid_read(list_part); + @ requires valid_list_part(list_part); + @ ensures valid_list_part(\result); + @*/ +list_part_t *gen_sorted_partition_list(const list_part_t *list_part); + +/*@ + @ requires \valid(list_part); + @ requires valid_list_part(list_part); + @*/ +void part_free_list(list_part_t *list_part); + +/*@ + @ requires \valid(list_part); + @ requires valid_list_part(list_part); + @*/ +void part_free_list_only(list_part_t *list_part); + +/*@ + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(arch); + @ requires \separated(partition, arch); + @ ensures partition->part_size == 0; + @ ensures partition->sborg_offset == 0; + @ ensures partition->sb_offset == 0; + @ ensures partition->sb_size == 0; + @ ensures partition->blocksize == 0; + @ ensures partition->part_type_i386 == P_NO_OS; + @ ensures partition->part_type_sun == PSUN_UNK; + @ ensures partition->part_type_mac == PMAC_UNK; + @ ensures partition->part_type_xbox == PXBOX_UNK; + @ ensures partition->upart_type == UP_UNK; + @ ensures partition->status == STATUS_DELETED; + @ ensures partition->order == NO_ORDER; + @ ensures partition->errcode == BAD_NOERR; + @ ensures partition->fsname[0] == '\0'; + @ ensures partition->partname[0] == '\0'; + @ ensures partition->info[0] == '\0'; + @ ensures partition->arch == arch; + @*/ + // assigns partition->part_size; + // assigns partition->sborg_offset; + // assigns partition->sb_offset; + // assigns partition->sb_size; + // assigns partition->blocksize; + // assigns partition->part_type_i386; + // assigns partition->part_type_sun; + // assigns partition->part_type_mac; + // assigns partition->part_type_xbox; + // assigns partition->part_type_gpt; + // assigns partition->part_uuid; + // assigns partition->upart_type; + // assigns partition->status; + // assigns partition->order; + // assigns partition->errcode; + // assigns partition->fsname[0]; + // assigns partition->partname[0]; + // assigns partition->info[0]; +void partition_reset(partition_t *partition, const arch_fnct_t *arch); + +/*@ + @ requires \valid_read(arch); + @*/ +// ensures valid_partition(\result); +// ensures \result->arch == arch; +partition_t *partition_new(const arch_fnct_t *arch); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(list_part); + @ requires valid_list_part(list_part); + @*/ +// assigns \nothing; +unsigned int get_geometry_from_list_part(const disk_t *disk_car, const list_part_t *list_part, const int verbose); + +/*@ + @ requires list_disk==\null || \valid(list_disk); + @ requires list_disk==\null || \freeable(list_disk); + @ requires list_disk==\null || \freeable(list_disk->disk); + @ requires list_disk==\null || (list_disk->disk->device == \null || \freeable(list_disk->disk->device)); + @ requires list_disk==\null || (list_disk->disk->model == \null || \freeable(list_disk->disk->model)); + @ requires list_disk==\null || (list_disk->disk->serial_no == \null || \freeable(list_disk->disk->serial_no)); + @ requires list_disk==\null || (list_disk->disk->fw_rev == \null || \freeable(list_disk->disk->fw_rev)); + @ requires list_disk==\null || (list_disk->disk->data == \null || \freeable(list_disk->disk->data)); + @ requires list_disk==\null || (list_disk->disk->rbuffer == \null || \freeable(list_disk->disk->rbuffer)); + @ requires list_disk==\null || (list_disk->disk->wbuffer == \null || \freeable(list_disk->disk->wbuffer)); + @*/ +int delete_list_disk(list_disk_t *list_disk); + +/*@ + @ requires \valid(buffer + (0..99)); + @ ensures valid_string(buffer); + @ assigns buffer[0 .. 99]; + @*/ +void size_to_unit(const uint64_t disk_size, char *buffer); + +/*@ + @ requires \valid_read(list_part); + @ requires valid_list_part(list_part); + @ assigns \nothing; + @*/ +int is_part_overlapping(const list_part_t *list_part); + +/*@ + @ requires \valid(dest); + @ requires \valid_read(src); + @ requires \separated(src, dest); + @ requires valid_partition(src); + @ ensures valid_partition(dest); + @*/ +void dup_partition_t(partition_t *dest, const partition_t *src); + +/*@ + @ requires valid_list_disk(list_disk); + @ assigns \nothing; + @*/ +void log_disk_list(list_disk_t *list_disk); +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/hdaccess.h b/include/hdaccess.h new file mode 100644 index 0000000..81d1c01 --- /dev/null +++ b/include/hdaccess.h @@ -0,0 +1,106 @@ +/* + + File: hdaccess.h + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _HDACCESS_H +#define _HDACCESS_H +#ifdef __cplusplus +extern "C" { +#endif +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->geom.heads_per_cylinder > 0; + @ requires \valid_function(disk_car->pread); + @ ensures valid_disk(disk_car); + @*/ +void hd_update_geometry(disk_t *disk_car, const int verbose); + +/*@ + @ requires list_disk==\null || \valid_read(list_disk); + @*/ +void hd_update_all_geometry(const list_disk_t * list_disk, const int verbose); + +/*@ + @ requires valid_list_disk(list_disk); + @ ensures valid_list_disk(\result); + @*/ +list_disk_t *hd_parse(list_disk_t *list_disk, const int verbose, const int testdisk_mode); + +/*@ + @ requires valid_read_string(device); + @ ensures valid_disk(\result); + @ ensures \result!=\null ==> (0 < \result->geom.cylinders < 0x2000000000000); + @ ensures \result!=\null ==> (0 < \result->geom.heads_per_cylinder <= 255); + @ ensures \result!=\null ==> (0 < \result->geom.sectors_per_head <= 63); + @ ensures valid_disk(\result); + @*/ +disk_t *file_test_availability(const char *device, const int verbose, const int testdisk_mode); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires 0 < disk_car->geom.heads_per_cylinder; + @ requires 0 < disk_car->geom.sectors_per_head; + @ requires 0 < disk_car->sector_size; + @ ensures 0 < disk_car->geom.cylinders < 0x2000000000000; + @ ensures valid_disk(disk_car); + @ assigns disk_car->disk_real_size, disk_car->geom.cylinders, disk_car->disk_size; + @*/ +void update_disk_car_fields(disk_t *disk_car); + +/*@ + @ requires \valid(disk); + @ ensures disk->autodetect == 0; + @ ensures disk->disk_size == 0; + @ ensures disk->user_max == 0; + @ ensures disk->native_max == 0; + @ ensures disk->dco == 0; + @ ensures disk->offset == 0; + @ ensures disk->rbuffer == NULL; + @ ensures disk->wbuffer == NULL; + @ ensures disk->rbuffer_size == 0; + @ ensures disk->wbuffer_size == 0; + @ ensures disk->model == NULL; + @ ensures disk->serial_no == NULL; + @ ensures disk->fw_rev == NULL; + @ ensures disk->write_used == 0; + @ ensures disk->description_txt[0] == '\0'; + @ ensures disk->unit == UNIT_CHS; + @ assigns disk->autodetect, disk->disk_size, disk->user_max, disk->native_max, disk->dco, disk->offset; + @ assigns disk->rbuffer, disk->wbuffer, disk->rbuffer_size, disk->wbuffer_size; + @ assigns disk->model, disk->serial_no, disk->fw_rev, disk->write_used; + @ assigns disk->description_txt[0], disk->unit; + @*/ +void init_disk(disk_t *disk); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \freeable(disk); + @ requires valid_disk(disk); + @*/ +void generic_clean(disk_t *disk); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/hdcache.h b/include/hdcache.h new file mode 100644 index 0000000..d263f4b --- /dev/null +++ b/include/hdcache.h @@ -0,0 +1,38 @@ +/* + + File: hdcache.h + + Copyright (C) 2005 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _HDCACHE_H +#define _HDCACHE_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ ensures \valid(\result); + @*/ +disk_t *new_diskcache(disk_t *disk_car, const unsigned int cache_size_min); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/intrf.h b/include/intrf.h new file mode 100644 index 0000000..dd9cfe3 --- /dev/null +++ b/include/intrf.h @@ -0,0 +1,111 @@ +/* + + File: intrf.h + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _INTRF_H +#define _INTRF_H +#ifdef __cplusplus +extern "C" { +#endif + +struct MenuItem +{ + const int key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */ + const char *name; /* Item name, should be eight characters with current implementation */ + const char *desc; /* Item description to be printed when item is selected */ +}; +#define MAX_LINES 200 +#define BUFFER_LINE_LENGTH 255 +#define MAXIMUM_PARTS 60 + +#define INTER_OPTION_X 0 +#define INTER_OPTION_Y 10 +#define INTER_PARTITION_X 0 +#define INTER_PARTITION_Y 8 +#define INTER_MAIN_X 0 +#define INTER_MAIN_Y 18 +#define INTER_GEOM_X 0 +#define INTER_GEOM_Y 18 +/* Constants for menuType parameter of menuSelect function */ +#define MENU_HORIZ 1 +#define MENU_VERT 2 +#define MENU_ACCEPT_OTHERS 4 +#define MENU_BUTTON 8 +#define MENU_VERT_WARN 16 +#define MENU_VERT_ARROW2VALID 32 +/* Miscellenous constants */ +#define MENU_SPACING 2 +#define MENU_MAX_ITEMS 256 /* for simpleMenu function */ +#define key_CR '\015' +#define key_ESC '\033' +/* '\014' == ^L */ +#define key_REDRAWKEY '\014' + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @*/ +void log_CHS_from_LBA(const disk_t *disk_car, const unsigned long int pos_LBA); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk_car, partition); + @*/ +const char *aff_part_aux(const unsigned int newline, const disk_t *disk_car, const partition_t *partition); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk_car, partition); + @*/ +void aff_part_buffer(const unsigned int newline, const disk_t *disk_car, const partition_t *partition); + +/*@ + @ requires valid_read_string(nptr); + @ assigns \nothing; + @*/ +uint64_t atouint64(const char *nptr); + +/*@ + @ requires valid_read_string(*current_cmd); + @ ensures valid_read_string(*current_cmd); + @ assigns *current_cmd; + @*/ +uint64_t ask_number_cli(char **current_cmd, const uint64_t val_cur, const uint64_t val_min, const uint64_t val_max, const char * _format, ...) __attribute__ ((format (printf, 5, 6))); +void screen_buffer_reset(void); +int screen_buffer_add(const char *_format, ...) __attribute__ ((format (printf, 1, 2))); +void screen_buffer_to_log(void); + +/*@ + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ assigns \nothing; + @*/ +int get_partition_status(const partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..1baaf7e --- /dev/null +++ b/include/list.h @@ -0,0 +1,590 @@ +/* + + File: list.h + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _LIST_H +#define _LIST_H + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * Copied from Linux Kernel 2.6.12.3 + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct td_list_head { + struct td_list_head *next, *prev; +}; + +#ifdef __FRAMAC__ +/*@ + @ requires \valid_read(a); + @ requires \valid_read(b); + @ assigns \nothing; + @*/ +int file_check_cmp(const struct td_list_head *a, const struct td_list_head *b); + +/*@ + @ assigns \nothing; + @*/ +int signature_cmp(const struct td_list_head *a, const struct td_list_head *b); +#endif + +/*@ + inductive reachable{L}(struct td_list_head *root, struct td_list_head *node) { + case root_reachable{L}: + \forall struct td_list_head *root; reachable(root,root) ; + case next_reachable{L}: + \forall struct td_list_head *root,*node; + \valid(root) && reachable(root->next,node) ==> reachable(root,node); + } + @*/ + // root->next->prev == root + +/*@ predicate finite{L}(struct td_list_head *root) = reachable(root->next,root); */ + + +/* + \forall struct td_list_head *l1; + reachable(l, l1) && \valid(l1) ==> \valid(l1->next) && l1->next->prev == l1; +*/ + +#define TD_LIST_HEAD_INIT(name) { &(name), &(name) } + +#define TD_LIST_HEAD(name) \ + struct td_list_head name = TD_LIST_HEAD_INIT(name) + +#define TD_INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +/* + X requires finite(prev); + X requires finite(next); + X ensures finite(prev); + X ensures finite(next); + X ensures finite(newe); + */ +/*@ + @ requires \valid(newe); + @ requires \valid(prev); + @ requires \valid(next); + @ requires separation: \separated(newe, \union(prev,next)); + @ requires prev == next || \separated(prev,next,newe); + @ ensures next->prev == newe; + @ ensures newe->next == next; + @ ensures newe->prev == prev; + @ ensures prev->next == newe; + @ assigns next->prev,newe->next,newe->prev,prev->next; + @*/ +static inline void __td_list_add(struct td_list_head *newe, + struct td_list_head *prev, + struct td_list_head *next) +{ + newe->next = next; + newe->prev = prev; + next->prev = newe; + prev->next = newe; + /*@ assert next->prev == newe; */ + /*@ assert newe->next == next; */ + /*@ assert newe->prev == prev; */ + /*@ assert prev->next == newe; */ + /*X assert finite(prev); */ + /*X assert finite(next); */ + /*X assert finite(newe); */ +} + +/** + * td_list_add - add a new entry + * @newe: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +/* + X requires finite(head); + X ensures finite(head); + X ensures finite(newe); + */ +/*@ + @ requires \valid(newe); + @ requires \valid(head); + @ requires \valid(head->next); + @ requires separation: \separated(newe, \union(head,head->next)); + @ ensures head->next == newe; + @ ensures newe->prev == head; + @ ensures newe->next == \old(head->next); + @ ensures \old(head->next)->prev == newe; + @ assigns head->next,newe->prev,newe->next,\old(head->next)->prev; + @*/ +static inline void td_list_add(struct td_list_head *newe, struct td_list_head *head) +{ + __td_list_add(newe, head, head->next); +} + +#if 0 +/*@ type invariant lists(struct td_list_head *l) = finite(l); */ +#endif + +/** + * td_list_add_tail - add a new entry + * @newe: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +/* + X requires finite(head); + X ensures finite(head); + X ensures finite(newe); + */ +/*@ + @ requires \valid(newe); + @ requires \valid(head); + @ requires \valid(head->prev); + @ requires separation: \separated(newe, head); + @ requires \separated(newe, \union(head->prev, head)); + @ requires head->prev == head || \separated(head->prev, head, newe); + @ ensures head->prev == newe; + @ ensures newe->next == head; + @ ensures newe->prev == \old(head->prev); + @ ensures \old(head->prev)->next == newe; + @ assigns head->prev,newe->next,newe->prev,\old(head->prev)->next; + @*/ +static inline void td_list_add_tail(struct td_list_head *newe, struct td_list_head *head) +{ + __td_list_add(newe, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +/*@ + @ requires \valid(prev); + @ requires \valid(next); + @ requires prev == next || \separated(prev,next); + @ ensures next->prev == prev; + @ ensures prev->next == next; + @ assigns next->prev,prev->next; + @*/ +static inline void __td_list_del(struct td_list_head * prev, struct td_list_head * next) +{ + next->prev = prev; + prev->next = next; + /*@ assert next->prev == prev; */ + /*@ assert prev->next == next; */ +} + +/** + * td_list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: td_list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +/*@ + @ requires \valid(entry); + @ requires \valid(entry->prev); + @ requires \valid(entry->next); + @ requires \separated(entry, \union(entry->prev,entry->next)); + @ requires entry->prev == entry->next || \separated(entry->prev,entry->next); + @ ensures \old(entry->prev)->next == \old(entry->next); + @ ensures \old(entry->next)->prev == \old(entry->prev); + @ assigns \old(entry->prev)->next, \old(entry->next)->prev, entry->next, entry->prev; + @*/ +static inline void td_list_del(struct td_list_head *entry) +{ + __td_list_del(entry->prev, entry->next); + /*@ assert entry->prev->next == entry->next; */ + /*@ assert entry->next->prev == entry->prev; */ + entry->next = (struct td_list_head*)LIST_POISON1; + entry->prev = (struct td_list_head*)LIST_POISON2; + /*@ assert \at(entry->prev,Pre)->next == \at(entry->next,Pre); */ + /*@ assert \at(entry->next,Pre)->prev == \at(entry->prev,Pre); */ +} + +/** + * td_list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void td_list_del_init(struct td_list_head *entry) +{ + __td_list_del(entry->prev, entry->next); + TD_INIT_LIST_HEAD(entry); +} + +/** + * td_list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void td_list_move(struct td_list_head *list, struct td_list_head *head) +{ + __td_list_del(list->prev, list->next); + td_list_add(list, head); +} + +/** + * td_list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void td_list_move_tail(struct td_list_head *list, + struct td_list_head *head) +{ + __td_list_del(list->prev, list->next); + td_list_add_tail(list, head); +} + +/** + * td_list_empty - tests whether a list is empty + * @head: the list to test. + */ +/*@ + @ requires \valid_read(head); + @ assigns \nothing; + @*/ +static inline int td_list_empty(const struct td_list_head *head) +{ + return head->next == head; +} + +/** + * td_list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using td_list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is td_list_del_init(). Eg. it cannot be used + * if another CPU could re-td_list_add() it. + * + * @head: the list to test. + */ +static inline int td_list_empty_careful(const struct td_list_head *head) +{ + struct td_list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __td_list_splice(struct td_list_head *list, + struct td_list_head *head) +{ + struct td_list_head *first = list->next; + struct td_list_head *last = list->prev; + struct td_list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * td_list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void td_list_splice(struct td_list_head *list, struct td_list_head *head) +{ + if (!td_list_empty(list)) + __td_list_splice(list, head); +} + +/** + * td_list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void td_list_splice_init(struct td_list_head *list, + struct td_list_head *head) +{ + if (!td_list_empty(list)) { + __td_list_splice(list, head); + TD_INIT_LIST_HEAD(list); + } +} + +/** + * td_list_entry - get the struct for this entry + * @ptr: the &struct td_list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member))) + +#define td_list_entry_const(ptr, type, member) \ + ((type *)((const char *)(ptr)-(size_t)(&((type *)0)->member))) + +/** + * __td_list_for_each - iterate over a list + * @pos: the &struct td_list_head to use as a loop counter. + * @head: the head for your list. + * + */ +#define td_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * td_list_for_each_prev - iterate over a list backwards + * @pos: the &struct td_list_head to use as a loop counter. + * @head: the head for your list. + */ +#define td_list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); \ + pos = pos->prev) + +/** + * td_list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct td_list_head to use as a loop counter. + * @n: another &struct td_list_head to use as temporary storage + * @head: the head for your list. + */ +#define td_list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * td_list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct td_list_head to use as a loop counter. + * @n: another &struct td_list_head to use as temporary storage + * @head: the head for your list. + */ +#define td_list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; pos != (head); \ + pos = n, n = pos->prev) + +/** + * td_list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_for_each_entry(pos, head, member) \ + for (pos = td_list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = td_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * td_list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_for_each_entry_reverse(pos, head, member) \ + for (pos = td_list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = td_list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * td_list_prepare_entry - prepare a pos entry for use as a start point in + * td_list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_prepare_entry(pos, head, member) \ + ((pos) ? : td_list_entry(head, typeof(*pos), member)) + +/** + * td_list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_for_each_entry_continue(pos, head, member) \ + for (pos = td_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = td_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * td_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the td_list_struct within the struct. + */ +#define td_list_for_each_entry_safe(pos, n, head, member) \ + for (pos = td_list_entry((head)->next, typeof(*pos), member), \ + n = td_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = td_list_entry(n->member.next, typeof(*n), member)) + + +/** + * td_list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ + +#define td_list_first_entry(ptr, type, member) \ + td_list_entry((ptr)->next, type, member) + + +/** + * td_list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define td_list_last_entry(ptr, type, member) \ + td_list_entry((ptr)->prev, type, member) + + +/** + * td_list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define td_list_next_entry(pos, member) \ + td_list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * td_list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define td_list_prev_entry(pos, member) \ + td_list_entry((pos)->member.prev, typeof(*(pos)), member) + + +#if 1 +/* + X requires finite(head); + X ensures finite(head); + X ensures finite(newe); + X ensures reachable(head,newe); + */ +/*@ + @ requires \valid(newe); + @ requires \valid(head); + @ requires \valid_function(compar); + @ requires compar == signature_cmp || compar == file_check_cmp; + @ requires separation: \separated(newe, head); + @*/ +static inline void td_list_add_sorted(struct td_list_head *newe, struct td_list_head *head, + int (*compar)(const struct td_list_head *a, const struct td_list_head *b)) +{ + struct td_list_head *pos; + /*@ + @ loop invariant pos == head || \separated(pos, head); + @*/ + td_list_for_each(pos, head) + { + /*@ assert compar == signature_cmp || compar == file_check_cmp; */ + /*@ assert \valid_read(newe); */ + /*@ assert \valid_read(pos); */ + /*X calls signature_cmp, file_check_cmp; */ + /*@ calls file_check_cmp; */ + if(compar(newe,pos)<0) + { + __td_list_add(newe, pos->prev, pos); + /*X assert finite(head); */ + /*X assert finite(newe); */ + return ; + } + } + td_list_add_tail(newe, head); + /*X assert finite(head); */ + /*X assert finite(newe); */ +} +#endif + +/*@ + @ requires \valid(newe); + @ requires \valid(head); + @ requires \valid_function(compar); + @ requires separation: \separated(newe, head); + @*/ +static inline int td_list_add_sorted_uniq(struct td_list_head *newe, struct td_list_head *head, + int (*compar)(const struct td_list_head *a, const struct td_list_head *b)) +{ + struct td_list_head *pos; + /*@ + @ loop invariant pos == head || \separated(pos, head); + @ loop assigns pos; + @*/ + td_list_for_each(pos, head) + { + // TODO const + /* calls spacerange_cmp; */ + int res=compar(newe,pos); + if(res<0) + { + __td_list_add(newe, pos->prev, pos); + return 0; + } + else if(res==0) + return 1; + } + td_list_add_tail(newe, head); + return 0; +} + +typedef struct alloc_list_s alloc_list_t; +struct alloc_list_s +{ + struct td_list_head list; + uint64_t start; + uint64_t end; + unsigned int data; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/log.h b/include/log.h new file mode 100644 index 0000000..e20c7b0 --- /dev/null +++ b/include/log.h @@ -0,0 +1,93 @@ +/* + + File: log.h + + Copyright (C) 2007-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _LOG_H +#define _LOG_H +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int log_set_levels(const unsigned int levels); + +/*@ + @ requires valid_read_string(default_filename); + @ requires \valid(errsv); + @ requires separation: \separated(default_filename, errsv, &errno); + @*/ +int log_open(const char*default_filename, const int mode, int *errsv); + +/*@ + @ requires \valid_read(default_filename); + @ requires \valid(errsv); + @ requires separation: \separated(default_filename, errsv, &errno); + @*/ +int log_open_default(const char*default_filename, const int mode, int *errsv); + +int log_flush(void); +int log_close(void); + +/*@ + @ requires valid_read_string(format); + @*/ +int log_redirect(const unsigned int level, const char *format, ...) __attribute__((format(printf, 2, 3))); + +/*@ + @ requires \valid((char *)nom_dump + (0 .. lng-1)); + @*/ +void dump_log(const void *nom_dump,unsigned int lng); + +/*@ + @ requires \valid((char *)dump_1 + (0 .. lng-1)); + @ requires \valid((char *)dump_2 + (0 .. lng-1)); + @*/ +void dump2_log(const void *dump_1, const void *dump_2,const unsigned int lng); + +#define TD_LOG_NONE 0 +#define TD_LOG_CREATE 1 +#define TD_LOG_APPEND 2 +#define TD_LOG_DONE 3 + +#define LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */ +#define LOG_LEVEL_TRACE (1 << 1) /* Entering function x() */ +#define LOG_LEVEL_QUIET (1 << 2) /* Quietable output */ +#define LOG_LEVEL_INFO (1 << 3) /* Volume needs defragmenting */ +#define LOG_LEVEL_VERBOSE (1 << 4) /* Forced to continue */ +#define LOG_LEVEL_PROGRESS (1 << 5) /* 54% complete */ +#define LOG_LEVEL_WARNING (1 << 6) /* You should backup before starting */ +#define LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */ +#define LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */ +#define LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */ + +#define log_debug(FORMAT, ARGS...) log_redirect(LOG_LEVEL_DEBUG,FORMAT,##ARGS) +#define log_trace(FORMAT, ARGS...) log_redirect(LOG_LEVEL_TRACE,FORMAT,##ARGS) +#define log_quiet(FORMAT, ARGS...) log_redirect(LOG_LEVEL_QUIET,FORMAT,##ARGS) +#define log_info(FORMAT, ARGS...) log_redirect(LOG_LEVEL_INFO,FORMAT,##ARGS) +#define log_verbose(FORMAT, ARGS...) log_redirect(LOG_LEVEL_VERBOSE,FORMAT,##ARGS) +#define log_progress(FORMAT, ARGS...) log_redirect(LOG_LEVEL_PROGRESS,FORMAT,##ARGS) +#define log_warning(FORMAT, ARGS...) log_redirect(LOG_LEVEL_WARNING,FORMAT,##ARGS) +#define log_error(FORMAT, ARGS...) log_redirect(LOG_LEVEL_ERROR,FORMAT,##ARGS) +#define log_perror(FORMAT, ARGS...) log_redirect(LOG_LEVEL_PERROR,FORMAT,##ARGS) +#define log_critical(FORMAT, ARGS...) log_redirect(LOG_LEVEL_CRITICAL,FORMAT,##ARGS) + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/log_part.h b/include/log_part.h new file mode 100644 index 0000000..d233acf --- /dev/null +++ b/include/log_part.h @@ -0,0 +1,45 @@ +/* + + File: log_part.h + + Copyright (C) 2007-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _LOG_PART_H +#define _LOG_PART_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid_read(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @*/ +void log_partition(const disk_t *disk, const partition_t *partition); + +/*@ + @ requires \valid_read(disk); + @ requires valid_disk(disk); + @ requires valid_list_part(list_part); + @*/ +void log_all_partitions(const disk_t *disk, const list_part_t *list_part); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/partauto.h b/include/partauto.h new file mode 100644 index 0000000..dbd7d7b --- /dev/null +++ b/include/partauto.h @@ -0,0 +1,41 @@ +/* + + File: partauto.h + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _PARTAUTO_H +#define _PARTAUTO_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(arch); + @ requires valid_disk(disk); + @ requires separation: \separated(disk, arch); + @ ensures valid_disk(disk); + @*/ +void autodetect_arch(disk_t *disk, const arch_fnct_t *arch); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/phcfg.h b/include/phcfg.h new file mode 100644 index 0000000..619bbdc --- /dev/null +++ b/include/phcfg.h @@ -0,0 +1,46 @@ +/* + + File: phcfg.h + + Copyright (C) 2020 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _PHCFG_H +#define _PHCFG_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(files_enable); + @*/ +void reset_array_file_enable(file_enable_t *files_enable); + +/*@ + @ requires \valid_read(files_enable); + @*/ +int file_options_save(const file_enable_t *files_enable); + +/*@ + @ requires \valid(files_enable); + @*/ +int file_options_load(file_enable_t *files_enable); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/photorec.h b/include/photorec.h new file mode 100644 index 0000000..1ef53c9 --- /dev/null +++ b/include/photorec.h @@ -0,0 +1,294 @@ +/* + + File: photorec.h + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _TESTDISK_PHOTOREC_H +#define _TESTDISK_PHOTOREC_H +#define MAX_FILES_PER_DIR 500 +#define DEFAULT_RECUP_DIR "recup_dir" +#ifdef __cplusplus +extern "C" { +#endif + +enum photorec_status { STATUS_FIND_OFFSET, STATUS_UNFORMAT, STATUS_EXT2_ON, STATUS_EXT2_ON_BF, STATUS_EXT2_OFF, STATUS_EXT2_OFF_BF, STATUS_EXT2_ON_SAVE_EVERYTHING, STATUS_EXT2_OFF_SAVE_EVERYTHING, STATUS_QUIT }; +typedef enum photorec_status photorec_status_t; + +typedef enum { PSTATUS_OK=0, PSTATUS_STOP=1, PSTATUS_EACCES=2, PSTATUS_ENOSPC=3} pstatus_t; +typedef enum { PFSTATUS_BAD=0, PFSTATUS_OK=1, PFSTATUS_OK_TRUNCATED=2} pfstatus_t; + +struct ph_options +{ + int paranoid; + int keep_corrupted_file; + unsigned int mode_ext2; + unsigned int expert; + unsigned int lowmem; + int verbose; + file_enable_t *list_file_format; +}; + +struct ph_param +{ + char *cmd_device; + char *cmd_run; + disk_t *disk; + partition_t *partition; + unsigned int carve_free_space_only; + unsigned int blocksize; + unsigned int pass; + photorec_status_t status; + time_t real_start_time; + char *recup_dir; + /* */ + unsigned int dir_num; + unsigned int file_nbr; + file_stat_t *file_stats; + uint64_t offset; +}; + +/*@ + predicate valid_ph_param(struct ph_param *p) = (\valid_read(p) && + (p->recup_dir == \null || valid_read_string(p->recup_dir)) + ); + @*/ + +#define PH_INVALID_OFFSET 0xffffffffffffffff + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires \separated(list_search_space, current_search_space, offset); + @ requires current_search_space==\null || (\valid(*current_search_space) && valid_list_search_space(*current_search_space)); + @ ensures \result==0 ==> (*current_search_space!=list_search_space && *offset == (*current_search_space)->start); + @*/ +// ensures current_search_space==\null || (\valid(*current_search_space) && valid_list_search_space(*current_search_space)); +int get_prev_file_header(const alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset); + +/*@ + @ requires valid_file_recovery(file_recovery); + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(file_recovery, params, list_search_space); + @*/ +int file_finish_bf(file_recovery_t *file_recovery, struct ph_param *params, + alloc_data_t *list_search_space); + +/*@ + @ requires \valid(file_recovery); + @ requires valid_file_recovery(file_recovery); + @ requires valid_list_search_space(list_search_space); + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires \separated(file_recovery, params, list_search_space, &errno); + @*/ +void file_recovery_aborted(file_recovery_t *file_recovery, struct ph_param *params, alloc_data_t *list_search_space); + +/*@ + @ requires \valid(file_recovery); + @ requires valid_file_recovery(file_recovery); + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(file_recovery, params, list_search_space); + @ ensures \result == PFSTATUS_BAD || \result == PFSTATUS_OK || \result == PFSTATUS_OK_TRUNCATED; + @*/ +// ensures valid_file_recovery(file_recovery); +pfstatus_t file_finish2(file_recovery_t *file_recovery, struct ph_param *params, const int paranoid, alloc_data_t *list_search_space); + +/*@ + @ requires \valid_read(file_stats); + @*/ +void write_stats_log(const file_stat_t *file_stats); + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires \separated(file_stats, list_search_space); + @*/ +//ensures valid_list_search_space(list_search_space); +void update_stats(file_stat_t *file_stats, alloc_data_t *list_search_space); +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @*/ +// ensures valid_partition(\result); +partition_t *new_whole_disk(const disk_t *disk_car); + +/*@ + @ requires valid_list_search_space(list_file); + @ requires \valid(offset); + @ requires \separated(list_file, offset); + @ requires default_blocksize > 0; + @*/ +// ensures \result > 0; +unsigned int find_blocksize(const alloc_data_t *list_file, const unsigned int default_blocksize, uint64_t *offset); + +/*@ + @ requires blocksize > 0; + @ requires valid_list_search_space(list_search_space); + @*/ +void update_blocksize(const unsigned int blocksize, alloc_data_t *list_search_space, const uint64_t offset); + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires current_search_space==\null || valid_list_search_space(current_search_space); + @*/ +// ensures current_search_space==\null || valid_list_search_space(current_search_space); +void forget(const alloc_data_t *list_search_space, alloc_data_t *current_search_space); + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->disk_size > 0; + @ requires disk_car->disk_real_size > 0; + @ requires \valid_read(partition); + @ requires separation: \separated(list_search_space, disk_car, partition); + @*/ +void init_search_space(alloc_data_t *list_search_space, const disk_t *disk_car, const partition_t *partition); + +/*@ + @ requires valid_disk(disk_car); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(disk_car, partition, list_search_space); + @ ensures valid_list_search_space(list_search_space); + @ ensures valid_disk(disk_car); + @ ensures valid_list_search_space(list_search_space); + @*/ +unsigned int remove_used_space(disk_t *disk_car, const partition_t *partition, alloc_data_t *list_search_space); + +/*@ + @ requires valid_list_search_space(list_search_space); + @*/ +void free_list_search_space(alloc_data_t *list_search_space); + +int sorfile_stat_ts(const void *p1, const void *p2); + +/*@ + @ requires valid_read_string(recup_dir); + @ requires \separated(recup_dir, &errno); + @*/ +unsigned int photorec_mkdir(const char *recup_dir, const unsigned int initial_dir_num); + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires \separated(list_search_space, current_search_space); + @ ensures valid_list_search_space(list_search_space); + @*/ +void info_list_search_space(const alloc_data_t *list_search_space, const alloc_data_t *current_search_space, const unsigned int sector_size, const int keep_corrupted_file, const int verbose); + +/*@ + @ requires valid_list_search_space(list_search_space); + @*/ +void free_search_space(alloc_data_t *list_search_space); + +/*@ + @ requires \valid(file_recovery); + @ requires valid_file_recovery(file_recovery); + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires \separated(file_recovery, params); + @*/ +// ensures valid_file_recovery(file_recovery); +void set_filename(file_recovery_t *file_recovery, struct ph_param *params); + +/*@ + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(params, new_current_search_space, list_search_space); + @ requires new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); + @*/ +// ensures new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); +// ensures valid_list_search_space(list_search_space); +uint64_t set_search_start(struct ph_param *params, alloc_data_t **new_current_search_space, alloc_data_t *list_search_space); + +/*@ + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires \valid_read(options); + @ requires \separated(params, options); + @*/ +void params_reset(struct ph_param *params, const struct ph_options *options); + +/*@ + @ assigns \nothing; + @*/ +const char *status_to_name(const photorec_status_t status); + +/*@ + @ requires \valid(params); + @ requires valid_ph_param(params); + @ requires \valid_read(options); + @ requires \separated(params, options); + @ assigns params->offset, params->status, params->file_nbr; + @*/ +void status_inc(struct ph_param *params, const struct ph_options *options); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(&disk->arch); + @ requires \valid_function(disk->arch->read_part); + @ requires \valid_read(options); + @ requires \separated(disk, options); + @ ensures valid_disk(disk); + @*/ +// ensures valid_list_part(\result); +list_part_t *init_list_part(disk_t *disk, const struct ph_options *options); + +/*@ + @ requires valid_file_recovery(file_recovery); + @*/ +// ensures valid_file_recovery(file_recovery); +void file_block_log(const file_recovery_t *file_recovery, const unsigned int sector_size); + +/*@ + @ requires valid_file_recovery(file_recovery); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(file_recovery, list_search_space, new_current_search_space, offset); + @ requires new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); + @*/ +// ensures new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); +// ensures valid_file_recovery(file_recovery); +// ensures valid_list_search_space(list_search_space); +void file_block_append(file_recovery_t *file_recovery, alloc_data_t *list_search_space, alloc_data_t **new_current_search_space, uint64_t *offset, const unsigned int blocksize, const unsigned int data); + +/*@ + @ requires valid_file_recovery(file_recovery); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(file_recovery, list_search_space, new_current_search_space, offset, buffer + (..)); + @ requires new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); + @*/ +// ensures new_current_search_space==\null || (\valid(*new_current_search_space) && valid_list_search_space(*new_current_search_space)); +// ensures valid_file_recovery(file_recovery); +// ensures valid_list_search_space(list_search_space); +void file_block_truncate_and_move(file_recovery_t *file_recovery, alloc_data_t *list_search_space, const unsigned int blocksize, alloc_data_t **new_current_search_space, uint64_t *offset, unsigned char *buffer); + +/*@ + @ requires \valid(list_search_space); + @ requires valid_list_search_space(list_search_space); + @*/ +void del_search_space(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/include/sessionp.h b/include/sessionp.h new file mode 100644 index 0000000..2dce789 --- /dev/null +++ b/include/sessionp.h @@ -0,0 +1,58 @@ +/* + + File: sessionp.h + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _SESSIONP_H +#define _SESSIONP_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*@ + @ requires \valid(cmd_device); + @ requires \valid(current_cmd); + @ requires valid_list_search_space(list_free_space); + @ requires \separated(cmd_device, current_cmd, list_free_space); + @*/ +// ensures *cmd_device==\null || valid_read_string(*cmd_device); +// ensures *current_cmd==\null || valid_read_string(*current_cmd); +// ensures valid_list_search_space(list_free_space); +int session_load(char **cmd_device, char **current_cmd, alloc_data_t *list_free_space); + +/*@ + @ requires list_free_space==\null || \valid_read(list_free_space); + @ requires params==\null || \valid_read(params); + @ requires options==\null || \valid_read(options); + @*/ +int session_save(const alloc_data_t *list_free_space, const struct ph_param *params, const struct ph_options *options); + +/*@ + @ requires \valid_read(list_free_space); + @ requires params==\null || \valid_read(params); + @ requires options==\null || \valid_read(options); + @*/ +time_t regular_session_save(alloc_data_t *list_free_space, struct ph_param *params, const struct ph_options *options, time_t current_time); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..49130a1 --- /dev/null +++ b/meson.build @@ -0,0 +1,27 @@ +project('grecovery', 'c', version: '21.8') + +desktop = meson.project_name() + '.desktop' +bindir = join_paths(get_option('prefix'), get_option('bindir')) + +lib_proj = subproject('lib') +lib_both = lib_proj.get_variable('lib_both') + +cc = meson.get_compiler('c') + +c_args = ['-DHAVE_CONFIG_H'] +incdir = include_directories('include') + +gnome = import('gnome') +res = gnome.compile_resources('res', join_paths('data', 'icons', 'gresource.xml'), source_dir: join_paths('data', 'icons')) + +dep = [dependency('gtk+-3.0', version: '>= 3.22')] + +c = run_command('sh', '-c', 'for file in gtk/src/*.c; do echo $file; done') +src = c.stdout().strip().split('\n') +src += res + +executable(meson.project_name(), src, include_directories: incdir, dependencies: dep, link_with: lib_both.get_static_lib(), c_args: c_args, install: true) + +configure_file(input: join_paths('data', 'desktop'), output: desktop, copy: true, install: true, install_dir: join_paths('share', 'applications')) +configure_file(input: join_paths('data', 'grecovery-pkexec'), output: 'grecovery-pkexec', copy: true, install: true, install_dir: bindir) + diff --git a/subprojects/lib/meson.build b/subprojects/lib/meson.build new file mode 100644 index 0000000..9be3793 --- /dev/null +++ b/subprojects/lib/meson.build @@ -0,0 +1,16 @@ +project('libphotorec', 'c', version: '21.0') + +c_args = ['-DHAVE_CONFIG_H'] +incdir = include_directories('../../include') + +cc = meson.get_compiler('c') + +libz = cc.find_library('libz', required: true) + +c = run_command('sh', '-c', 'for file in src/*.c; do echo $file; done') +lib_src = c.stdout().strip().split('\n') + +lib_dep = [dependency('ext2fs'), dependency('libntfs-3g'), dependency('libjpeg'), libz] + +lib_both = both_libraries('photorec', sources: lib_src, include_directories: incdir, dependencies: lib_dep, c_args: c_args) + diff --git a/subprojects/lib/src/addpart.c b/subprojects/lib/src/addpart.c new file mode 100644 index 0000000..9f297c3 --- /dev/null +++ b/subprojects/lib/src/addpart.c @@ -0,0 +1,87 @@ +/* + + File: addpart.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "types.h" +#include "common.h" +#include "parti386.h" +#include "partgpt.h" +#include "parthumax.h" +#include "partmac.h" +#include "partsun.h" +#include "partxbox.h" +#include "addpart.h" + +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) +extern const arch_fnct_t arch_gpt; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) +extern const arch_fnct_t arch_humax; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) +extern const arch_fnct_t arch_i386; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) +extern const arch_fnct_t arch_mac; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_SUN) +extern const arch_fnct_t arch_sun; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_XBOX) +extern const arch_fnct_t arch_xbox; +#endif + +list_part_t *add_partition_cli(disk_t *disk, list_part_t *list_part, char **current_cmd) +{ + assert(current_cmd!=NULL); + /*@ assert valid_read_string(*current_cmd); */ +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) + if(disk->arch==&arch_gpt) + return add_partition_gpt_cli(disk, list_part, current_cmd); +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + if(disk->arch==&arch_i386) + return add_partition_i386_cli(disk, list_part, current_cmd); +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) + if(disk->arch==&arch_humax) + return add_partition_humax_cli(disk, list_part, current_cmd); +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) + if(disk->arch==&arch_mac) + return add_partition_mac_cli(disk, list_part, current_cmd); +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_SUN) + if(disk->arch==&arch_sun) + return add_partition_sun_cli(disk, list_part, current_cmd); +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_XBOX) + if(disk->arch==&arch_xbox) + return add_partition_xbox_cli(disk, list_part, current_cmd); +#endif + return list_part; +} diff --git a/subprojects/lib/src/addpart.h b/subprojects/lib/src/addpart.h new file mode 100644 index 0000000..9d25a80 --- /dev/null +++ b/subprojects/lib/src/addpart.h @@ -0,0 +1,35 @@ +/* + + File: addpart.h + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _ADDPART_H +#define _ADDPART_H +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires valid_list_part(list_part); + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires separation: \separated(disk, list_part, current_cmd); + @*/ +// ensures valid_read_string(*current_cmd); +list_part_t *add_partition_cli(disk_t *disk, list_part_t *list_part, char **current_cmd); +#endif diff --git a/subprojects/lib/src/alignio.h b/subprojects/lib/src/alignio.h new file mode 100644 index 0000000..be949e2 --- /dev/null +++ b/subprojects/lib/src/alignio.h @@ -0,0 +1,140 @@ +/* + + File: alignio.h + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _ALIGNIO_H +#define _ALIGNIO_H + +/*@ + @ requires \valid_function(fnct_pread); + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->offset < 0x8000000000000000; + @ requires 0 < count < 0x8000000000000000; + @ requires offset < 0x8000000000000000; + @ requires \valid((char *)buf + (0 .. count -1)); + @ requires \separated(disk_car, (char *)buf); + @ ensures valid_disk(disk_car); + @*/ +static int align_pread(int (*fnct_pread)(const disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset), + disk_t *disk_car, void*buf, const unsigned int count, const uint64_t offset) +{ + const uint64_t offset_new=offset+disk_car->offset; + const unsigned int count_new=((offset_new%disk_car->sector_size)+count+disk_car->sector_size-1)/disk_car->sector_size*disk_car->sector_size; + /*@ assert count_new >= count; */ + /*@ assert count_new >= disk_car->sector_size; */ + /*@ assert count_new > 0; */ + if(count!=count_new || + ((disk_car->access_mode&TESTDISK_O_DIRECT)!=0 && + (((size_t)(buf) & (disk_car->sector_size-1))!=0) && + (buf!=disk_car->rbuffer || disk_car->rbuffer_sizerbuffer_size < count_new) + { + free(disk_car->rbuffer); + disk_car->rbuffer=NULL; + } + if(disk_car->rbuffer==NULL) + { + disk_car->rbuffer_size=128*512; + /*@ loop assigns disk_car->rbuffer_size; */ + while(disk_car->rbuffer_size < count_new) + { + disk_car->rbuffer_size*=2; + } + /*@ assert disk_car->rbuffer_size >= count_new; */ + disk_car->rbuffer=(char*)MALLOC(disk_car->rbuffer_size); + /*@ assert valid_disk(disk_car); */ + } + /*@ assert \freeable(disk_car->rbuffer); */ + /*@ assert valid_disk(disk_car); */ + res=fnct_pread(disk_car, disk_car->rbuffer, count_new, offset_new/disk_car->sector_size*disk_car->sector_size); + memcpy(buf,(char*)disk_car->rbuffer+(offset_new%disk_car->sector_size),count); + /*@ assert \freeable(disk_car->rbuffer) && disk_car->rbuffer_size > 0; */ + /*@ assert valid_disk(disk_car); */ + return (res < (signed)count ? res : (signed)count ); + } + /*@ assert valid_disk(disk_car); */ + return fnct_pread(disk_car, buf, count, offset_new); +} + +/*@ + @ requires \valid_function(fnct_pread); + @ requires \valid_function(fnct_pwrite); + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires disk_car->sector_size > 0; + @ requires disk_car->offset < 0x8000000000000000; + @ requires 0 < count < 0x8000000000000000; + @ requires offset < 0x8000000000000000; + @ requires \valid_read((char *)buf + (0 .. count -1)); + @ requires \separated(disk_car, (char *)buf); + @ ensures valid_disk(disk_car); + @*/ +static int align_pwrite(int (*fnct_pread)(const disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset), + int (*fnct_pwrite)(disk_t *disk_car, const void *buf, const unsigned int count, const uint64_t offset), + disk_t *disk_car, const void*buf, const unsigned int count, const uint64_t offset) +{ + const uint64_t offset_new=offset+disk_car->offset; + const unsigned int count_new=((offset_new%disk_car->sector_size)+count+disk_car->sector_size-1)/disk_car->sector_size*disk_car->sector_size; + if(count!=count_new || + ((disk_car->access_mode&TESTDISK_O_DIRECT)!=0 && + (((size_t)(buf) & (disk_car->sector_size-1))!=0)) + ) + { + int tmp; + if(disk_car->wbuffer_size < count_new) + { + free(disk_car->wbuffer); + disk_car->wbuffer=NULL; + } + if(disk_car->wbuffer==NULL) + { + disk_car->wbuffer_size=128*512; + /*@ loop assigns disk_car->wbuffer_size; */ + while(disk_car->wbuffer_size < count_new) + { + disk_car->wbuffer_size*=2; + } + /*@ assert disk_car->wbuffer_size >= count_new; */ + disk_car->wbuffer=(char*)MALLOC(disk_car->wbuffer_size); + /*@ assert valid_disk(disk_car); */ + } + /*@ assert \freeable(disk_car->wbuffer); */ + /*@ assert valid_disk(disk_car); */ + if(fnct_pread(disk_car, disk_car->wbuffer, count_new, offset_new/disk_car->sector_size*disk_car->sector_size)<0) + { + log_error("read failed but trying to write anyway"); + memset(disk_car->wbuffer,0, disk_car->wbuffer_size); + } + memcpy((char*)disk_car->wbuffer+(offset_new%disk_car->sector_size),buf,count); + tmp=fnct_pwrite(disk_car, disk_car->wbuffer, count_new, offset_new/disk_car->sector_size*disk_car->sector_size); + /*@ assert \freeable(disk_car->wbuffer) && disk_car->wbuffer_size > 0; */ + /*@ assert valid_disk(disk_car); */ + return (tmp < (signed)count ? tmp : (signed)count); + } + /*@ assert valid_disk(disk_car); */ + return fnct_pwrite(disk_car, buf, count, offset_new); +} +#endif diff --git a/subprojects/lib/src/analyse.c b/subprojects/lib/src/analyse.c new file mode 100644 index 0000000..303b378 --- /dev/null +++ b/subprojects/lib/src/analyse.c @@ -0,0 +1,459 @@ +/* + + File: analyse.c + + Copyright (C) 1998-2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "analyse.h" +#include "fat.h" +#include "exfat.h" +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) +#include "apfs.h" +#include "bfs.h" +#include "bsd.h" +#include "btrfs.h" +#include "cramfs.h" +#include "ext2.h" +#include "fatx.h" +#include "f2fs_fs.h" +#include "f2fs.h" +#include "gfs2.h" +#include "hfs.h" +#include "hfsp.h" +#include "jfs_superblock.h" +#include "jfs.h" +#include "hpfs.h" +#include "luks.h" +#include "lvm.h" +#include "md.h" +#include "netware.h" +#include "ntfs.h" +#include "refs.h" +#include "rfs.h" +#include "sun.h" +#include "swap.h" +#include "sysv.h" +#include "ufs.h" +#include "vmfs.h" +#include "wbfs.h" +#include "xfs.h" +#include "zfs.h" +#endif +#include "parti386.h" +#include "log.h" + +int search_NTFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ + if(disk->pread(disk, buffer, DEFAULT_SECTOR_SIZE, partition->part_offset) != DEFAULT_SECTOR_SIZE) + return -1; + { + const struct ntfs_boot_sector *ntfs_header=(const struct ntfs_boot_sector*)buffer; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + /* NTFS recovery using backup sector */ + if(le16(ntfs_header->marker)==0xAA55 && + recover_NTFS(disk, ntfs_header, partition, verbose, dump_ind, 1)==0) + return 1; +#endif + } + return 0; +} + +int search_HFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ + if(disk->pread(disk, buffer, 0x400, partition->part_offset)!= 0x400) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { + const hfs_mdb_t *hfs_mdb=(const hfs_mdb_t *)buffer; + const struct hfsp_vh *vh=(const struct hfsp_vh *)buffer; + /* HFS recovery using backup sector */ + if(hfs_mdb->drSigWord==be16(HFS_SUPER_MAGIC) && + recover_HFS(disk, hfs_mdb, partition, verbose, dump_ind, 1)==0) + { + strncpy(partition->info,"HFS found using backup sector!",sizeof(partition->info)); + return 1; + } + if((be16(vh->version)==4 || be16(vh->version)==5) && + recover_HFSP(disk, vh, partition, verbose, dump_ind, 1)==0) + { + strncpy(partition->info,"HFS+ found using backup sector!",sizeof(partition->info)); + return 1; + } + } +#endif + return 0; +} + +int search_exFAT_backup(unsigned char *buffer, disk_t *disk, partition_t *partition) +{ + if(disk->pread(disk, buffer, DEFAULT_SECTOR_SIZE, partition->part_offset) != DEFAULT_SECTOR_SIZE) + return -1; + { + const struct exfat_super_block *exfat_header=(const struct exfat_super_block *)buffer; + /* EXFAT recovery using backup sector */ + if(le16(exfat_header->signature)==0xAA55 && + recover_exFAT(disk, exfat_header, partition)==0) + { + /* part_offset has already been updated if found using backup sector */ + return 1; + } + } + return 0; +} + +int search_FAT_backup(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ + if(disk->pread(disk, buffer, DEFAULT_SECTOR_SIZE, partition->part_offset)!=DEFAULT_SECTOR_SIZE) + return -1; + { + const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)buffer; + /* FAT32 recovery using backup sector */ + if(le16(fat_header->marker)==0xAA55 && + recover_FAT(disk, fat_header, partition, verbose, dump_ind, 1)==0) + return 1; + } + return 0; +} + +int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + /* Expect a buffer filled with 8k to handle the SWAP detection */ + const pv_disk_t *pv=(const pv_disk_t *)buffer; + const struct cramfs_super *cramfs=(const struct cramfs_super *)buffer; + const struct disk_fatx *fatx_block=(const struct disk_fatx*)buffer; + const struct disk_netware *netware_block=(const struct disk_netware *)buffer; + const struct exfat_super_block *exfat_header=(const struct exfat_super_block *)buffer; + const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)buffer; + const struct luks_phdr *luks=(const struct luks_phdr *)buffer; + const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer; + const struct ntfs_boot_sector *ntfs_header=(const struct ntfs_boot_sector*)buffer; + const struct wbfs_head *wbfs=(const struct wbfs_head *)buffer; + const struct xfs_sb *xfs=(const struct xfs_sb *)buffer; + const union swap_header *swap_header=(const union swap_header *)buffer; + const struct ReFS_boot_sector *refs_header=(const struct ReFS_boot_sector *)buffer; + const nx_superblock_t *apfs=(const nx_superblock_t *)buffer; + static const uint8_t LUKS_MAGIC[LUKS_MAGIC_L] = {'L','U','K','S', 0xba, 0xbe}; +// assert(sizeof(union swap_header)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(pv_disk_t)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(struct fat_boot_sector)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(struct ntfs_boot_sector)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(struct disk_netware)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(struct xfs_sb)<=8*DEFAULT_SECTOR_SIZE); +// assert(sizeof(struct disk_fatx)<=8*DEFAULT_SECTOR_SIZE); + if(verbose>2) + { + log_trace("search_type_0 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(le32(apfs->nx_magic)== 0x4253584e && + recover_APFS(disk, apfs, partition, verbose, dump_ind)==0) + return 1; + if((memcmp(swap_header->magic.magic, "SWAP", 4)==0 || + memcmp(swap_header->magic8k.magic, "SWAP", 4)==0) && + recover_Linux_SWAP(swap_header, partition)==0) + return 1; + if(memcmp((const char *)pv->id,LVM_ID,sizeof(pv->id)) == 0 && + recover_LVM(disk, pv, partition, verbose, dump_ind)==0) + return 1; + if(le16(fat_header->marker)==0xAA55 && + recover_FAT(disk, fat_header, partition, verbose, dump_ind, 0)==0) + return 1; + if(le16(exfat_header->signature)==0xAA55 && + recover_exFAT(disk, exfat_header, partition)==0) + return 1; + if(le16(fat_header->marker)==0xAA55 && + recover_HPFS(disk, fat_header, partition, verbose)==0) + return 1; + if(le16(fat_header->marker)==0xAA55 && + recover_OS2MB(disk, fat_header, partition, verbose, dump_ind)==0) + return 1; + if(le16(ntfs_header->marker)==0xAA55 && + recover_NTFS(disk, ntfs_header, partition, verbose, dump_ind, 0)==0) + return 1; + if(memcmp(netware_block->magic, "Nw_PaRtItIoN", 12)==0 && + recover_netware(disk, netware_block, partition)==0) + return 1; + if (xfs->sb_magicnum==be32(XFS_SB_MAGIC) && + recover_xfs(disk, xfs, partition, verbose, dump_ind)==0) + return 1; + if(memcmp(fatx_block->magic,"FATX",4)==0 && + recover_FATX(fatx_block, partition)==0) + return 1; + if(memcmp(luks->magic,LUKS_MAGIC,LUKS_MAGIC_L)==0 && + recover_LUKS(disk, luks, partition, verbose, dump_ind)==0) + return 1; + if(refs_header->fsname==be32(0x52654653) && + recover_ReFS(disk, refs_header, partition)==0) + return 1; + /* MD 1.1 */ + if(le32(sb1->major_version)==1 && + recover_MD(disk, (const struct mdp_superblock_s*)buffer, partition, verbose, dump_ind)==0) + { + partition->part_offset-=le64(sb1->super_offset)*512; + return 1; + } + if(memcmp(&wbfs->magic,"WBFS",4)==0 && + recover_WBFS(disk, wbfs, partition, verbose, dump_ind)==0) + return 1; + if(cramfs->magic==le32(CRAMFS_MAGIC) && + recover_cramfs(disk, cramfs, partition, verbose, dump_ind)==0) + return 1; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + /* Try to locate logical partition that may host truecrypt encrypted filesystem */ + if(buffer[0x1fe]==0x55 && buffer[0x1ff]==0xAA && + recover_i386_logical(disk, buffer, partition)==0 && + partition->upart_type==UP_UNK) + return 1; +#endif + return 0; +} + +int search_type_1(const unsigned char *buffer, const disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + const struct disklabel *bsd_header=(const struct disklabel *)(buffer+0x200); + const struct disk_super_block *beos_block=(const struct disk_super_block*)(buffer+0x200); + const struct cramfs_super *cramfs=(const struct cramfs_super *)(buffer+0x200); + const struct lvm2_label_header *lvm2=(const struct lvm2_label_header *)(buffer+0x200); + const struct sysv4_super_block *sysv4=(const struct sysv4_super_block *)(buffer+0x200); + const sun_partition_i386 *sunlabel=(const sun_partition_i386*)(buffer+0x200); +// assert(sizeof(struct disklabel)<=2*0x200); +// assert(sizeof(struct disk_super_block)<=0x200); +// assert(sizeof(struct cramfs_super)<=2*0x200); +// assert(sizeof(struct sysv4_super_block)<=2*0x200); +// assert(sizeof(sun_partition_i386)<=2*0x200); + if(verbose>2) + { + log_trace("search_type_1 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(le32(bsd_header->d_magic) == DISKMAGIC && le32(bsd_header->d_magic2)==DISKMAGIC && + recover_BSD(disk, bsd_header, partition, verbose, dump_ind)==0) + return 1; + if(beos_block->magic1==le32(SUPER_BLOCK_MAGIC1) && + recover_BeFS(disk, beos_block, partition, dump_ind)==0) + return 1; + if(cramfs->magic==le32(CRAMFS_MAGIC) && + recover_cramfs(disk, cramfs, partition, verbose, dump_ind)==0) + return 1; + if(((unsigned)sysv4->s_magic == le32(0xfd187e20) || (unsigned)sysv4->s_magic == be32(0xfd187e20)) && + recover_sysv(disk, sysv4, partition, verbose, dump_ind)==0) + return 1; + if(memcmp((const char *)lvm2->type, LVM2_LABEL, sizeof(lvm2->type)) == 0 && + recover_LVM2(disk, (buffer+0x200), partition, verbose, dump_ind)==0) + return 1; + if(le32(sunlabel->magic_start) == SUN_LABEL_MAGIC_START && + recover_sun_i386(disk, sunlabel, partition, verbose, dump_ind)==0) + return 1; +#endif + return 0; +} + +int search_type_2(const unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + const hfs_mdb_t *hfs_mdb=(const hfs_mdb_t *)(buffer+0x400); + const struct hfsp_vh *vh=(const struct hfsp_vh *)(buffer+0x400); + const struct ext2_super_block *sb=(const struct ext2_super_block*)(buffer+0x400); + const struct f2fs_super_block *sb_f2fs=(const struct f2fs_super_block *)(buffer+0x400); +// assert(sizeof(struct ext2_super_block)<=1024); +// assert(sizeof(hfs_mdb_t)<=1024); +// assert(sizeof(struct hfsp_vh)<=1024); +// assert(sizeof(struct f2fs_super_block)==3072); + if(verbose>2) + { + log_trace("search_type_2 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(le16(sb->s_magic)==EXT2_SUPER_MAGIC && + recover_EXT2(disk, sb, partition, verbose, dump_ind)==0) + return 1; + if(hfs_mdb->drSigWord==be16(HFS_SUPER_MAGIC) && + recover_HFS(disk, hfs_mdb, partition, verbose, dump_ind, 0)==0) + return 1; + if((be16(vh->version)==4 || be16(vh->version)==5) && + recover_HFSP(disk, vh, partition, verbose, dump_ind, 0)==0) + return 1; + if(sb_f2fs->magic == le32(F2FS_SUPER_MAGIC) && + recover_f2fs(disk, sb_f2fs, partition)==0) + return 1; +#endif + return 0; +} + +int search_type_8(unsigned char *buffer, disk_t *disk,partition_t *partition,const int verbose, const int dump_ind) +{ + if(verbose>2) + { + log_trace("search_type_8 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(disk->pread(disk, buffer, 4096, partition->part_offset + 4096) != 4096) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { /* MD 1.2 */ + const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer; + if(le32(sb1->major_version)==1 && + recover_MD(disk, (const struct mdp_superblock_s*)buffer, partition, verbose, dump_ind)==0) + { + partition->part_offset-=(uint64_t)le64(sb1->super_offset)*512-4096; + return 1; + } + } +#endif + return 0; +} + +int search_type_16(unsigned char *buffer, disk_t *disk,partition_t *partition,const int verbose, const int dump_ind) +{ + if(verbose>2) + { + log_trace("search_type_16 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + /* 8k offset */ + if(disk->pread(disk, buffer, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 16 * 512) != 3 * DEFAULT_SECTOR_SIZE) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { + const struct ufs_super_block *ufs=(const struct ufs_super_block *)buffer; + const struct vdev_boot_header *zfs=(const struct vdev_boot_header*)buffer; + /* Test UFS */ + if((le32(ufs->fs_magic)==UFS_MAGIC || be32(ufs->fs_magic)==UFS_MAGIC || + le32(ufs->fs_magic)==UFS2_MAGIC || be32(ufs->fs_magic)==UFS2_MAGIC) && + recover_ufs(disk, ufs, partition, verbose, dump_ind)==0) + return 1; + if(le64(zfs->vb_magic)==VDEV_BOOT_MAGIC && + recover_ZFS(disk, zfs, partition, verbose, dump_ind)==0) + return 1; + } +#endif + return 0; +} + +int search_type_64(unsigned char *buffer, disk_t *disk,partition_t *partition,const int verbose, const int dump_ind) +{ + if(verbose>2) + { + log_trace("search_type_64 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + /* 32k offset */ + if(disk->pread(disk, buffer, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 63 * 512) != 3 * DEFAULT_SECTOR_SIZE) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { + const struct jfs_superblock* jfs=(const struct jfs_superblock*)(buffer+0x200); + /* Test JFS */ + if(memcmp(jfs->s_magic,"JFS1",4)==0 && + recover_JFS(disk, jfs, partition, verbose, dump_ind)==0) + return 1; + } +#endif + return 0; +} + +int search_type_128(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ + if(verbose>2) + { + log_trace("search_type_128 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(disk->pread(disk, buffer, 11 * DEFAULT_SECTOR_SIZE, partition->part_offset + 126 * 512) != 11 * DEFAULT_SECTOR_SIZE) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { + const unsigned char *buffer_1024=buffer+0x400; + const struct reiserfs_super_block *rfs=(const struct reiserfs_super_block *)buffer_1024; + const struct reiser4_master_sb *rfs4=(const struct reiser4_master_sb *)buffer_1024; + const struct ufs_super_block *ufs=(const struct ufs_super_block *)buffer_1024; + const struct btrfs_super_block *btrfs=(const struct btrfs_super_block*)buffer_1024; + const struct gfs2_sb *gfs2=(const struct gfs2_sb *)buffer_1024; + /* 64k offset */ + /* Test ReiserFS */ + if((memcmp(rfs->s_magic,"ReIs",4) == 0 || + memcmp(rfs4->magic,REISERFS4_SUPER_MAGIC,sizeof(REISERFS4_SUPER_MAGIC)) == 0) && + recover_rfs(disk, rfs, partition, verbose, dump_ind)==0) + return 1; + /* Test UFS2 */ + if((le32(ufs->fs_magic)==UFS_MAGIC || be32(ufs->fs_magic)==UFS_MAGIC || + le32(ufs->fs_magic)==UFS2_MAGIC || be32(ufs->fs_magic)==UFS2_MAGIC) && + recover_ufs(disk, ufs, partition, verbose, dump_ind)==0) + return 1; + if(memcmp(&btrfs->magic, BTRFS_MAGIC, 8)==0 && + recover_btrfs(disk, btrfs, partition, verbose, dump_ind)==0) + return 1; + if(gfs2->sb_header.mh_magic==be32(GFS2_MAGIC) && + recover_gfs2(disk, gfs2, partition, dump_ind)==0) + return 1; + } +#endif + return 0; +} + +int search_type_2048(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) +{ + if(verbose>2) + { + log_trace("search_type_2048 lba=%lu\n", + (long unsigned)(partition->part_offset/disk->sector_size)); + } + if(disk->pread(disk, buffer, 2*DEFAULT_SECTOR_SIZE, partition->part_offset + 2048 * 512) != 2*DEFAULT_SECTOR_SIZE) + return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + { + const struct vmfs_volume *sb_vmfs=(const struct vmfs_volume *)buffer; + if(le32(sb_vmfs->magic)==0xc001d00d && + recover_VMFS(disk, sb_vmfs, partition, verbose, dump_ind)==0) + return 1; + } +#endif + return 0; +} + +int check_linux(disk_t *disk, partition_t *partition, const int verbose) +{ +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) + if(check_JFS(disk, partition)==0 || + check_rfs(disk, partition, verbose)==0 || + check_EXT2(disk, partition, verbose)==0 || + check_cramfs(disk, partition, verbose)==0 || + check_xfs(disk, partition, verbose)==0 || + check_LUKS(disk, partition)==0 || + check_btrfs(disk, partition)==0 || + check_f2fs(disk, partition)==0 || + check_gfs2(disk, partition)==0 || + check_ZFS(disk, partition)==0) + return 0; +#endif + return 1; +} + diff --git a/subprojects/lib/src/analyse.h b/subprojects/lib/src/analyse.h new file mode 100644 index 0000000..6b3f383 --- /dev/null +++ b/subprojects/lib/src/analyse.h @@ -0,0 +1,148 @@ +/* + + file: analyse.h + + Copyright (C) 1998-2004 Christophe GRENIER + + this software is free software; you can redistribute it and/or modify + it under the terms of the gnu general public license as published by + the free software foundation; either version 2 of the license, or + (at your option) any later version. + + this program is distributed in the hope that it will be useful, + but without any warranty; without even the implied warranty of + merchantability or fitness for a particular purpose. see the + gnu general public license for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _ANALYSE_H +#define _ANALYSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_0(const unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_1(const unsigned char *buffer, const disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_2(const unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_8(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_16(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_64(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_128(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_type_2048(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk, partition); + @*/ +int search_exFAT_backup(unsigned char *buffer, disk_t *disk, partition_t *partition); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_FAT_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_HFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(buffer, disk_car, partition); + @*/ +int search_NTFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, partition); + @*/ +int check_linux(disk_t *disk, partition_t *partition, const int verbose); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/apfs.c b/subprojects/lib/src/apfs.c new file mode 100644 index 0000000..94a6123 --- /dev/null +++ b/subprojects/lib/src/apfs.c @@ -0,0 +1,105 @@ +/* + + File: apfs.c + + Copyright (C) 2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "apfs.h" +#include "fnctdsk.h" +#include "log.h" +#include "guid_cpy.h" + +static void set_APFS_info(const nx_superblock_t *sb, partition_t *partition) +{ + partition->upart_type=UP_APFS; +} + +int check_APFS(disk_t *disk_car, partition_t *partition) +{ + unsigned char *buffer=(unsigned char*)MALLOC(APFS_SUPERBLOCK_SIZE); + const nx_superblock_t* sb=(const nx_superblock_t *)buffer; + if(disk_car->pread(disk_car, buffer, APFS_SUPERBLOCK_SIZE, partition->part_offset) != APFS_SUPERBLOCK_SIZE) + { + free(buffer); + return 1; + } + if(test_APFS(sb, partition)!=0) + { + free(buffer); + return 1; + } + set_APFS_info(sb, partition); + free(buffer); + return 0; +} + +int recover_APFS(const disk_t *disk, const nx_superblock_t *sb, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_APFS(sb, partition)!=0) + return 1; + if(dump_ind!=0) + { + if(partition!=NULL && disk!=NULL) + log_info("\nAPFS magic value at %u/%u/%u\n", + offset2cylinder(disk,partition->part_offset), + offset2head(disk,partition->part_offset), + offset2sector(disk,partition->part_offset)); + /* There is a little offset ... */ + dump_log(sb,DEFAULT_SECTOR_SIZE); + } + if(partition==NULL) + return 0; + set_APFS_info(sb, partition); + partition->part_type_i386=P_LINUX; + partition->part_type_mac=PMAC_LINUX; + partition->part_type_sun=PSUN_LINUX; + partition->part_type_gpt=GPT_ENT_TYPE_MAC_APFS; + partition->part_size=le32(sb->nx_block_size) * le64(sb->nx_block_count); + guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->nx_uuid); + if(verbose>0) + { + log_info("\n"); + } + partition->sborg_offset=0; + partition->sb_size=le32(sb->nx_block_size); + partition->sb_offset=0; + if(verbose>0) + { + log_info("recover_APFS: s_blocksize=%u\n", partition->blocksize); + log_info("recover_APFS: s_blocks_count %lu\n", (long unsigned int)le64(sb->nx_block_count)); + if(disk==NULL) + log_info("recover_APFS: part_size %lu\n", (long unsigned)(partition->part_size / DEFAULT_SECTOR_SIZE)); + else + log_info("recover_APFS: part_size %lu\n", (long unsigned)(partition->part_size / disk->sector_size)); + } + return 0; +} diff --git a/subprojects/lib/src/apfs.h b/subprojects/lib/src/apfs.h new file mode 100644 index 0000000..b9163c4 --- /dev/null +++ b/subprojects/lib/src/apfs.h @@ -0,0 +1,48 @@ +/* + + File: apfs.h + + Copyright (C) 2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _APFS_H +#define _APFS_H +#include "apfs_common.h" +#ifdef __cplusplus +extern "C" { +#endif +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_APFS(disk_t *disk_car, partition_t *partition); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(sb); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int recover_APFS(const disk_t *disk_car, const nx_superblock_t *sb, partition_t *partition, const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/apfs_common.c b/subprojects/lib/src/apfs_common.c new file mode 100644 index 0000000..ee3d25c --- /dev/null +++ b/subprojects/lib/src/apfs_common.c @@ -0,0 +1,85 @@ +/* + + File: apfs_common.c + + Copyright (C) 2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "apfs_common.h" +#include "log.h" + +/*@ + @ requires \valid_read((char *)data + (0 .. cnt-1)); + @ assigns \nothing; + @*/ +static uint64_t fletcher64(const uint32_t *data, const size_t cnt, const uint64_t init) +{ + size_t k; + uint64_t sum1 = init & 0xFFFFFFFFU; + uint64_t sum2 = (init >> 32); + /*@ loop assigns k, sum1, sum2; */ + for (k = 0; k < cnt; k++) + { + sum1 = (sum1 + le32(data[k])); + sum2 = (sum2 + sum1); + } + sum1 = sum1 % 0xFFFFFFFF; + sum2 = sum2 % 0xFFFFFFFF; + return (sum2 << 32) | sum1; +} + +/*@ + @ requires \valid_read((char *)block+ (0 .. size-1)); + @ assigns \nothing; + @*/ +static uint64_t VerifyBlock(const void *block, const size_t size) +{ + uint64_t cs; + const uint32_t *data = (const uint32_t *)block; + const size_t size4 = size / sizeof(uint32_t); + + cs = fletcher64(data + 2, size4 - 2, 0); + cs = fletcher64(data, 2, cs); + return cs; +} + +int test_APFS(const nx_superblock_t *sb, const partition_t *partition) +{ + if(le32(sb->nx_magic)!=0x4253584e) + return 1; + if(le32(sb->nx_xp_desc_blocks) + le32(sb->nx_xp_data_blocks) > le64(sb->nx_block_count)) + return 2; + if(le32(sb->nx_block_size) < NX_MINIMUM_BLOCK_SIZE || + le32(sb->nx_block_size) > NX_MAXIMUM_BLOCK_SIZE) + return 3; + if(VerifyBlock(sb, 4096) != 0) + return 4; + return 0; +} diff --git a/subprojects/lib/src/apfs_common.h b/subprojects/lib/src/apfs_common.h new file mode 100644 index 0000000..724c713 --- /dev/null +++ b/subprojects/lib/src/apfs_common.h @@ -0,0 +1,104 @@ +#ifndef _APFS_COMMON_H +#define _APFS_COMMON_H +#ifdef __cplusplus +extern "C" +{ +#endif +#define MAX_CKSUM_SIZE 8 +#define NX_EPH_INFO_COUNT 4 +#define NX_EPH_INFO_VERSION_1 1 +#define NX_EPH_MIN_BLOCK_COUNT 8 +#define NX_MAGIC 'BSXN' +#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 +#define NX_MAX_FILE_SYSTEMS 100 +#define NX_MAXIMUM_BLOCK_SIZE 65536 +#define NX_MINIMUM_BLOCK_SIZE 4096 +#define NX_TX_MIN_CHECKPOINT_COUNT 4 + + typedef enum { + NX_CNTR_OBJ_CKSUM_SET + = 0, + NX_CNTR_OBJ_CKSUM_FAIL = 1, + NX_NUM_COUNTERS = 32 + } nx_counter_id_t; + + typedef uint64_t oid_t; + typedef uint64_t xid_t; + + struct obj_phys { + uint8_t o_cksum[MAX_CKSUM_SIZE]; + oid_t o_oid; + xid_t o_xid; + uint32_t o_type; + uint32_t o_subtype; + } __attribute__((gcc_struct, __packed__)); + + typedef struct obj_phys obj_phys_t; + typedef int64_t paddr_t; + + struct prange { + paddr_t pr_start_paddr; + uint64_t pr_block_count; + } __attribute__((gcc_struct, __packed__)); + typedef struct prange prange_t; + + typedef unsigned char apfs_uuid_t[16]; + + struct nx_superblock { + obj_phys_t nx_o; + uint32_t nx_magic; + uint32_t nx_block_size; + uint64_t nx_block_count; + uint64_t nx_features; + uint64_t nx_readonly_compatible_features; + uint64_t nx_incompatible_features; + apfs_uuid_t nx_uuid; + oid_t nx_next_oid; + xid_t nx_next_xid; + uint32_t nx_xp_desc_blocks; + uint32_t nx_xp_data_blocks; + paddr_t nx_xp_desc_base; + paddr_t nx_xp_data_base; + uint32_t nx_xp_desc_next; + uint32_t nx_xp_data_next; + uint32_t nx_xp_desc_index; + uint32_t nx_xp_desc_len; + uint32_t nx_xp_data_index; + uint32_t nx_xp_data_len; + oid_t nx_spaceman_oid; + oid_t nx_omap_oid; + oid_t nx_reaper_oid; + uint32_t nx_test_type; + uint32_t nx_max_file_systems; + oid_t nx_fs_oid[NX_MAX_FILE_SYSTEMS]; + uint64_t nx_counters[NX_NUM_COUNTERS]; + prange_t nx_blocked_out_prange; + oid_t nx_evict_mapping_tree_oid; + uint64_t nx_flags; + paddr_t nx_efi_jumpstart; + apfs_uuid_t nx_fusion_uuid; + prange_t nx_keylocker; + uint64_t nx_ephemeral_info[NX_EPH_INFO_COUNT]; + oid_t nx_test_oid; + oid_t nx_fusion_mt_oid; + oid_t nx_fusion_wbc_oid; + prange_t nx_fusion_wbc; + uint64_t nx_newest_mounted_version; + prange_t nx_mkb_locker; + }; +typedef struct nx_superblock nx_superblock_t; + +//#define APFS_SUPERBLOCK_SIZE (sizeof(nx_superblock_t)) +#define APFS_SUPERBLOCK_SIZE 4096 +/*@ + @ requires \valid_read(sb); + @ requires partition==\null || (\valid_read(partition) && valid_partition(partition)); + @ requires \separated(sb, partition); + @ assigns \nothing; + @ */ +int test_APFS(const nx_superblock_t *sb, const partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/autoset.c b/subprojects/lib/src/autoset.c new file mode 100644 index 0000000..bc44fd2 --- /dev/null +++ b/subprojects/lib/src/autoset.c @@ -0,0 +1,58 @@ +/* + + File: autoset.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "autoset.h" + +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) +extern const arch_fnct_t arch_gpt; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) +extern const arch_fnct_t arch_humax; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) +extern const arch_fnct_t arch_mac; +#endif + +void autoset_unit(disk_t *disk) +{ + if(disk==NULL) + return ; + if( +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) + disk->arch==&arch_gpt || +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) + disk->arch==&arch_humax || +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) + disk->arch==&arch_mac || +#endif + (disk->geom.heads_per_cylinder==1 && disk->geom.sectors_per_head==1)) + disk->unit=UNIT_SECTOR; + else + disk->unit=UNIT_CHS; +} diff --git a/subprojects/lib/src/autoset.h b/subprojects/lib/src/autoset.h new file mode 100644 index 0000000..a7f512b --- /dev/null +++ b/subprojects/lib/src/autoset.h @@ -0,0 +1,38 @@ +/* + + File: autoset.h + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _AUTOSET_H +#define _AUTOSET_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ assigns disk_car->unit; + @*/ +void autoset_unit(disk_t *disk_car); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/bfs.c b/subprojects/lib/src/bfs.c new file mode 100644 index 0000000..fb8f35d --- /dev/null +++ b/subprojects/lib/src/bfs.c @@ -0,0 +1,92 @@ +/* + + File: bfs.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "types.h" +#include "common.h" +#include "bfs.h" +#include "fnctdsk.h" +#include "log.h" + +static void set_BeFS_info(const struct disk_super_block *beos_block, partition_t *partition) +{ + partition->upart_type=UP_BEOS; + partition->blocksize= 1 << le32(beos_block->block_shift); + partition->info[0]='\0'; + snprintf(partition->info, sizeof(partition->info), "BeFS blocksize=%u", partition->blocksize); + set_part_name(partition,beos_block->name,B_OS_NAME_LENGTH); +} + +static int test_BeFS(const disk_t *disk_car, const struct disk_super_block*beos_block, const partition_t *partition, const int dump_ind) +{ + if(beos_block->magic1!=le32(SUPER_BLOCK_MAGIC1) && + beos_block->magic2!=le32(SUPER_BLOCK_MAGIC2) && + beos_block->magic3!=le32(SUPER_BLOCK_MAGIC3)) + return 1; + if(partition==NULL) + return 0; + if(dump_ind!=0) + { + log_info("\nBeFS magic value at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset)); + dump_log(beos_block,DEFAULT_SECTOR_SIZE); + } + return 0; +} + + +int check_BeFS(disk_t *disk_car,partition_t *partition) +{ + unsigned char *buffer; + buffer=(unsigned char*)MALLOC(BFS_SUPERBLOCK_SIZE); + if(disk_car->pread(disk_car, buffer, BFS_SUPERBLOCK_SIZE, partition->part_offset + 0x200) != BFS_SUPERBLOCK_SIZE) + { + free(buffer); + return 1; + } + if(test_BeFS(disk_car,(struct disk_super_block*)buffer,partition,0)!=0) + { + free(buffer); + return 1; + } + set_BeFS_info((struct disk_super_block*)buffer, partition); + free(buffer); + return 0; +} + +int recover_BeFS(const disk_t *disk_car, const struct disk_super_block *beos_block, partition_t *partition, const int dump_ind) +{ + if(test_BeFS(disk_car,beos_block,partition,dump_ind)!=0) + return 1; + set_BeFS_info(beos_block, partition); + partition->part_size=le64(beos_block->num_blocks) << le32(beos_block->block_shift); + partition->part_type_i386=(unsigned char)P_BEOS; + partition->part_type_mac=PMAC_BEOS; + partition->part_type_gpt=GPT_ENT_TYPE_BEOS_BFS; + return 0; +} diff --git a/subprojects/lib/src/bfs.h b/subprojects/lib/src/bfs.h new file mode 100644 index 0000000..fb3dd7d --- /dev/null +++ b/subprojects/lib/src/bfs.h @@ -0,0 +1,108 @@ +/* + + File: bfs.h + + Copyright (C) 1998-2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _BFS_H +#define _BFS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* real size is 164 */ +#define BFS_SUPERBLOCK_SIZE 512 + +typedef struct block_run +{ + uint32_t allocation_group; + uint16_t start; + uint16_t len; /* in blocks */ +} block_run; + +typedef block_run inode_addr; + + +#define B_OS_NAME_LENGTH 32 + +struct disk_super_block /* super block as it is on disk */ +{ + char name[B_OS_NAME_LENGTH]; + uint32_t magic1; /* 0x20 */ + uint32_t fs_byte_order; /* 0x24 */ + + uint32_t block_size; /* 0x28 in bytes */ + uint32_t block_shift; /* 0x2C block_size == (1 << block_shift) */ + + uint64_t num_blocks; /* 0x30 */ + uint64_t used_blocks; /* 0x38 */ + + uint32_t inode_size; /* 0x40 # of bytes per inode */ + + uint32_t magic2; /* 0x44 */ + uint32_t blocks_per_ag; /* 0x48 in blocks */ + uint32_t ag_shift; /* 0x4C # of bits to shift to get ag num */ + uint32_t num_ags; /* 0x50 # of allocation groups */ + uint32_t flags; /* 0x54 if it's clean, etc */ + block_run log_blocks; /* 0x58 a block_run of the log blocks */ + uint64_t log_start; /* 0x60 block # of the beginning */ + uint64_t log_end; /* 0x68 block # of the end of the log */ + + uint32_t magic3; /* 0x70 */ + inode_addr root_dir; /* 0x74 */ + inode_addr indices; /* 0x7C */ + + uint32_t pad[8]; /* 0x84 extra stuff for the future */ + /* 0xA4-0xFF */ +}; + + +/*the flags field can have these values */ +#define BFS_CLEAN 0x434c454e /* 'CLEN', for flags field */ +#define BFS_DIRTY 0x44495254 /* 'DIRT', for flags field */ + +/* these are the magic numbers for the 3 magic fields */ +#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */ +#define SUPER_BLOCK_MAGIC2 0xdd121031 +#define SUPER_BLOCK_MAGIC3 0x15b6830e + +/* this is stored in the fs_byte_order field... it's kind of dumb */ +#define BFS_BIG_ENDIAN 0x42494745 /* BIGE */ +/* int test_beos(struct disk_super_block *,partition_t); */ + +/*@ + @ requires \valid(disk_car); + @ requires \valid(partition); + @ requires valid_disk(disk_car); + @ requires separation: \separated(disk_car, partition); + @*/ +int check_BeFS(disk_t *disk_car, partition_t *partition); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(beos_block); + @ requires \valid(partition); + @ requires separation: \separated(disk_car, beos_block, partition); + @*/ +int recover_BeFS(const disk_t *disk_car, const struct disk_super_block *beos_block, partition_t *partition, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/bsd.c b/subprojects/lib/src/bsd.c new file mode 100644 index 0000000..13dd9b9 --- /dev/null +++ b/subprojects/lib/src/bsd.c @@ -0,0 +1,174 @@ +/* + + File: bsd.c + + Copyright (C) 1998-2006,2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include "types.h" +#include "common.h" +#include "bsd.h" +#include "intrf.h" +#include "log.h" + +static int test_BSD(const disk_t *disk_car, const struct disklabel*bsd_header, const partition_t *partition,const int verbose, const int dump_ind, const unsigned int max_partitions) +{ + unsigned int i; + const uint16_t* cp; + uint16_t crc; + if(le32(bsd_header->d_magic) != DISKMAGIC || le32(bsd_header->d_magic2)!=DISKMAGIC) + return 0; + if(verbose) + log_info("\nBSD offset %lu, nbr_part %u, CHS=(%u,%u,%u) ", + (long unsigned)(partition->part_offset/disk_car->sector_size), + (unsigned int)le16(bsd_header->d_npartitions), + (unsigned int)le32(bsd_header->d_ncylinders), + (unsigned int)le32(bsd_header->d_ntracks), + (unsigned int)le32(bsd_header->d_nsectors)); + if(le16(bsd_header->d_npartitions) > max_partitions) + return 1; + crc=0; + for(cp=(const uint16_t*)bsd_header; + cp<(const uint16_t*)&bsd_header->d_partitions[le16(bsd_header->d_npartitions)];cp++) + crc^=*cp; + if(crc==0) + { + if(verbose>0) + { + log_info("CRC Ok\n"); + } + } + else + log_error("Bad CRC! CRC must be xor'd by %04X\n",crc); + for(i=0;id_npartitions);i++) + { + if(bsd_header->d_partitions[i].p_fstype>0) + { + if(verbose>0) + { + /* UFS UFS2 SWAP */ + log_info("BSD %c: ", 'a'+i); + switch(bsd_header->d_partitions[i].p_fstype) + { + case TST_FS_SWAP: + log_info("swap"); + break; + case TST_FS_BSDFFS: + log_info("4.2BSD fast filesystem"); + break; + case TST_FS_BSDLFS: + log_info("4.4BSD log-structured filesystem"); + break; + default: + log_info("type %02X", bsd_header->d_partitions[i].p_fstype); + break; + } + log_info(", offset %9u, size %9u ", + (unsigned int)le32(bsd_header->d_partitions[i].p_offset), + (unsigned int)le32(bsd_header->d_partitions[i].p_size)); + log_CHS_from_LBA(disk_car,le32(bsd_header->d_partitions[i].p_offset)); + log_info(" -> "); + log_CHS_from_LBA(disk_car,le32(bsd_header->d_partitions[i].p_offset)+le32(bsd_header->d_partitions[i].p_size)-1); + log_info("\n"); + } + } + } + if(crc) + return 1; + if(dump_ind!=0) + { + dump_log(bsd_header,DEFAULT_SECTOR_SIZE); + } + return 0; +} + +int check_BSD(disk_t *disk_car,partition_t *partition,const int verbose, const unsigned int max_partitions) +{ + unsigned char *buffer; + buffer=(unsigned char*)MALLOC(BSD_DISKLABEL_SIZE); + if(disk_car->pread(disk_car, buffer, BSD_DISKLABEL_SIZE, partition->part_offset + 0x200) != BSD_DISKLABEL_SIZE) + { + free(buffer); + return 1; + } + if(test_BSD(disk_car,(const struct disklabel*)buffer,partition,verbose,0,max_partitions)) + { + free(buffer); + return 1; + } + set_part_name(partition,((const struct disklabel*)buffer)->d_packname,16); + free(buffer); + return 0; +} + +int recover_BSD(const disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind) +{ + int i; + int i_max_p_offset=-1; + if(test_BSD(disk_car,bsd_header,partition,verbose,dump_ind,BSD_MAXPARTITIONS)==0) + { + partition->upart_type=UP_FREEBSD; + for(i=0;id_partitions[i].p_fstype>0) + { + if(i_max_p_offset==-1 || le32(bsd_header->d_partitions[i].p_offset)>le32(bsd_header->d_partitions[i_max_p_offset].p_offset)) + i_max_p_offset=i; + } + } + if(i_max_p_offset>=0) + partition->part_size=(uint64_t)(le32(bsd_header->d_partitions[i_max_p_offset].p_size) + + le32(bsd_header->d_partitions[i_max_p_offset].p_offset) - 1) * disk_car->sector_size - partition->part_offset; + else + partition->part_size=0; + partition->part_type_i386=P_FREEBSD; + set_part_name(partition,bsd_header->d_packname,16); + partition->info[0]='\0'; + return 0; + } + if(test_BSD(disk_car,bsd_header,partition,verbose,dump_ind,OPENBSD_MAXPARTITIONS)==0) + { + partition->upart_type=UP_OPENBSD; + for(i=0;id_partitions[i].p_fstype>0) + { + if(i_max_p_offset==-1 || le32(bsd_header->d_partitions[i].p_offset)>le32(bsd_header->d_partitions[i_max_p_offset].p_offset)) + i_max_p_offset=i; + } + } + if(i_max_p_offset>=0) + partition->part_size=(uint64_t)(le32(bsd_header->d_partitions[i_max_p_offset].p_size) + + le32(bsd_header->d_partitions[i_max_p_offset].p_offset) - 1) * disk_car->sector_size - partition->part_offset; + else + partition->part_size=0; + partition->part_type_i386=P_OPENBSD; + set_part_name(partition,bsd_header->d_packname,16); + partition->info[0]='\0'; + return 0; + } + return 1; +} diff --git a/subprojects/lib/src/bsd.h b/subprojects/lib/src/bsd.h new file mode 100644 index 0000000..52c9f02 --- /dev/null +++ b/subprojects/lib/src/bsd.h @@ -0,0 +1,192 @@ +/* + + File: bsd.h + + Copyright (C) 1998-2004,2006,2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +/* Come mainly from sys/disklabel.h and disktab.h */ + +#ifndef _BSD_H +#define _BSD_H +#ifdef __cplusplus +extern "C" { +#endif +/* BSD_DISKLABEL_SIZE is 276 */ +#define BSD_DISKLABEL_SIZE 512 +#define STANDALONE + +#define BBSIZE 8192 /* size of boot area, with label */ + +#ifdef __i386__ +#define LABELSECTOR 1 /* sector containing label */ +#define LABELOFFSET 0 /* offset of label in sector */ +#endif + +#ifndef LABELSECTOR +#define LABELSECTOR 0 /* sector containing label */ +#endif + +#ifndef LABELOFFSET +#define LABELOFFSET 64 /* offset of label in sector */ +#endif + +#define DISKMAGIC ((uint32_t)0x82564557) /* The disk magic number */ + +#define LABEL_PART 2 /* partition containing label */ +#define RAW_PART 2 /* partition containing whole disk */ +#define SWAP_PART 1 /* partition normally containing swap */ + +struct disklabel { + uint32_t d_magic; /* the magic number */ + uint16_t d_type; /* drive type */ + uint16_t d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + + /* + * d_packname contains the pack identifier and is returned when + * the disklabel is read off the disk or in-core copy. + * d_boot0 and d_boot1 are the (optional) names of the + * primary (block 0) and secondary (block 1-15) bootstraps + * as found in /usr/mdec. These are returned when using + * getdiskbyname(3) to retrieve the values from /etc/disktab. + */ +#if defined(KERNEL) || defined(STANDALONE) + char d_packname[16]; /* pack identifier */ +#else + union { + char un_d_packname[16]; /* pack identifier */ + struct { + char *un_d_boot0; /* primary bootstrap name */ + char *un_d_boot1; /* secondary bootstrap name */ + } un_b; + } d_un; +#define d_packname d_un.un_d_packname +#define d_boot0 d_un.un_b.un_d_boot0 +#define d_boot1 d_un.un_b.un_d_boot1 +#endif /* ! KERNEL or STANDALONE */ + + /* disk geometry: */ + uint32_t d_secsize; /* # of bytes per sector */ + uint32_t d_nsectors; /* # of data sectors per track */ + uint32_t d_ntracks; /* # of tracks per cylinder */ + uint32_t d_ncylinders; /* # of data cylinders per unit */ + uint32_t d_secpercyl; /* # of data sectors per cylinder */ + uint32_t d_secperunit; /* # of data sectors per unit */ + + /* + * Spares (bad sector replacements) below are not counted in + * d_nsectors or d_secpercyl. Spare sectors are assumed to + * be physical sectors which occupy space at the end of each + * track and/or cylinder. + */ + uint16_t d_sparespertrack; /* # of spare sectors per track */ + uint16_t d_sparespercyl; /* # of spare sectors per cylinder */ + /* + * Alternate cylinders include maintenance, replacement, configuration + * description areas, etc. + */ + uint32_t d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the + * formatter or controller when formatting. When interleaving is + * in use, logically adjacent sectors are not physically + * contiguous, but instead are separated by some number of + * sectors. It is specified as the ratio of physical sectors + * traversed per logical sector. Thus an interleave of 1:1 + * implies contiguous layout, while 2:1 implies that logical + * sector 0 is separated by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N relative to + * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew + * is the offset of sector 0 on cylinder N relative to sector 0 + * on cylinder N-1. + */ + uint16_t d_rpm; /* rotational speed */ + uint16_t d_interleave; /* hardware sector interleave */ + uint16_t d_trackskew; /* sector 0 skew, per track */ + uint16_t d_cylskew; /* sector 0 skew, per cylinder */ + uint32_t d_headswitch; /* head switch time, usec */ + uint32_t d_trkseek; /* track-to-track seek, usec */ + uint32_t d_flags; /* generic flags */ +#define NDDATA 5 + uint32_t d_drivedata[NDDATA]; /* drive-type specific information */ +#define NSPARE 5 + uint32_t d_spare[NSPARE]; /* reserved for future use */ + uint32_t d_magic2; /* the magic number (again) */ + uint16_t d_checksum; /* xor of data incl. partitions */ + + /* filesystem and partition information: */ + uint16_t d_npartitions; /* number of partitions in following */ + uint32_t d_bbsize; /* size of boot area at sn0, bytes */ + uint32_t d_sbsize; /* max size of fs superblock, bytes */ + struct partition { /* the partition table */ + uint32_t p_size; /* number of sectors in partition */ + uint32_t p_offset; /* starting sector */ + uint32_t p_fsize; /* filesystem basic fragment size */ + uint8_t p_fstype; /* filesystem type, see below */ + uint8_t p_frag; /* filesystem fragments per block */ + union { + uint16_t cpg; /* UFS: FS cylinders per group */ + uint16_t sgs; /* LFS: FS segment shift */ + } __partition_u1; +#define p_cpg __partition_u1.cpg +#define p_sgs __partition_u1.sgs + } d_partitions[OPENBSD_MAXPARTITIONS]; /* actually may be more */ +}; +#define TST_FS_UNUSED 0 /* unused */ +#define TST_FS_SWAP 1 /* swap */ +#define TST_FS_V6 2 /* Sixth Edition */ +#define TST_FS_V7 3 /* Seventh Edition */ +#define TST_FS_SYSV 4 /* System V */ +#define TST_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define TST_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define TST_FS_BSDFFS 7 /* 4.2BSD fast filesystem */ +#define TST_FS_MSDOS 8 /* MSDOS filesystem */ +#define TST_FS_BSDLFS 9 /* 4.4BSD log-structured filesystem */ +#define TST_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define TST_FS_HPFS 11 /* OS/2 high-performance filesystem */ +#define TST_FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ +#define TST_FS_BOOT 13 /* partition contains bootstrap */ +#define TST_FS_VINUM 14 /* Vinum drive */ +#define TST_FS_RAID 15 /* RAIDFrame drive */ +#define TST_FS_JFS2 21 /* IBM JFS2 */ + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires separation: \separated(disk_car, partition); + @*/ +int check_BSD(disk_t *disk_car, partition_t *partition, const int verbose, const unsigned int max_partitions); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(bsd_header); + @ requires \valid(partition); + @ requires separation: \separated(disk_car, bsd_header, partition); + @*/ +int recover_BSD(const disk_t *disk_car, const struct disklabel*bsd_header, partition_t *partition, const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/btrfs.c b/subprojects/lib/src/btrfs.c new file mode 100644 index 0000000..4eef0bb --- /dev/null +++ b/subprojects/lib/src/btrfs.c @@ -0,0 +1,122 @@ +/* + + File: btrfs.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "btrfs.h" +#include "fnctdsk.h" +#include "log.h" +#include "guid_cpy.h" + +static int test_btrfs(const struct btrfs_super_block *sb); + +static void set_btrfs_info(const struct btrfs_super_block *sb, partition_t *partition) +{ + partition->upart_type=UP_BTRFS; + partition->blocksize=le32(sb->dev_item.sector_size); + set_part_name(partition, sb->label, sizeof(sb->label)); + snprintf(partition->info, sizeof(partition->info), "btrfs blocksize=%u", partition->blocksize); + if(le64(sb->bytenr)!=partition->part_offset + BTRFS_SUPER_INFO_OFFSET) + { + strcat(partition->info," Backup superblock"); + } + /* last mounted => date */ +} + +int check_btrfs(disk_t *disk_car,partition_t *partition) +{ + unsigned char *buffer=(unsigned char*)MALLOC(BTRFS_SUPER_INFO_SIZE); + if(disk_car->pread(disk_car, buffer, BTRFS_SUPER_INFO_SIZE, partition->part_offset + BTRFS_SUPER_INFO_OFFSET) != BTRFS_SUPER_INFO_SIZE) + { + free(buffer); + return 1; + } + if(test_btrfs((struct btrfs_super_block*)buffer)!=0) + { + free(buffer); + return 1; + } + set_btrfs_info((struct btrfs_super_block*)buffer, partition); + free(buffer); + return 0; +} + +/* +Primary superblock is at 1024 (SUPERBLOCK_OFFSET) +Group 0 begin at s_first_data_block +*/ +int recover_btrfs(const disk_t *disk, const struct btrfs_super_block *sb, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_btrfs(sb)!=0) + return 1; + if(dump_ind!=0) + { + if(partition!=NULL && disk!=NULL) + log_info("\nbtrfs magic value at %u/%u/%u\n", + offset2cylinder(disk,partition->part_offset), + offset2head(disk,partition->part_offset), + offset2sector(disk,partition->part_offset)); + dump_log(sb, BTRFS_SUPER_INFO_SIZE); + } + if(partition==NULL) + return 0; + set_btrfs_info(sb, partition); + partition->part_type_i386=P_LINUX; + partition->part_type_mac=PMAC_LINUX; + partition->part_type_sun=PSUN_LINUX; + partition->part_type_gpt=GPT_ENT_TYPE_LINUX_DATA; + partition->part_size=(uint64_t)le64(sb->dev_item.total_bytes); + guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->fsid); + if(verbose>0) + { + log_info("\n"); + } + partition->sborg_offset=BTRFS_SUPER_INFO_OFFSET; + partition->sb_size=BTRFS_SUPER_INFO_SIZE; + if(verbose>0) + { + if(disk==NULL) + log_info("recover_btrfs: part_size %lu\n", (long unsigned)(partition->part_size / le32(sb->dev_item.sector_size))); + else + log_info("recover_btrfs: part_size %lu\n", (long unsigned)(partition->part_size / disk->sector_size)); + } + return 0; +} + +static int test_btrfs(const struct btrfs_super_block *sb) +{ + if(memcmp(&sb->magic, BTRFS_MAGIC, 8)!=0) + return 1; + if(le32(sb->dev_item.sector_size)==0) + return 1; + return 0; +} diff --git a/subprojects/lib/src/btrfs.h b/subprojects/lib/src/btrfs.h new file mode 100644 index 0000000..022c696 --- /dev/null +++ b/subprojects/lib/src/btrfs.h @@ -0,0 +1,162 @@ +/* + + File: btrfs.h + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _BTRFS_H +#define _BTRFS_H +#ifdef __cplusplus +extern "C" { +#endif + +#define BTRFS_SUPER_INFO_OFFSET (64 * 1024) +#define BTRFS_SUPER_INFO_SIZE 4096 + +#define BTRFS_SUPER_MIRROR_MAX 3 +#define BTRFS_SUPER_MIRROR_SHIFT 12 +#define BTRFS_MAGIC "_BHRfS_M" + +#define BTRFS_FSID_SIZE 16 + +/* 32 bytes in various csum fields */ +#define BTRFS_CSUM_SIZE 32 +/* + * this is a very generous portion of the super block, giving us + * room to translate 14 chunks with 3 stripes each. + */ +#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 +#define BTRFS_LABEL_SIZE 256 + +/* + * Structure of the super block + * Check http://git.kernel.org/?p=linux/kernel/git/mason/btrfs-progs-unstable.git;a=blob;f=ctree.h;hb=HEAD + * for an up-to-date version + * Fields are in low endian + */ + +#define BTRFS_UUID_SIZE 16 +struct btrfs_dev_item { + /* the internal btrfs device id */ + uint64_t devid; + + /* size of the device */ + uint64_t total_bytes; + + /* bytes used */ + uint64_t bytes_used; + + /* optimal io alignment for this device */ + uint32_t io_align; + + /* optimal io width for this device */ + uint32_t io_width; + + /* minimal io size for this device */ + uint32_t sector_size; + + /* type and info about this device */ + uint64_t type; + + /* expected generation for this device */ + uint64_t generation; + + /* + * starting byte of this partition on the device, + * to allowr for stripe alignment in the future + */ + uint64_t start_offset; + + /* grouping information for allocation decisions */ + uint32_t dev_group; + + /* seek speed 0-100 where 100 is fastest */ + uint8_t seek_speed; + + /* bandwidth 0-100 where 100 is fastest */ + uint8_t bandwidth; + + /* btrfs generated uuid for this device */ + uint8_t uuid[BTRFS_UUID_SIZE]; + + /* uuid of FS who owns this device */ + uint8_t fsid[BTRFS_UUID_SIZE]; +} __attribute__ ((gcc_struct, __packed__)); + +struct btrfs_super_block { + uint8_t csum[BTRFS_CSUM_SIZE]; + /* the first 3 fields must match struct btrfs_header */ + uint8_t fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ + uint64_t bytenr; /* this block number */ + uint64_t flags; + + /* allowed to be different from the btrfs_header from here own down */ + uint64_t magic; + uint64_t generation; + uint64_t root; + uint64_t chunk_root; + uint64_t log_root; + + /* this will help find the new super based on the log root */ + uint64_t log_root_transid; + uint64_t total_bytes; + uint64_t bytes_used; + uint64_t root_dir_objectid; + uint64_t num_devices; + uint32_t sectorsize; + uint32_t nodesize; + uint32_t leafsize; + uint32_t stripesize; + uint32_t sys_chunk_array_size; + uint64_t chunk_root_generation; + uint64_t compat_flags; + uint64_t compat_ro_flags; + uint64_t incompat_flags; + uint16_t csum_type; + uint8_t root_level; + uint8_t chunk_root_level; + uint8_t log_root_level; + struct btrfs_dev_item dev_item; + + char label[BTRFS_LABEL_SIZE]; + + /* future expansion */ + uint64_t reserved[32]; + uint8_t sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_btrfs(disk_t *disk_car, partition_t *partition); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, sb, partition); + @*/ +int recover_btrfs(const disk_t *disk_car, const struct btrfs_super_block *sb,partition_t *partition,const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/chgarch.c b/subprojects/lib/src/chgarch.c new file mode 100644 index 0000000..61baac5 --- /dev/null +++ b/subprojects/lib/src/chgarch.c @@ -0,0 +1,123 @@ +/* + + File: chgarch.c + + Copyright (C) 1998-2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "log.h" +#include "log_part.h" +#include "autoset.h" +#include "hdaccess.h" +#include "chgarch.h" + +extern const arch_fnct_t arch_none; +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) +extern const arch_fnct_t arch_gpt; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) +extern const arch_fnct_t arch_humax; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) +extern const arch_fnct_t arch_i386; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) +extern const arch_fnct_t arch_mac; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_SUN) +extern const arch_fnct_t arch_sun; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_XBOX) +extern const arch_fnct_t arch_xbox; +#endif + +/* return 1 if user need to give the partition table type */ +int change_arch_type_cli(disk_t *disk, const int verbose, char**current_cmd) +{ +#ifndef __FRAMAC__ + const arch_fnct_t *arch_list[]={ +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + &arch_i386, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) + &arch_gpt, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_HUMAX) + &arch_humax, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) + &arch_mac, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_NONE) + &arch_none, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_SUN) + &arch_sun, +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_XBOX) + &arch_xbox, +#endif + NULL}; + int keep_asking; + if(*current_cmd==NULL) + return 1; + /*@ assert valid_read_string(*current_cmd); */ + /*@ + loop invariant valid_read_string(*current_cmd); + */ + do + { + int i; + keep_asking=0; + skip_comma_in_command(current_cmd); + /*@ + loop unroll 10; + @*/ + for(i=0; arch_list[i]!=NULL; i++) + { + if(check_command(current_cmd, arch_list[i]->part_name_option, strlen(arch_list[i]->part_name_option))==0) + { + disk->arch=arch_list[i]; + keep_asking=1; + } + } + if(check_command(current_cmd, "ask_type", 8)==0) + { + return 1; + } + } while(keep_asking>0); + autoset_unit(disk); + hd_update_geometry(disk, verbose); + log_info("%s\n",disk->description_short(disk)); + log_info("Partition table type: %s\n", disk->arch->part_name); +#endif + /*@ assert valid_disk(disk); */ + return 0; +} diff --git a/subprojects/lib/src/chgarch.h b/subprojects/lib/src/chgarch.h new file mode 100644 index 0000000..505763a --- /dev/null +++ b/subprojects/lib/src/chgarch.h @@ -0,0 +1,43 @@ + +/* + + File: chgarch.h + + Copyright (C) 1998-2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _CHGARCH_H +#define _CHGARCH_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(current_cmd); + @ requires \valid(disk); + @ requires \separated(disk, current_cmd); + @ requires valid_disk(disk); + @ requires current_cmd == \null || valid_read_string(*current_cmd); + @ ensures current_cmd == \null || valid_read_string(*current_cmd); + @ ensures valid_disk(disk); + @*/ +int change_arch_type_cli(disk_t *disk, const int verbose, char**current_cmd); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/chgtype.c b/subprojects/lib/src/chgtype.c new file mode 100644 index 0000000..08e9bf6 --- /dev/null +++ b/subprojects/lib/src/chgtype.c @@ -0,0 +1,98 @@ +/* + + File: chgtype.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "chgtype.h" +#include "log.h" +#include "log_part.h" + +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) +extern const arch_fnct_t arch_gpt; +extern const arch_fnct_t arch_none; +#endif + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ ensures valid_read_string(*current_cmd); + @*/ +// TODO assigns *current_cmd; +static int get_hex_from_command(char **current_cmd) +{ + const int tmp=strtol(*current_cmd, NULL, 16); + /*@ + @ loop invariant valid_read_string(*current_cmd); + @ loop assigns *current_cmd; + @*/ + while(*current_cmd[0]!=',' && *current_cmd[0]!='\0') + (*current_cmd)++; + /*@ assert valid_read_string(*current_cmd); */ + return tmp; +} + +void change_part_type_cli(const disk_t *disk_car,partition_t *partition, char **current_cmd) +{ + assert(current_cmd!=NULL); + assert(partition!=NULL); + if(*current_cmd==NULL || partition->arch==NULL) + return ; + if(partition->arch==NULL) + return; +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) + if(partition->arch==&arch_gpt) + { + partition->arch=&arch_none; + skip_comma_in_command(current_cmd); + { + const int tmp_val=get_hex_from_command(current_cmd); + partition->arch->set_part_type(partition,tmp_val); + } +#ifndef __FRAMAC__ + log_info("Change partition type:\n"); + log_partition(disk_car,partition); +#endif + partition->arch=&arch_gpt; + return; + } +#endif + if(partition->arch->set_part_type==NULL) + return ; + skip_comma_in_command(current_cmd); + { + const int tmp_val=get_hex_from_command(current_cmd); + partition->arch->set_part_type(partition,tmp_val); + } +#ifndef __FRAMAC__ + log_info("Change partition type:\n"); + log_partition(disk_car,partition); +#endif + return ; +} diff --git a/subprojects/lib/src/chgtype.h b/subprojects/lib/src/chgtype.h new file mode 100644 index 0000000..3365eb5 --- /dev/null +++ b/subprojects/lib/src/chgtype.h @@ -0,0 +1,41 @@ +/* + + File: chgtype.h + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _CHGTYPE_H +#define _CHGTYPE_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid(current_cmd); + @ requires \separated(disk_car, partition, current_cmd); + @*/ +void change_part_type_cli(const disk_t *disk_car,partition_t *partition, char **current_cmd); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/common.c b/subprojects/lib/src/common.c new file mode 100644 index 0000000..caebfd4 --- /dev/null +++ b/subprojects/lib/src/common.c @@ -0,0 +1,423 @@ +/* + + File: common.c + + Copyright (C) 1998-2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __FRAMAC__ +#undef HAVE_POSIX_MEMALIGN +#undef HAVE_MEMALIGN +#undef HAVE_NCURSES +#endif + +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef __MINGW32__ +#ifdef HAVE_IO_H +#include +#endif +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "log.h" + +static int32_t secwest=0; + +/* coverity[+alloc] */ +void *MALLOC(size_t size) +{ + void *res; + assert(size>0); + /* Warning, memory leak checker must be posix_memalign/memalign aware, otherwise * + * reports may look strange. Aligned memory is required if the buffer is * + * used for read/write operation with a file opened with O_DIRECT */ +#if defined(HAVE_POSIX_MEMALIGN) + if(size>=512) + { + if(posix_memalign(&res,4096,size)==0) + { + memset(res,0,size); + return res; + } + } +#elif defined(HAVE_MEMALIGN) + if(size>=512) + { + if((res=memalign(4096, size))!=NULL) + { + memset(res,0,size); + return res; + } + } +#endif +#ifdef __FRAMAC__ + if((res=calloc(1,size))==NULL) + { + exit(EXIT_FAILURE); + } +#else + if((res=malloc(size))==NULL) + { +#ifndef __FRAMAC__ + log_critical("\nCan't allocate %lu bytes of memory.\n", (long unsigned)size); + log_close(); +#endif + exit(EXIT_FAILURE); + } + memset(res,0,size); +#endif + /*@ assert \valid((char *)res + (0 .. size - 1)); */ + return res; +} + +#ifndef HAVE_SNPRINTF +int snprintf(char *str, size_t size, const char *format, ...) +{ + int res; + va_list ap; + va_start(ap,format); + res=vsnprintf(str, size, format, ap); + va_end(ap); + return res; +} +#endif + +#ifndef HAVE_VSNPRINTF +int vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + return vsprintf(str,format,ap); +} +#endif + +#ifndef HAVE_STRNCASECMP +/** Case-insensitive, size-constrained, lexical comparison. + * + * Compares a specified maximum number of characters of two strings for + * lexical equivalence in a case-insensitive manner. + * + * @param[in] s1 - The first string to be compared. + * @param[in] s2 - The second string to be compared. + * @param[in] len - The maximum number of characters to compare. + * + * @return Zero if at least @p len characters of @p s1 are the same as + * the corresponding characters in @p s2 within the ASCII printable + * range; a value less than zero if @p s1 is lexically less than + * @p s2; or a value greater than zero if @p s1 is lexically greater + * than @p s2. + * + * @internal + */ +int strncasecmp(const char * s1, const char * s2, size_t len) +{ + while (*s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2))) + { + len--; + if (len == 0) + return 0; + s1++; + s2++; + } + return (int)*(const unsigned char *)s1 - (int)*(const unsigned char *)s2; +} +#endif + +#ifndef HAVE_STRCASESTR +char * strcasestr (const char *haystack, const char *needle) +{ + const char *p, *startn = NULL, *np = NULL; + for (p = haystack; *p; p++) + { + if (np) + { + if (toupper(*p) == toupper(*np)) + { + if (!*++np) + return startn; + } + else + np = NULL; + } + else if (toupper(*p) == toupper(*needle)) + { + np = needle + 1; + startn = p; + } + } + return NULL; +} +#endif + +#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__) && !defined(__FRAMAC__) +struct tm *localtime_r(const time_t *timep, struct tm *result) +{ + return localtime(timep); +} +#endif + +/*@ + @ assigns \nothing; + @*/ +static unsigned int up2power_aux(const unsigned int number) +{ + if(number==0) + return 0; + else + return(1+up2power_aux(number/2)); +} + +unsigned int up2power(const unsigned int number) +{ + if(number==0) + return 1; + return (1<fsname[i]; + @*/ + for(i=0; ifsname)-1 && ifsname[i]=src[i]; + partition->fsname[i]='\0'; +} + +void set_part_name_chomp(partition_t *partition, const unsigned char *src, const unsigned int max_size) +{ + unsigned int i; + /*@ + @ loop assigns i, partition->fsname[i]; + @*/ + for(i=0; ifsname)-1 && ifsname[i]=src[i]; + /*@ + @ loop assigns i; + @*/ + while(i>0 && src[i-1]==' ') + i--; + partition->fsname[i]='\0'; +} + +char* strip_dup(char* str) +{ + unsigned int i; + char *end; + /*@ + @ loop assigns str; + @*/ + while(isspace(*str)) + str++; + end=str; + /*@ + @ loop assigns i, end; + @*/ + for (i = 0; str[i] != 0; i++) + if (!isspace (str[i])) + end=&str[i]; + if(str == end) + return NULL; + *(end+1) = 0; + return strdup (str); +} + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ +/* + * The epoch of FAT timestamp is 1980. + * : bits : value + * date: 0 - 4: day (1 - 31) + * date: 5 - 8: month (1 - 12) + * date: 9 - 15: year (0 - 127) from 1980 + * time: 0 - 4: sec (0 - 29) 2sec counts + * time: 5 - 10: min (0 - 59) + * time: 11 - 15: hour (0 - 23) + */ +#define SECS_PER_MIN 60 +#define SECS_PER_HOUR (60 * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define YEAR_2100 120 +#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) + +time_t date_dos2unix(const unsigned short f_time, const unsigned short f_date) +{ + static const unsigned int days_in_year[] = { 0, 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + unsigned long int day,leap_day,month,year,days; + unsigned long int secs; + year = f_date >> 9; + /*@ assert 0 <= year <= 127; */ + month = td_max(1, (f_date >> 5) & 0xf); + /*@ assert 1 <= month <= 15; */ + day = td_max(1, f_date & 0x1f) - 1; + /*@ assert 0 <= day <= 30; */ + + if (year > YEAR_2100) /* 2100 isn't leap year */ + { + /*@ assert year > YEAR_2100; */ + leap_day = (year + 3) / 4; + /*@ assert (YEAR_2100 + 3)/4 < leap_day <= 32; */ + leap_day--; + /*@ assert (YEAR_2100 + 3)/4 <= leap_day < 32; */ + } + else + { + /*@ assert year <= YEAR_2100; */ + leap_day = (year + 3) / 4; + /*@ assert 0 <= leap_day <= (YEAR_2100 + 3)/4; */ + } + /*@ assert 0 <= leap_day < 32; */ + if (IS_LEAP_YEAR(year) && month > 2) + leap_day++; + /*@ assert 0 <= leap_day <= 32; */ + days = days_in_year[month]; + /*@ assert days <= 334; */ + days += year * 365 + leap_day + day + DAYS_DELTA; + + secs = (f_time & 0x1f)<<1; + secs += ((f_time >> 5) & 0x3f) * SECS_PER_MIN; + secs += (f_time >> 11)* SECS_PER_HOUR; + secs += days * SECS_PER_DAY; + + return secs+secwest; +} + +void set_secwest(void) +{ + const time_t t = time(NULL); +#if defined(__MINGW32__) || defined(__FRAMAC__) + const struct tm *tmptr = localtime(&t); +#else + struct tm tmp; + const struct tm *tmptr = localtime_r(&t,&tmp); +#endif +#ifdef HAVE_STRUCT_TM_TM_GMTOFF + if(tmptr) + secwest = -1 * tmptr->tm_gmtoff; + else + secwest = 0; +#elif defined (DJGPP) || defined(__ANDROID__) + secwest = 0; +#else +#if defined (__CYGWIN__) + secwest = _timezone; +#else + secwest = timezone; +#endif + /* account for daylight savings */ + if (tmptr && tmptr->tm_isdst) + secwest -= 3600; +#endif +} + +/** + * td_ntfs2utc - Convert an NTFS time to Unix time + * @time: An NTFS time in 100ns units since 1601 + * + * NTFS stores times as the number of 100ns intervals since January 1st 1601 at + * 00:00 UTC. This system will not suffer from Y2K problems until ~57000AD. + * + * Return: n A Unix time (number of seconds since 1970) + */ +#define NTFS_TIME_OFFSET ((int64_t)(369 * 365 + 89) * 24 * 3600 * 10000000) +time_t td_ntfs2utc (int64_t ntfstime) +{ + if(ntfstime < NTFS_TIME_OFFSET) + return 0; + return (ntfstime - NTFS_TIME_OFFSET) / 10000000; +} + +int check_command(char **current_cmd, const char *cmd, const size_t n) +{ + const int res=strncmp(*current_cmd, cmd, n); + if(res==0) + { +#ifdef __FRAMAC__ + const char *src=*current_cmd; + unsigned int i; + /*@ + @ loop invariant valid_read_string(src); + @ loop assigns i, src; + @*/ + for(i=0; i='0' && *current_cmd[0] <= '9') + { + tmp = tmp * 10 + *current_cmd[0] - '0'; + (*current_cmd)++; + } + return tmp; +} diff --git a/subprojects/lib/src/common.h b/subprojects/lib/src/common.h new file mode 100644 index 0000000..10c3e32 --- /dev/null +++ b/subprojects/lib/src/common.h @@ -0,0 +1,667 @@ +/* + + File: common.h + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _COMMON_H +#define _COMMON_H +#ifdef __cplusplus +extern "C" { +#endif +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_NCURSES +#endif +#if defined(__FRAMAC__) && defined(HAVE_STRING_H) +#include +#endif + +typedef struct efi_guid_s efi_guid_t; +struct efi_guid_s +{ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} __attribute__ ((gcc_struct, __packed__)); + +#define DEFAULT_SECTOR_SIZE 0x200u + +#define DISKNAME_MAX 64 +#define DISKDESCRIPTION_MAX 128 +/* PARTITION TYPE */ +#define P_NO_OS 0x00 +#define P_12FAT 0x01 +#define P_16FAT 0x04 +#define P_EXTENDED 0x05 +#define P_16FATBD 0x06 +#define P_NTFS 0x07 +#define P_HPFS 0x07 +#define P_EXFAT 0x07 +#define P_OS2MB 0x0A +#define P_32FAT 0x0B +#define P_32FAT_LBA 0x0C +#define P_16FATBD_LBA 0x0E +#define P_EXTENDX 0x0F +#define P_12FATH 0x11 +#define P_16FATH 0x14 +#define P_16FATBDH 0x16 +#define P_NTFSH 0x17 +#define P_32FATH 0x1B +#define P_32FAT_LBAH 0x1C +#define P_16FATBD_LBAH 0x1E +#define P_SYSV 0x63 +#define P_NETWARE 0x65 +#define P_OLDLINUX 0x81 +#define P_LINSWAP 0x82 +#define P_LINUX 0x83 +#define P_LINUXEXTENDX 0x85 +#define P_LVM 0x8E +#define P_FREEBSD 0xA5 +#define P_OPENBSD 0xA6 +#define P_NETBSD 0xA9 +#define P_HFS 0xAF +#define P_HFSP 0xAF +#define P_SUN 0xBF +#define P_BEOS 0xEB +#define P_VMFS 0xFB +#define P_RAID 0xFD +#define P_UNK 255 +#define NO_ORDER 255 +/* Partition SUN */ +#define PSUN_BOOT 1 +#define PSUN_ROOT 2 +#define PSUN_SWAP 3 +#define PSUN_USR 4 +#define PSUN_WHOLE_DISK 5 +#define PSUN_STAND 6 +#define PSUN_VAR 7 +#define PSUN_HOME 8 +#define PSUN_ALT 9 +#define PSUN_CACHEFS 10 +#define PSUN_LINSWAP P_LINSWAP +#define PSUN_LINUX P_LINUX +#define PSUN_LVM P_LVM +#define PSUN_RAID P_RAID +#define PSUN_UNK 255 + +#define PHUMAX_PARTITION 1 + +#define PMAC_DRIVER43 1 +#define PMAC_DRIVERATA 2 +#define PMAC_DRIVERIO 3 +#define PMAC_FREE 4 +#define PMAC_FWDRIVER 5 +#define PMAC_SWAP 0x82 +#define PMAC_LINUX 0x83 +#define PMAC_BEOS 0xEB +#define PMAC_HFS 0xAF +#define PMAC_MAP 6 +#define PMAC_PATCHES 7 +#define PMAC_UNK 8 +#define PMAC_NewWorld 9 +#define PMAC_DRIVER 10 +#define PMAC_MFS 11 +#define PMAC_PRODOS 12 +#define PMAC_FAT32 13 + +#define PXBOX_UNK 0 +#define PXBOX_FATX 1 + +#define GPT_ENT_TYPE_UNUSED \ + ((const efi_guid_t){le32(0x00000000),le16(0x0000),le16(0x0000),0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}) +#define GPT_ENT_TYPE_EFI \ + ((const efi_guid_t){le32(0xc12a7328),le16(0xf81f),le16(0x11d2),0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}) +/* Extended Boot Partition */ +#define GPT_ENT_TYPE_EBP \ + ((const efi_guid_t){le32(0xbc13c2ff),le16(0x59e6),le16(0x4262),0xa3,0x52,{0xb2,0x75,0xfd,0x6f,0x71,0x72}}) +#define GPT_ENT_TYPE_MBR \ + ((const efi_guid_t){le32(0x024dee41),le16(0x33e7),le16(0x11d3),0x9d,0x69,{0x00,0x08,0xc7,0x81,0xf3,0x9f}}) +#define GPT_ENT_TYPE_FREEBSD \ + ((const efi_guid_t){le32(0x516e7cb4),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_SWAP \ + ((const efi_guid_t){le32(0x516e7cb5),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_UFS \ + ((const efi_guid_t){le32(0x516e7cb6),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +#define GPT_ENT_TYPE_FREEBSD_ZFS \ + ((const efi_guid_t){le32(0x516e7cb),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) +/* + * The following is unused but documented here to avoid reuse. + * + * GPT_ENT_TYPE_FREEBSD_UFS2 \ + * ((const efi_guid_t){le32(0x516e7cb7),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) + */ + +#define GPT_ENT_TYPE_FREEBSD_VINUM \ + ((const efi_guid_t){le32(0x516e7cb8),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}}) + + +#define GPT_ENT_TYPE_MS_BASIC_DATA \ + ((const efi_guid_t){le32(0xebd0a0a2),le16(0xb9e5),le16(0x4433),0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}) +#define GPT_ENT_TYPE_MS_LDM_DATA \ + ((const efi_guid_t){le32(0xaf9b60a0),le16(0x1431),le16(0x4f62),0xbc,0x68,{0x33,0x11,0x71,0x4a,0x69,0xad}}) +#define GPT_ENT_TYPE_MS_LDM_METADATA \ + ((const efi_guid_t){le32(0x5808c8aa),le16(0x7e8f),le16(0x42e0),0x85,0xd2,{0xe1,0xe9,0x04,0x34,0xcf,0xb3}}) +#define GPT_ENT_TYPE_MS_RECOVERY \ + ((const efi_guid_t){le32(0xde94bba4),le16(0x06d1),le16(0x4d40),0xa1,0x6a,{0xbf,0xd5,0x01,0x79,0xd6,0xac}}) +#define GPT_ENT_TYPE_MS_RESERVED \ + ((const efi_guid_t){le32(0xe3c9e316),le16(0x0b5c),le16(0x4db8),0x81,0x7d,{0xf9,0x2d,0xf0,0x02,0x15,0xae}}) +#define GPT_ENT_TYPE_MS_SPACES \ + ((const efi_guid_t){le32(0xe75caf8f),le16(0xf680),le16(0x4cee),0xaf,0xa3,{0xb0,0x01,0xe5,0x6e,0xfc,0x2d}}) + +#define GPT_ENT_TYPE_LINUX_DATA \ + ((const efi_guid_t){le32(0x0fc63daf),le16(0x8483),le16(0x4772),0x8e,0x79,{0x3d,0x69,0xd8,0x47,0x7d,0xe4}}) +#define GPT_ENT_TYPE_LINUX_HOME \ + ((const efi_guid_t){le32(0x933ac7e1),le16(0x2eb4),le16(0x4f13),0xb8,0x44,{0x0e,0x14,0xe2,0xae,0xf9,0x15}}) +#define GPT_ENT_TYPE_LINUX_LVM \ + ((const efi_guid_t){le32(0xe6d6d379),le16(0xf507),le16(0x44c2),0xa2,0x3c,{0x23,0x8f,0x2a,0x3d,0xf9,0x28}}) +#define GPT_ENT_TYPE_LINUX_RAID \ + ((const efi_guid_t){le32(0xa19d880f),le16(0x05fc),le16(0x4d3b),0xa0,0x06,{0x74,0x3f,0x0f,0x84,0x91,0x1e}}) +#define GPT_ENT_TYPE_LINUX_RESERVED \ + ((const efi_guid_t){le32(0x8da63339),le16(0x0007),le16(0x60c0),0xc4,0x36,{0x08,0x3a,0xc8,0x23,0x09,0x08}}) +#define GPT_ENT_TYPE_LINUX_SRV \ + ((const efi_guid_t){le32(0x3b8f8425),le16(0x20e0),le16(0x4f3b),0x90,0x7f,{0x1a,0x25,0xa7,0x6f,0x98,0xe8}}) +#define GPT_ENT_TYPE_LINUX_SWAP \ + ((const efi_guid_t){le32(0x0657fd6d),le16(0xa4ab),le16(0x43c4),0x84,0xe5,{0x09,0x33,0xc8,0x4b,0x4f,0x4f}}) + +#define GPT_ENT_TYPE_HPUX_DATA \ + ((const efi_guid_t){le32(0x75894c1e),le16(0x3aeb),le16(0x11d3),0xb7,0xc1,{0x7b,0x03,0xa0,0x00,0x00,0x00}}) +#define GPT_ENT_TYPE_HPUX_SERVICE \ + ((const efi_guid_t){le32(0xe2a1e728),le16(0x32e3),le16(0x11d6),0xa6,0x82,{0x7b,0x03,0xa0,0x00,0x00,0x00}}) + +#define GPT_ENT_TYPE_APPLE_CORE_STORAGE \ + ((const efi_guid_t){le32(0x53746F72),le16(0x6167),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_APFS \ + ((const efi_guid_t){le32(0x7c3457ef),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_BOOT \ + ((const efi_guid_t){le32(0x426f6f74),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_HFS \ + ((const efi_guid_t){le32(0x48465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_LABEL \ + ((const efi_guid_t){le32(0x4c616265),le16(0x6c00),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_RAID \ + ((const efi_guid_t){le32(0x52414944),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_RAID_OFFLINE \ + ((const efi_guid_t){le32(0x52414944),le16(0x5f4f),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_TV_RECOVERY \ + ((const efi_guid_t){le32(0x5265636f),le16(0x7665),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) +#define GPT_ENT_TYPE_MAC_UFS \ + ((const efi_guid_t){le32(0x55465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}}) + +#define GPT_ENT_TYPE_SOLARIS_BACKUP \ + ((const efi_guid_t){le32(0x6a8b642b),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_BOOT \ + ((const efi_guid_t){le32(0x6a82cb45),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_ROOT \ + ((const efi_guid_t){le32(0x6a85cf4d),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_SWAP \ + ((const efi_guid_t){le32(0x6a87c46f),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_USR \ + ((const efi_guid_t){le32(0x6a898cc3),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_MAC_ZFS GPT_ENT_TYPE_SOLARIS_USR +#define GPT_ENT_TYPE_SOLARIS_VAR \ + ((const efi_guid_t){le32(0x6a8ef2e9),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_HOME \ + ((const efi_guid_t){le32(0x6a90ba39),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_EFI_ALTSCTR \ + ((const efi_guid_t){le32(0x6a9283a5),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED1 \ + ((const efi_guid_t){le32(0x6a945a3b),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED2 \ + ((const efi_guid_t){le32(0x6a9630d1),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED3 \ + ((const efi_guid_t){le32(0x6a980767),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED4 \ + ((const efi_guid_t){le32(0x6a96237f),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) +#define GPT_ENT_TYPE_SOLARIS_RESERVED5 \ + ((const efi_guid_t){le32(0x6a8d2ac7),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}}) + +#define GPT_ENT_TYPE_BEOS_BFS \ + ((const efi_guid_t){le32(0x42465331),le16(0x3ba3),le16(0x10f1),0x80,0x2a,{0x48,0x61,0x69,0x6b,0x75,0x21}}) + +#define TESTDISK_O_RDONLY 00 +#define TESTDISK_O_RDWR 02 +#define TESTDISK_O_DIRECT 040000 +#define TESTDISK_O_READAHEAD_8K 04 +#define TESTDISK_O_READAHEAD_32K 010 +#define TESTDISK_O_ALL 020 + +enum upart_type { + UP_UNK=0, + UP_APFS, + UP_BEOS, + UP_BTRFS, + UP_CRAMFS, + UP_EXFAT, + UP_EXT2, + UP_EXT3, + UP_EXT4, + UP_EXTENDED, + UP_FAT12, + UP_FAT16, + UP_FAT32, + UP_FATX, + UP_FREEBSD, + UP_F2FS, + UP_GFS2, + UP_HFS, + UP_HFSP, + UP_HFSX, + UP_HPFS, + UP_ISO, + UP_JFS, + UP_LINSWAP, + UP_LINSWAP2, + UP_LINSWAP_8K, + UP_LINSWAP2_8K, + UP_LINSWAP2_8KBE, + UP_LUKS, + UP_LVM, + UP_LVM2, + UP_MD, + UP_MD1, + UP_NETWARE, + UP_NTFS, + UP_OPENBSD, + UP_OS2MB, + UP_ReFS, + UP_RFS, + UP_RFS2, + UP_RFS3, + UP_RFS4, + UP_SUN, + UP_SYSV4, + UP_UFS, + UP_UFS2, + UP_UFS_LE, + UP_UFS2_LE, + UP_VMFS, + UP_WBFS, + UP_XFS, + UP_XFS2, + UP_XFS3, + UP_XFS4, + UP_XFS5, + UP_ZFS}; +typedef enum upart_type upart_type_t; +enum status_type { STATUS_DELETED, STATUS_PRIM, STATUS_PRIM_BOOT, STATUS_LOG, STATUS_EXT, STATUS_EXT_IN_EXT}; +typedef enum status_type status_type_t; +enum errcode_type {BAD_NOERR, BAD_SS, BAD_ES, BAD_SH, BAD_EH, BAD_EBS, BAD_RS, BAD_SC, BAD_EC, BAD_SCOUNT}; +typedef enum errcode_type errcode_type_t; + +#define AFF_PART_BASE 0 +#define AFF_PART_ORDER 1 +#define AFF_PART_STATUS 2 + +#define UNIT_DEFAULT 0 +#define UNIT_SECTOR 1 +#define UNIT_CHS 2 + +typedef struct param_disk_struct disk_t; +typedef struct partition_struct partition_t; +/*@ + predicate valid_partition(partition_t *part) = (\valid_read(part)); + @*/ + +typedef struct CHS_struct CHS_t; +typedef struct +{ + unsigned long int cylinders; + unsigned int heads_per_cylinder; + unsigned int sectors_per_head; + unsigned int bytes_per_sector; /* WARN: may be uninitialized */ +} CHSgeometry_t; + +struct CHS_struct +{ + unsigned long int cylinder; + unsigned int head; + unsigned int sector; +}; + +typedef struct list_part_struct list_part_t; +struct list_part_struct +{ + partition_t *part; + list_part_t *prev; + list_part_t *next; + int to_be_removed; +}; +/*@ + predicate valid_list_part(list_part_t *list) = ((list == \null) || (\valid_read(list) && valid_list_part(list->next))); + @*/ + +typedef struct list_disk_struct list_disk_t; +struct list_disk_struct +{ + disk_t *disk; + list_disk_t *prev; + list_disk_t *next; +}; + +/*@ +inductive ld_reachable{L} (list_disk_t* root, list_disk_t* node) +{ + case root_ld_reachable{L}: + \forall list_disk_t *root; ld_reachable(root,root); + case next_ld_reachable{L}: + \forall list_disk_t *root, *node; \valid(root) ==> ld_reachable(root->next, node) ==> ld_reachable(root,node); +} +*/ + +/*@ predicate ld_finite{L}(list_disk_t* root) = ld_reachable(root,\null); */ + +struct systypes { + const unsigned int part_type; + const char *name; +}; + +struct arch_fnct_struct +{ + const char *part_name; + const char *part_name_option; + const char *msg_part_type; + list_part_t *(*read_part)(disk_t *disk, const int verbose,const int saveheader); + int (*write_part)(disk_t *disk, const list_part_t *list_part, const int ro, const int verbose); + list_part_t *(*init_part_order)(const disk_t *disk, list_part_t *list_part); + /* geometry must be initialized to 0,0,0 in get_geometry_from_mbr()*/ + int (*get_geometry_from_mbr)(const unsigned char *buffer, const int verbose, CHSgeometry_t *geometry); + int (*check_part)(disk_t *disk,const int verbose,partition_t *partition, const int saveheader); + int (*write_MBR_code)(disk_t *disk); + void (*set_prev_status)(const disk_t *disk, partition_t *partition); + void (*set_next_status)(const disk_t *disk, partition_t *partition); + int (*test_structure)(const list_part_t *list_part); + unsigned int (*get_part_type)(const partition_t *partition); + int (*set_part_type)(partition_t *partition, unsigned int part_type); + void (*init_structure)(const disk_t *disk,list_part_t *list_part, const int verbose); + int (*erase_list_part)(disk_t *disk); + const char *(*get_partition_typename)(const partition_t *partition); + int (*is_part_known)(const partition_t *partition); +}; + +typedef struct arch_fnct_struct arch_fnct_t; + +/*@ + predicate valid_arch(arch_fnct_t *arch) = ( + \valid_read(arch) && + (arch->get_geometry_from_mbr==\null || \valid_function(arch->get_geometry_from_mbr)) + ); + @*/ + +struct param_disk_struct +{ + char description_txt[DISKDESCRIPTION_MAX]; + char description_short_txt[DISKDESCRIPTION_MAX]; + CHSgeometry_t geom; /* logical CHS */ + uint64_t disk_size; + char *device; + char *model; + char *serial_no; + char *fw_rev; + const char *(*description)(disk_t *disk); + const char *(*description_short)(disk_t *disk); + int (*pread)(disk_t *disk, void *buf, const unsigned int count, const uint64_t offset); + int (*pwrite)(disk_t *disk, const void *buf, const unsigned int count, const uint64_t offset); + int (*sync)(disk_t *disk); + void (*clean)(disk_t *disk); + const arch_fnct_t *arch; + const arch_fnct_t *arch_autodetected; + void *data; + uint64_t disk_real_size; + uint64_t user_max; + uint64_t native_max; + uint64_t dco; + uint64_t offset; /* offset to first sector, may be modified in the futur to handle broken raid */ + void *rbuffer; + void *wbuffer; + unsigned int rbuffer_size; + unsigned int wbuffer_size; + int write_used; + int autodetect; + int access_mode; + int unit; + unsigned int sector_size; +}; + +/*@ + predicate valid_disk(disk_t *disk) = ((disk == \null) || + (\valid_read(disk) && + \freeable(disk) && + valid_read_string(disk->device) && + \freeable(disk->device) && + \valid_function(disk->clean) && + \valid_function(disk->description) && + (disk->model == \null || \freeable(disk->model)) && + (disk->model == \null || valid_read_string(disk->model)) && + (disk->serial_no == \null || \freeable(disk->serial_no)) && + (disk->fw_rev == \null || \freeable(disk->fw_rev)) && + (disk->data == \null || \freeable(disk->data)) && + (disk->rbuffer == \null || (\freeable(disk->rbuffer) && disk->rbuffer_size > 0)) && + (disk->wbuffer == \null || (\freeable(disk->wbuffer) && disk->wbuffer_size > 0)) && + valid_arch(disk->arch) && + disk->sector_size > 0 + )); +*/ +/*@ predicate valid_list_disk(list_disk_t* root) = ((root == \null) || (\valid_read(root))); */ + +/* TODO predicate valid_list_disk{L}(list_disk_t* root) = + \forall list_disk_t *node; \valid(node) && ld_reachable(root,node) ==> \valid(node->disk); + */ + + +struct partition_struct +{ + char fsname[128]; + char partname[128]; + char info[128]; + uint64_t part_offset; + uint64_t part_size; + uint64_t sborg_offset; + uint64_t sb_offset; + unsigned int sb_size; + unsigned int blocksize; + efi_guid_t part_uuid; + efi_guid_t part_type_gpt; + unsigned int part_type_humax; + unsigned int part_type_i386; + unsigned int part_type_mac; + unsigned int part_type_sun; + unsigned int part_type_xbox; + upart_type_t upart_type; + status_type_t status; + unsigned int order; + errcode_type_t errcode; + const arch_fnct_t *arch; + /* NTFS => utils_cluster_in_use */ + /* ext2/ext3/ext4 */ +#if 0 + int (*is_allocated)(disk_t *disk, const partition_t *partition, const uint64_t offset); + void *free_is_allocated(void); +#endif +}; + +typedef struct my_data_struct my_data_t; +struct my_data_struct +{ + disk_t *disk_car; + const partition_t *partition; + uint64_t offset; +}; + +/*@ + @ requires size > 0; + @ ensures \valid(((char *)\result)+(0..size-1)); + @ ensures zero_initialization: \subset(((char *)\result)[0..size-1], {0}); + @ assigns __fc_heap_status; + @*/ +void *MALLOC(size_t size); + +/*@ + @ assigns \nothing; + @*/ +unsigned int up2power(const unsigned int number); + +/*@ + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(src + (0 .. max_size-1)); + @*/ +void set_part_name(partition_t *partition, const char *src, const unsigned int max_size); + +/*@ + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(src + (0 .. max_size-1)); + @*/ +void set_part_name_chomp(partition_t *partition, const unsigned char *src, const unsigned int max_size); + +/*@ + @ requires valid_read_string(str); + @ ensures \result == \null || valid_read_string(\result); + @*/ +char* strip_dup(char* str); + +/*@ assigns \nothing; */ +time_t date_dos2unix(const unsigned short f_time,const unsigned short f_date); + +void set_secwest(void); + +/*@ assigns \nothing; */ +time_t td_ntfs2utc (int64_t ntfstime); +#ifndef BSD_MAXPARTITIONS +#define BSD_MAXPARTITIONS 8 +#endif +#ifndef OPENBSD_MAXPARTITIONS +#define OPENBSD_MAXPARTITIONS 16 +#endif + +#define __swab16(x) (((((uint16_t)x)&(uint16_t)0xff00)>>8) | \ + (((uint16_t)(x)&(uint16_t)0x00ff)<<8)) + +#define __swab24(x) ((((x) & 0x000000ffUL) << 16) | \ + ((x) & 0x0000ff00UL) | \ + (((x) & 0x00ff0000UL) >> 16)) + +#define __swab32(x) ((((uint32_t)(x)&(uint32_t)0xff000000UL)>>24) | \ + (((uint32_t)(x)&(uint32_t)0x00ff0000UL)>>8) | \ + (((uint32_t)(x)&(uint32_t)0x0000ff00UL)<<8) | \ + (((uint32_t)(x)&(uint32_t)0x000000ffUL)<<24)) + +#define __swab64(x) ((((uint64_t)(x)&(uint64_t)0xff00000000000000ULL)>>56) | \ + (((uint64_t)(x)&(uint64_t)0x00ff000000000000ULL)>>40) | \ + (((uint64_t)(x)&(uint64_t)0x0000ff0000000000ULL)>>24) | \ + (((uint64_t)(x)&(uint64_t)0x000000ff00000000ULL)>>8) | \ + (((uint64_t)(x)&(uint64_t)0x00000000ff000000ULL)<<8) | \ + (((uint64_t)(x)&(uint64_t)0x0000000000ff0000ULL)<<24) | \ + (((uint64_t)(x)&(uint64_t)0x000000000000ff00ULL)<<40) | \ + (((uint64_t)(x)&(uint64_t)0x00000000000000ffULL)<<56)) + +#ifdef TESTDISK_LSB +#define be16(x) (__swab16(x)) +#define be24(x) (__swab24(x)) +#define be32(x) (__swab32(x)) +#define be64(x) (__swab64(x)) +#define le16(x) (x) /* x as little endian */ +#define le24(x) (x) +#define le32(x) (x) +#define le64(x) (x) +#else /* bigendian */ +#define be16(x) (x) +#define be24(x) (x) +#define be32(x) (x) +#define be64(x) (x) +#define le16(x) (__swab16(x)) +#define le24(x) (__swab24(x)) +#define le32(x) (__swab32(x)) +#define le64(x) (__swab64(x)) +#endif +#ifndef HAVE_SNPRINTF +int snprintf(char *str, size_t size, const char *format, ...); +#endif +#ifndef HAVE_VSNPRINTF +#include +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif +#ifndef HAVE_STRNCASECMP +int strncasecmp(const char * s1, const char * s2, size_t len); +#endif +#ifndef HAVE_STRCASESTR +char * strcasestr (const char *haystack, const char *needle); +#endif +#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__) && !defined(__FRAMAC__) +/*@ + @ requires valid_timer: \valid_read(timep); + @ requires \valid(result); + @*/ +struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif +/* + * td_min()/td_max() macros that also do + * strict type-checking.. See the + * "unnecessary" pointer comparison. + * Comes from Linux kernel + */ +#define td_min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define td_max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires valid_read_string(cmd); + @ requires \separated(cmd+(..), current_cmd, *current_cmd); + @ requires strlen(cmd) == n; + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @ ensures \result != 0 ==> *current_cmd == \old(*current_cmd); + @*/ +// ensures \result == 0 ==> *current_cmd == \old(*current_cmd) + n; +// assigns \result \from indirect:(*current_cmd)[0 .. n-1], indirect:cmd[0 ..n-1], indirect:n; +int check_command(char **current_cmd, const char *cmd, const size_t n); + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires \separated(current_cmd, *current_cmd); + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @*/ +void skip_comma_in_command(char **current_cmd); + +/*@ + @ requires \valid(current_cmd); + @ requires valid_read_string(*current_cmd); + @ requires \separated(current_cmd, *current_cmd); + @ assigns *current_cmd; + @ ensures valid_read_string(*current_cmd); + @*/ +uint64_t get_int_from_command(char **current_cmd); +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/cramfs.c b/subprojects/lib/src/cramfs.c new file mode 100644 index 0000000..e5afeb0 --- /dev/null +++ b/subprojects/lib/src/cramfs.c @@ -0,0 +1,105 @@ +/* + + File: cramfs.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "cramfs.h" +#include "fnctdsk.h" +#include "log.h" + +static void set_cramfs_info(const struct cramfs_super *sb, partition_t *partition); +static int test_cramfs(const disk_t *disk_car, const struct cramfs_super *sb, const partition_t *partition, const int verbose); + +int check_cramfs(disk_t *disk_car,partition_t *partition,const int verbose) +{ + unsigned char *buffer=(unsigned char*)MALLOC(CRAMFS_SUPERBLOCK_SIZE); + if(disk_car->pread(disk_car, buffer, CRAMFS_SUPERBLOCK_SIZE, partition->part_offset + 0x200) == CRAMFS_SUPERBLOCK_SIZE) + { + if(test_cramfs(disk_car, (struct cramfs_super*)buffer, partition, verbose)==0) + { + set_cramfs_info((struct cramfs_super*)buffer, partition); + free(buffer); + return 0; + } + } + if(disk_car->pread(disk_car, buffer, CRAMFS_SUPERBLOCK_SIZE, partition->part_offset) == CRAMFS_SUPERBLOCK_SIZE) + { + if(test_cramfs(disk_car, (struct cramfs_super*)buffer, partition, verbose)==0) + { + set_cramfs_info((struct cramfs_super*)buffer, partition); + free(buffer); + return 0; + } + } + free(buffer); + return 1; +} + +static int test_cramfs(const disk_t *disk_car, const struct cramfs_super *sb, const partition_t *partition, const int verbose) +{ + if (sb->magic!=le32(CRAMFS_MAGIC)) + return 1; + if(partition==NULL) + return 0; + if(verbose>0) + log_info("\ncramfs Marker at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset)); + return 0; +} + +int recover_cramfs(const disk_t *disk_car, const struct cramfs_super *sb, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_cramfs(disk_car, sb, partition, verbose)!=0) + return 1; + if(verbose>0 || dump_ind!=0) + { + log_trace("\nrecover_cramfs\n"); + if(dump_ind!=0) + { + dump_log(sb,DEFAULT_SECTOR_SIZE); + } + } + partition->part_size = sb->size; + partition->part_type_i386 = P_LINUX; + partition->part_type_mac= PMAC_LINUX; + partition->part_type_sun= PSUN_LINUX; + partition->part_type_gpt= GPT_ENT_TYPE_LINUX_DATA; + set_cramfs_info(sb, partition); + return 0; +} + +static void set_cramfs_info(const struct cramfs_super *sb, partition_t *partition) +{ + partition->upart_type = UP_CRAMFS; + set_part_name(partition, (const char*)sb->name, 16); + strncpy(partition->info,"cramfs",sizeof(partition->info)); +} diff --git a/subprojects/lib/src/cramfs.h b/subprojects/lib/src/cramfs.h new file mode 100644 index 0000000..eef22aa --- /dev/null +++ b/subprojects/lib/src/cramfs.h @@ -0,0 +1,107 @@ +/* + + File: cramfs.h + + Copyright (C) 2004-2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _CRAMFS_H +#define _CRAMFS_H +#ifdef __cplusplus +extern "C" { +#endif +/* real size is 76 */ +#define CRAMFS_SUPERBLOCK_SIZE 512 +#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ +#define CRAMFS_SIGNATURE "Compressed ROMFS" + +struct cramfs_info { + uint32_t crc; + uint32_t edition; + uint32_t blocks; + uint32_t files; +}; + +/* + * Width of various bitfields in struct cramfs_inode. + * Primarily used to generate warnings in mkcramfs. + */ +#define CRAMFS_MODE_WIDTH 16 +#define CRAMFS_UID_WIDTH 16 +#define CRAMFS_SIZE_WIDTH 24 +#define CRAMFS_GID_WIDTH 8 +#define CRAMFS_NAMELEN_WIDTH 6 +#define CRAMFS_OFFSET_WIDTH 26 + +/* + * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs + * path length is 63 << 2 = 252. + */ +#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2) + +/* + * Reasonably terse representation of the inode data. + */ +struct cramfs_inode { + uint32_t mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; + /* SIZE for device files is i_rdev */ + uint32_t size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; + /* NAMELEN is the length of the file name, divided by 4 and + rounded up. (cramfs doesn't support hard links.) */ + /* OFFSET: For symlinks and non-empty regular files, this + contains the offset (divided by 4) of the file data in + compressed form (starting with an array of block pointers; + see README). For non-empty directories it is the offset + (divided by 4) of the inode of the first file in that + directory. For anything else, offset is zero. */ + uint32_t namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; +}; + + +struct cramfs_super { + uint32_t magic; /* 0x28cd3d45 - random number */ + uint32_t size; /* length in bytes */ + uint32_t flags; /* feature flags */ + uint32_t future; /* reserved for future use */ + uint8_t signature[16]; /* "Compressed ROMFS" */ + struct cramfs_info fsid; /* unique filesystem info */ + uint8_t name[16]; /* user-defined name */ + struct cramfs_inode root; /* root inode data */ +}; + + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_cramfs(disk_t *disk_car,partition_t *partition,const int verbose); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition, sb); + @ requires \valid_read(sb); + @*/ +int recover_cramfs(const disk_t *disk_car, const struct cramfs_super *sb, partition_t *partition, const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/crc.c b/subprojects/lib/src/crc.c new file mode 100644 index 0000000..10dd8bd --- /dev/null +++ b/subprojects/lib/src/crc.c @@ -0,0 +1,129 @@ +/* + + File: crc.c + + Copyright (C) 2007 Christophe GRENIER + Copyright (C) 1986 Gary S. Brown for the crc32 table. + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "types.h" +#include "common.h" +#include "crc.h" + +/* crc32_tab=make_crc32_table(0xEDB88320); */ +static const uint32_t crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +unsigned int get_crc32(const void*buf, const unsigned int len, const uint32_t seed) +{ + unsigned int i; + register uint32_t crc32val; + const unsigned char *s=(const unsigned char *)buf; + crc32val = seed; + /*@ loop assigns i, crc32val; */ + for (i = 0; i < len; i ++) + { + crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); + } + return (unsigned int)crc32val; +} + +#if 0 +uint32_t* make_crc32_table(uint32_t poly) +{ + unsigned i,j; + uint32_t *crctable = (uint32_t *)MALLOC(256*sizeof(uint32_t)); + for (i=0;i<256;i++) + { + uint32_t r=i; + for (j=8;j>0;j--) + r=((r&1)?(r>>1)^poly:(r>>1)); + crctable[i] = r; + } + return crctable; +} + +unsigned int get_crc32_gen(const void *buf, const unsigned int len, const uint32_t seed, const uint32_t *crctab) +{ + unsigned int i; + register uint32_t crc32val; + const unsigned char *s=buf; + crc32val = seed; + for (i = 0; i < len; i ++) + { + crc32val = crctab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); + } + return crc32val; +} +#endif diff --git a/subprojects/lib/src/crc.h b/subprojects/lib/src/crc.h new file mode 100644 index 0000000..50d651d --- /dev/null +++ b/subprojects/lib/src/crc.h @@ -0,0 +1,43 @@ +/* + + File: crc.h + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _CRC_H +#define _CRC_H +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +uint32_t* make_crc32_table(uint32_t poly); +unsigned int get_crc32_gen(const unsigned char *s, const unsigned int len, const uint32_t seed, const uint32_t *crctab); +#endif +/*@ + @ requires \valid_read((const char *)s + (0 .. len-1)); + @ requires \initialized((const char *)s + (0 .. len-1)); + @ assigns \nothing; + @*/ +unsigned int get_crc32(const void *s, const unsigned int len, const uint32_t seed); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/dfxml.c b/subprojects/lib/src/dfxml.c new file mode 100644 index 0000000..88fbef6 --- /dev/null +++ b/subprojects/lib/src/dfxml.c @@ -0,0 +1,352 @@ +/* + + File: xml.c + + Copyright (C) 2011 Simson Garfinkel + Copyright (C) 2011 Christophe Grenier + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) +#undef HAVE_LIBEWF +#undef HAVE_SYS_UTSNAME_H +#undef ENABLE_DFXML +#endif + +#ifdef ENABLE_DFXML +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include /* unlink, ftruncate */ +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include "types.h" +#include "common.h" +#include "dir.h" +#include "filegen.h" +#include "photorec.h" +#include "ext2_dir.h" +#include "ewf.h" +#include "file_jpg.h" +#include "file_gz.h" +#include "ntfs_dir.h" +#include "misc.h" +#include "dfxml.h" + +static FILE *xml_handle = NULL; +static int xml_stack_depth = 0; +static char *command_line = NULL; + +static const char *xml_header = "\n"; +static char xml_dir[2048]; +static char xml_fname[2048]; /* what photorec uses elsewhere */ + + +FILE *xml_open(const char *recup_dir, const unsigned int dir_num) +{ + snprintf(xml_dir, sizeof(xml_dir), "%s.%u/", recup_dir,dir_num); + snprintf(xml_fname, sizeof(xml_fname), "%s.%u/report.xml", recup_dir, dir_num); + xml_handle = fopen(xml_fname,"w"); + return xml_handle; +} + +void xml_set_command_line(const int argc, char **argv) +{ + int i; + int len=argc; + if(command_line!=NULL) + return ; + /* Capture the command line */ + for(i=0; i0) + strcat(command_line," "); + strcat(command_line, argv[i]); + } +} + +void xml_clear_command_line(void) +{ + free(command_line); + command_line=NULL; +} + +void xml_close() +{ + if(xml_handle==NULL) + return; + fclose(xml_handle); + xml_handle = NULL; +} + +static void xml_spaces(void) +{ + int i; + if(xml_handle==NULL) + return; + for(i = 0; i < xml_stack_depth * 2; i++) + { + fputc(' ', xml_handle); + } +} + +static void xml_tagout(const char *tag,const char *attribute) +{ + if(attribute[0]=='\0') + xml_printf("<%s>", tag); + else + xml_printf("<%s %s>", tag, attribute); +} + +/** + * output the closing tag */ +static void xml_ctagout(const char *tag) +{ + xml_printf("", tag); +} + +void xml_push(const char *tag,const char *attribute) +{ + if(xml_handle==NULL) + return; + xml_tagout(tag, attribute); + fputc('\n', xml_handle); + xml_stack_depth++; +} + +void xml_pop(const char *tag) +{ + if(xml_handle==NULL) + return; + xml_stack_depth--; + xml_ctagout(tag); + fputc('\n', xml_handle); +} + +void xml_printf(const char *fmt,...) +{ + va_list ap; + if(xml_handle==NULL) + return; + va_start(ap, fmt); + xml_spaces(); + vfprintf(xml_handle, fmt, ap); + va_end(ap); +} + +void xml_out2s(const char *tag, const char *value) +{ + if(xml_handle==NULL) + return; + xml_spaces(); + fprintf(xml_handle, "<%s>", tag); + for(;*value!='\0'; value++) + { + if(*value=='&') + fputs("&", xml_handle); + else + putc(*value, xml_handle); + } + fprintf(xml_handle, "\n", tag); +} + +void xml_out2i(const char *tag, const uint64_t value) +{ + xml_printf("<%s>%llu\n", tag, (long long unsigned)value, tag); +} + +void xml_add_DFXML_creator(const char *package, const char *version) +{ + xml_push("creator",""); + xml_out2s("package", package); + xml_out2s("version", version); + xml_push("build_environment",""); + xml_printf("%s\n", get_compiler()); +#ifdef RECORD_COMPILATION_DATE + xml_out2s("compilation_date", get_compilation_date()); +#endif +#ifndef MAIN_photorec + xml_printf("\n", td_ext2fs_version()); + xml_printf("\n", td_ewf_version()); + xml_printf("\n", td_jpeg_version()); + xml_printf("\n", td_ntfs_version()); + xml_printf("\n", td_zlib_version()); +#endif + xml_pop("build_environment"); + xml_push("execution_environment",""); +#if defined(__CYGWIN__) || defined(__MINGW32__) + xml_out2s("os_sysname", "Windows"); + xml_out2s("os_release", get_os()); + xml_out2s("os_version", get_os()); +#ifdef HAVE_SYS_UTSNAME_H + { + struct utsname name; + if(uname(&name)==0) + { + xml_out2s("host", name.nodename); + xml_out2s("arch", name.machine); + } + } +#endif +#elif defined(HAVE_SYS_UTSNAME_H) + { + struct utsname name; + if(uname(&name)==0) + { + xml_out2s("os_sysname", name.sysname); + xml_out2s("os_release", name.release); + xml_out2s("os_version", name.version); + xml_out2s("host", name.nodename); + xml_out2s("arch", name.machine); + } + } +#elif defined(UNAMES) + xml_out2s("os_sysname", UNAMES); +#endif +#ifdef HAVE_GETEUID + xml_out2i("uid", geteuid()); +#endif +#if !defined(__FRAMAC__) + { + char outstr[200]; + const time_t t = time(NULL); +#if defined(__MINGW32__) || defined(__FRAMAC__) + const struct tm *tmp = localtime(&t); +#else + struct tm tm_tmp; + const struct tm *tmp = localtime_r(&t,&tm_tmp); +#endif + if (tmp != NULL && + strftime(outstr, sizeof(outstr), "%Y-%m-%dT%H:%M:%S%z", tmp) != 0) + { + xml_out2s("start_time", outstr); + } + } +#endif + xml_pop("execution_environment"); + xml_pop("creator"); +} + +void xml_setup(const disk_t *disk, const partition_t *partition) +{ + if(xml_handle==NULL) + return; + fputs(xml_header, xml_handle); + xml_push("dfxml", "xmloutputversion='1.0'"); + xml_push("metadata", + "\n xmlns='http://www.forensicswiki.org/wiki/Category:Digital_Forensics_XML' " + "\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " + "\n xmlns:dc='http://purl.org/dc/elements/1.1/'" ); + xml_out2s("dc:type","Carve Report"); + xml_pop("metadata"); + xml_add_DFXML_creator("PhotoRec", VERSION); + xml_push("source", ""); + xml_out2s("image_filename", disk->device); + xml_out2i("sectorsize", disk->sector_size); + if(disk->model != NULL) + xml_out2s("device_model", disk->model); + xml_out2i("image_size", disk->disk_real_size); + xml_push("volume", ""); + xml_push("byte_runs", ""); + xml_printf( "\n", + (long long unsigned)partition->part_offset, + (long long unsigned)partition->part_size); + xml_pop("byte_runs"); + if(partition->blocksize > 0) + xml_out2i("block_size", partition->blocksize); + xml_pop("volume"); + xml_pop("source"); + xml_push("configuration", ""); + xml_pop("configuration"); // configuration +} + +void xml_shutdown(void) +{ + if(xml_handle==NULL) + return; + xml_pop("dfxml"); + xml_close(); +} + +/* If fname begins with xml_dir then just return the relative part */ +static const char *relative_name(const char *fname) +{ + if(fname==NULL) + return ""; + if(strncmp(fname, xml_dir, strlen(xml_dir))==0) + return fname+strlen(xml_dir); + return fname; +} + +/* See filegen.h for the definition of file_recovery_struct */ +void xml_log_file_recovered(const file_recovery_t *file_recovery) +{ + const struct td_list_head *tmp; + uint64_t file_size=0; + if(xml_handle==NULL) + return; + if(file_recovery==NULL || file_recovery->filename[0]=='\0') + return; + xml_push("fileobject", ""); + xml_out2s("filename", relative_name(file_recovery->filename)); + xml_out2i("filesize", file_recovery->file_size); + xml_push("byte_runs", ""); + td_list_for_each(tmp, &file_recovery->location.list) + { + const alloc_list_t *element=td_list_entry_const(tmp, const alloc_list_t, list); + if(element->data>0) + { + const uint64_t len=element->end - element->start + 1; + xml_printf( "\n", + (long long unsigned)file_size, + (long long unsigned)element->start, + (long long unsigned)len); + file_size+=len; + } + } + xml_pop("byte_runs"); + xml_pop("fileobject"); + fflush(xml_handle); +} +#endif diff --git a/subprojects/lib/src/dfxml.h b/subprojects/lib/src/dfxml.h new file mode 100644 index 0000000..3f97526 --- /dev/null +++ b/subprojects/lib/src/dfxml.h @@ -0,0 +1,60 @@ +/* + + File: dfxml.h + + Copyright (C) 2011 Simson Garfinkel + Copyright (C) 2011 Christophe Grenier + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _DFXML_H +#define _DFXML_H + +#include +#ifdef __cplusplus +extern "C" { +#endif +#if defined(__FRAMAC__) +#undef ENABLE_DFXML +#endif + +#ifdef ENABLE_DFXML +FILE *xml_open(const char *default_filename, const unsigned int dir_num); +void xml_close(void); +void xml_push(const char *tag, const char *attribute); +void xml_pop(const char *tag); +void xml_out2s(const char *tag, const char *value); +void xml_out2i(const char *tag, const uint64_t value); +/*@ + @ requires \valid_read(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires \separated(disk, partition); + @*/ +void xml_setup(const disk_t *disk, const partition_t *partition); +void xml_set_command_line(const int argc, char **argv); +void xml_clear_command_line(void); +void xml_add_DFXML_creator(const char *package, const char *version); +void xml_shutdown(void); +void xml_log_file_recovered(const file_recovery_t *file_recovery); +void xml_log_file_recovered2(const alloc_data_t *space, const file_recovery_t *file_recovery); +void xml_printf(const char *__restrict __format,...) __attribute__((format(printf,1,2))); +#endif +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/dir.c b/subprojects/lib/src/dir.c new file mode 100644 index 0000000..587dd9d --- /dev/null +++ b/subprojects/lib/src/dir.c @@ -0,0 +1,859 @@ +/* + + File: dir.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __FRAMAC__ +#undef HAVE_CHMOD +#endif + +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include "types.h" +#include +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include "common.h" +#include "dir.h" +#include "log.h" +#include "log_part.h" +#define MAX_DIR_NBR 256 + +const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +/*@ + @ assigns \result; + @*/ +static char ftypelet (unsigned int bits) +{ +#ifdef LINUX_S_ISBLK + if (LINUX_S_ISBLK (bits)) + return 'b'; +#endif + if (LINUX_S_ISCHR (bits)) + return 'c'; + if (LINUX_S_ISDIR (bits)) + return 'd'; + if (LINUX_S_ISREG (bits)) + return '-'; +#ifdef LINUX_S_ISFIFO + if (LINUX_S_ISFIFO (bits)) + return 'p'; +#endif +#ifdef LINUX_S_ISLNK + if (LINUX_S_ISLNK (bits)) + return 'l'; +#endif +#ifdef LINUX_S_ISSOCK + if (LINUX_S_ISSOCK (bits)) + return 's'; +#endif +#ifdef LINUX_S_ISMPC + if (LINUX_S_ISMPC (bits)) + return 'm'; +#endif +#ifdef LINUX_S_ISNWK + if (LINUX_S_ISNWK (bits)) + return 'n'; +#endif +#ifdef LINUX_S_ISDOOR + if (LINUX_S_ISDOOR (bits)) + return 'D'; +#endif +#ifdef LINUX_S_ISCTG + if (LINUX_S_ISCTG (bits)) + return 'C'; +#endif +#ifdef LINUX_S_ISOFD + if (LINUX_S_ISOFD (bits)) + /* off line, with data */ + return 'M'; +#endif +#ifdef LINUX_S_ISOFL + /* off line, with no data */ + if (LINUX_S_ISOFL (bits)) + return 'M'; +#endif + return '?'; +} + +void mode_string (const unsigned int mode, char *str) +{ +#ifndef __FRAMAC__ + str[0] = ftypelet(mode); + str[1] = (mode & LINUX_S_IRUSR) ? 'r' : '-'; + str[2] = (mode & LINUX_S_IWUSR) ? 'w' : '-'; + str[3] = (mode & LINUX_S_IXUSR) ? 'x' : '-'; + str[4] = (mode & LINUX_S_IRGRP) ? 'r' : '-'; + str[5] = (mode & LINUX_S_IWGRP) ? 'w' : '-'; + str[6] = (mode & LINUX_S_IXGRP) ? 'x' : '-'; + str[7] = (mode & LINUX_S_IROTH) ? 'r' : '-'; + str[8] = (mode & LINUX_S_IWOTH) ? 'w' : '-'; + str[9] = (mode & LINUX_S_IXOTH) ? 'x' : '-'; + str[10]='\0'; +#ifdef LINUX_S_ISUID + if (mode & LINUX_S_ISUID) + { + if (str[3] != 'x') + /* Set-uid, but not executable by owner. */ + str[3] = 'S'; + else + str[3] = 's'; + } +#endif +#ifdef LINUX_S_ISGID + if (mode & LINUX_S_ISGID) + { + if (str[6] != 'x') + /* Set-gid, but not executable by group. */ + str[6] = 'S'; + else + str[6] = 's'; + } +#endif +#ifdef LINUX_S_ISVTX + if (mode & LINUX_S_ISVTX) + { + if (str[9] != 'x') + /* Sticky, but not executable by others. */ + str[9] = 'T'; + else + str[9] = 't'; + } +#endif +#endif +} + +int set_datestr(char *datestr, size_t n, const time_t timev) +{ + const struct tm *tm_p; +#if ! defined(__MINGW32__) + struct tm tmp; +#endif + if(timev==0) + { + strncpy(datestr, " ", n); + return 0; + } +#if defined(__MINGW32__) || defined(__FRAMAC__) + tm_p=localtime(&timev); +#else + tm_p=localtime_r(&timev, &tmp); +#endif + if(tm_p==NULL) + { + strncpy(datestr, " ", n); + return 0; + } + snprintf(datestr, n,"%2d-%s-%4d %02d:%02d", + tm_p->tm_mday, monstr[tm_p->tm_mon], + 1900 + tm_p->tm_year, tm_p->tm_hour, + tm_p->tm_min); + if(1900+tm_p->tm_year>=2000) + return 1; + return 0; +} + +int dir_aff_log(const dir_data_t *dir_data, const file_info_t *dir_list) +{ + int test_date=0; + struct td_list_head *file_walker = NULL; + if(dir_data!=NULL) + { + log_info("Directory %s\n",dir_data->current_directory); + } +#ifndef __FRAMAC__ + td_list_for_each(file_walker, &dir_list->list) + { + const file_info_t *current_file=td_list_entry_const(file_walker, const file_info_t, list); + char datestr[80]; + char str[11]; + test_date=set_datestr((char *)&datestr, sizeof(datestr), current_file->td_mtime); + mode_string(current_file->st_mode, str); + if((current_file->status&FILE_STATUS_DELETED)!=0) + log_info("X"); + else + log_info(" "); + log_info("%7lu %s %5u %5u %9llu %s ", + (unsigned long int)current_file->st_ino, + str, + (unsigned int)current_file->st_uid, + (unsigned int)current_file->st_gid, + (long long unsigned int)current_file->st_size, + datestr); + if(dir_data!=NULL && (dir_data->param&FLAG_LIST_PATHNAME)!=0) + { + if(dir_data->current_directory[1]!='\0') + log_info("%s/", dir_data->current_directory); + else + log_info("/"); + } + log_info("%s\n", current_file->name); + } +#endif + return test_date; +} + +void log_list_file(const disk_t *disk, const partition_t *partition, const dir_data_t *dir_data, const file_info_t*list) +{ +#ifndef __FRAMAC__ + struct td_list_head *tmp; + log_partition(disk, partition); + if(dir_data!=NULL) + { + log_info("Directory %s\n",dir_data->current_directory); + } + td_list_for_each(tmp, &list->list) + { + char datestr[80]; + char str[11]; + const file_info_t *current_file=td_list_entry_const(tmp, const file_info_t, list); + if((current_file->status&FILE_STATUS_DELETED)!=0) + log_info("X"); + else + log_info(" "); + set_datestr((char *)&datestr, sizeof(datestr), current_file->td_mtime); + mode_string(current_file->st_mode, str); + log_info("%7lu ",(unsigned long int)current_file->st_ino); + log_info("%s %5u %5u ", + str, (unsigned int)current_file->st_uid, (unsigned int)current_file->st_gid); + log_info("%9llu", (long long unsigned int)current_file->st_size); + log_info(" %s %s\n", datestr, current_file->name); + } +#endif +} + +unsigned int delete_list_file(file_info_t *file_info) +{ + unsigned int nbr=0; + struct td_list_head *file_walker = NULL; + struct td_list_head *file_walker_next = NULL; + td_list_for_each_safe(file_walker,file_walker_next, &file_info->list) + { + file_info_t *tmp; + tmp=td_list_entry(file_walker, file_info_t, list); + free(tmp->name); + td_list_del(file_walker); + free(tmp); + nbr++; + } + return nbr; +} + +/*@ + @ requires \valid_read(current_file); + @ requires \valid_read(inode_known + (0 .. dir_nbr-1)); + @ assigns \nothing; + @*/ +static int is_inode_valid(const file_info_t *current_file, const unsigned int dir_nbr, const unsigned long int *inode_known) +{ + const unsigned long int new_inode=current_file->st_ino; + unsigned int i; + if(new_inode<2) + return 0; + if(strcmp(current_file->name, "..")==0) + return 0; + /*@ loop assigns i; */ + for(i=0; icurrent_directory); + file_info_t dir_list; + TD_INIT_LIST_HEAD(&dir_list.list); + if(dir_nbr==MAX_DIR_NBR) + return 1; /* subdirectories depth is too high => Back */ + if(dir_data->verbose>0) + log_info("\ndir_partition inode=%lu\n",inode); + dir_data->get_dir(disk, partition, dir_data, inode, &dir_list); + dir_aff_log(dir_data, &dir_list); + /* Not perfect for FAT32 root cluster */ + inode_known[dir_nbr++]=inode; + td_list_for_each(file_walker, &dir_list.list) + { + const file_info_t *current_file=td_list_entry_const(file_walker, const file_info_t, list); + if(LINUX_S_ISDIR(current_file->st_mode)!=0 && + is_inode_valid(current_file, dir_nbr, inode_known)>0 && + strlen(dir_data->current_directory)+1+strlen(current_file->name)current_directory)-1) + { + if(strcmp(dir_data->current_directory,"/")) + strcat(dir_data->current_directory,"/"); + strcat(dir_data->current_directory,current_file->name); + dir_whole_partition_log_aux(disk, partition, dir_data, current_file->st_ino); + /* restore current_directory name */ + dir_data->current_directory[current_directory_namelength]='\0'; + } + } + delete_list_file(&dir_list); + dir_nbr--; + return 0; +} + +int dir_whole_partition_log(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode) +{ + log_partition(disk, partition); + return dir_whole_partition_log_aux(disk, partition, dir_data, inode); +} + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(dir_data); + @ requires \valid(copy_ok); + @ requires \valid(copy_bad); + @ requires \separated(disk, partition, dir_data, copy_ok, copy_bad); + @*/ +static int dir_whole_partition_copy_aux(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, unsigned int *copy_ok, unsigned int *copy_bad) +{ + struct td_list_head *file_walker = NULL; + static unsigned int dir_nbr=0; + static unsigned long int inode_known[MAX_DIR_NBR]; + const unsigned int current_directory_namelength=strlen(dir_data->current_directory); + file_info_t dir_list; + TD_INIT_LIST_HEAD(&dir_list.list); + if(dir_nbr==MAX_DIR_NBR) + return 1; /* subdirectories depth is too high => Back */ + dir_data->get_dir(disk, partition, dir_data, inode, &dir_list); + /* Not perfect for FAT32 root cluster */ + inode_known[dir_nbr++]=inode; + td_list_for_each(file_walker, &dir_list.list) + { + const file_info_t *current_file=td_list_entry_const(file_walker, const file_info_t, list); + if(strlen(dir_data->current_directory) + 1 + strlen(current_file->name) < + sizeof(dir_data->current_directory)-1) + { + if(strcmp(dir_data->current_directory,"/")) + strcat(dir_data->current_directory,"/"); + strcat(dir_data->current_directory,current_file->name); + if(LINUX_S_ISDIR(current_file->st_mode)!=0) + { + if(is_inode_valid(current_file, dir_nbr, inode_known)>0) + { + dir_whole_partition_copy_aux(disk, partition, dir_data, current_file->st_ino, copy_ok, copy_bad); + } + } + else if(LINUX_S_ISREG(current_file->st_mode)!=0) + { + if(dir_data->copy_file(disk, partition, dir_data, current_file) == 0) + (*copy_ok)++; + else + (*copy_bad)++; + } + } + /* restore current_directory name */ + dir_data->current_directory[current_directory_namelength]='\0'; + } + delete_list_file(&dir_list); + dir_nbr--; + return 0; +} + +void dir_whole_partition_copy(disk_t *disk, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode) +{ + unsigned int copy_ok=0; + unsigned int copy_bad=0; + char *dst_directory=(char *)MALLOC(4096); + dst_directory[0]='.'; + dst_directory[1]='\0'; +#ifdef HAVE_GETCWD + if(getcwd(dst_directory, 4096)==NULL) + { + free(dst_directory); + return ; + } +#endif + dir_data->local_dir=dst_directory; + dir_whole_partition_copy_aux(disk, partition, dir_data, inode, ©_ok, ©_bad); + log_info("Copy done! %u ok, %u failed", copy_ok, copy_bad); +} + +int filesort(const struct td_list_head *a, const struct td_list_head *b) +{ + const file_info_t *file_a=td_list_entry_const(a, const file_info_t, list); + const file_info_t *file_b=td_list_entry_const(b, const file_info_t, list); + /* Directories must be listed before files */ + const int res=((file_b->st_mode&LINUX_S_IFDIR)-(file_a->st_mode&LINUX_S_IFDIR)); + if(res) + return res; + /* . and .. must listed before the other directories */ + if((file_a->st_mode&LINUX_S_IFDIR) && strcmp(file_a->name, ".")==0) + return -1; + if((file_a->st_mode&LINUX_S_IFDIR) && strcmp(file_a->name, "..")==0 && + strcmp(file_b->name, ".")!=0) + return -1; + if((file_b->st_mode&LINUX_S_IFDIR) && strcmp(file_b->name, ".")==0) + return 1; + if((file_b->st_mode&LINUX_S_IFDIR) && strcmp(file_b->name, "..")==0 && + strcmp(file_a->name, ".")!=0) + return 1; + /* Files and directories are sorted by name */ + return strcmp(file_a->name, file_b->name); +} + +/* + * The mode_xlate function translates a linux mode into a native-OS mode_t. + */ + +static struct { + unsigned int lmask; + mode_t mask; +} mode_table[] = { +#ifdef S_IRUSR + { LINUX_S_IRUSR, S_IRUSR }, +#endif +#ifdef S_IWUSR + { LINUX_S_IWUSR, S_IWUSR }, +#endif +#ifdef S_IXUSR + { LINUX_S_IXUSR, S_IXUSR }, +#endif +#ifdef S_IRGRP + { LINUX_S_IRGRP, S_IRGRP }, +#endif +#ifdef S_IWGRP + { LINUX_S_IWGRP, S_IWGRP }, +#endif +#ifdef S_IXGRP + { LINUX_S_IXGRP, S_IXGRP }, +#endif +#ifdef S_IROTH + { LINUX_S_IROTH, S_IROTH }, +#endif +#ifdef S_IWOTH + { LINUX_S_IWOTH, S_IWOTH }, +#endif +#ifdef S_IXOTH + { LINUX_S_IXOTH, S_IXOTH }, +#endif + { 0, 0 } +}; + +/*@ + @ assigns \nothing; + @*/ +static mode_t mode_xlate(unsigned int lmode) +{ + mode_t mode = 0; + int i; + /*@ loop assigns i, mode; */ + for (i=0; mode_table[i].lmask; i++) { + if (lmode & mode_table[i].lmask) + mode |= mode_table[i].mask; + } + return mode; +} + +/** + * set_mode - Set the file's date and time + * @pathname: Path and name of the file to alter + * @mode: Mode using LINUX values + * + * Give a file a particular mode. + * + * Return: 0 Success, set the file's mode + * -1 Error, failed to change the file's mode + */ +int set_mode(const char *pathname, unsigned int mode) +{ +#if defined(HAVE_CHMOD) && ! ( defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) || defined(__OS2__)) + return chmod(pathname, mode_xlate(mode)); +#else + return 0; +#endif +} + +/*@ + @ requires valid_string(fn); + @*/ +static void strip_fn(char *fn) +{ + unsigned int i; + for(i=0;fn[i]!='\0';i++); + while(i>0 && (fn[i-1]==' '||fn[i-1]=='.')) + i--; + if(i==0 && (fn[i]==' '||fn[i]=='.')) + fn[i++]='_'; + fn[i]='\0'; +} + +#ifdef DJGPP +static inline unsigned char convert_char_dos(unsigned char car) +{ + if(car<0x20) + return '_'; + switch(car) + { + /* Forbidden */ + case '<': + case '>': + case ':': + case '"': + /* case '/': subdirectory */ + case '\\': + case '|': + case '?': + case '*': + /* Not recommanded */ + case '[': + case ']': + case ';': + case ',': + case '+': + case '=': + return '_'; + } + /* 'a' */ + if(car>=224 && car<=230) + return 'a'; + /* 'c' */ + if(car==231) + return 'c'; + /* 'e' */ + if(car>=232 && car<=235) + return 'e'; + /* 'i' */ + if(car>=236 && car<=239) + return 'n'; + /* n */ + if(car==241) + return 'n'; + /* 'o' */ + if((car>=242 && car<=246) || car==248) + return 'o'; + /* 'u' */ + if(car>=249 && car<=252) + return 'u'; + /* 'y' */ + if(car>=253) + return 'y'; + return car; +} + +/* + * filename_convert reads a maximum of n and writes a maximum of n+1 bytes + * dst string will be null-terminated + */ +static unsigned int filename_convert(char *dst, const char*src, const unsigned int n) +{ + unsigned int i; + for(i=0;i0 && (dst[i-1]==' '||dst[i-1]=='.')) + i--; + if(i==0 && (dst[i]==' '||dst[i]=='.')) + dst[i++]='_'; + dst[i]='\0'; + return i; +} +#elif defined(__CYGWIN__) || defined(__MINGW32__) +static inline unsigned char convert_char_win(unsigned char car) +{ + if(car<0x20) + return '_'; + switch(car) + { + /* Forbidden */ + case '<': + case '>': + case ':': + case '"': + /* case '/': subdirectory */ + case '\\': + case '|': + case '?': + case '*': + /* Not recommanded, valid for NTFS, invalid for FAT */ + case '[': + case ']': + case '+': + /* Not recommanded */ + case ';': + case ',': + case '=': + return '_'; + } + return car; +} + +static unsigned int filename_convert(char *dst, const char*src, const unsigned int n) +{ + unsigned int i; + for(i=0;i0 && (dst[i-1]==' '||dst[i-1]=='.')) + i--; + if(i==0 && (dst[i]==' '||dst[i]=='.')) + dst[i++]='_'; + dst[i]='\0'; + return i; +} +#elif defined(__APPLE__) +static unsigned int filename_convert(char *dst, const char*src, const unsigned int n) +{ + unsigned int i,j; + const unsigned char *p; /* pointers to actual position in source buffer */ + unsigned char *q; /* pointers to actual position in destination buffer */ + p=(const unsigned char *)src; + q=(unsigned char *)dst; + for(i=0,j=0; (*p)!='\0' && i=0 || errno==EEXIST) + return localdir; +#else + if(mkdir(localdir, 0775)>=0 || errno==EEXIST) + return localdir; +#endif + /* Need to create the parent and maybe convert the pathname */ + if(localroot!=NULL) + memcpy(localdir, localroot, l1); + localdir[l1]='\0'; + src=pathname; + dst=localdir+l1; + while(*src!='\0') + { + unsigned int n=0; + const char *src_org=src; + char *dst_org=dst; + for(n=0; + *src!='\0' && (n==0 || *src!='/'); + dst++, src++, n++) + *dst=*src; + *dst='\0'; +#ifdef __MINGW32__ + if(mkdir(localdir)<0 && errno==EINVAL) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + mkdir(localdir); + } +#elif defined(__CYGWIN__) + if(memcmp(&localdir[1],":/cygdrive",11)!=0 && + mkdir(localdir, 0775)<0 && errno==EINVAL) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + mkdir(localdir, 0775); + } +#else + if(mkdir(localdir, 0775)<0 && errno==EINVAL) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + (void)mkdir(localdir, 0775); + } +#endif + } +#else +#warning "You need a mkdir function!" +#endif + return localdir; +} + +void mkdir_local_for_file(const char *filename) +{ + char *dir; + char *sep; + dir=strdup(filename); + sep=strrchr(dir,'/'); + if(sep!=NULL) + { + *sep='\0'; + free(mkdir_local(NULL, dir)); + } + free(dir); +} + +FILE *fopen_local(char **localfilename, const char *localroot, const char *filename) +{ + const int l1=strlen(localroot); + const int l2=strlen(filename); + const char *src; + char *dst=(char *)MALLOC(l1+l2+1); + const char *src_org=filename; + char *dst_org=dst; + FILE *f_out; + memcpy(dst, localroot, l1); + memcpy(dst+l1, filename, l2+1); + *localfilename=dst; + strip_fn(dst); + f_out=fopen(dst,"wb"); + if(f_out) + return f_out; + /* Need to create the parent and maybe convert the pathname */ + src=filename; + memcpy(dst, localroot, l1+1); + dst+=l1; + while(*src!='\0') + { + unsigned int n; + src_org=src; + dst_org=dst; + for(n=0; + *src!='\0' && (n==0 || *src!='/'); + dst++, src++, n++) + *dst=*src; + *dst='\0'; + if(*src!='\0') + { +#ifdef __MINGW32__ + if(mkdir(*localfilename)<0 && errno==EINVAL) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + mkdir(*localfilename); + } +#elif defined(__CYGWIN__) + if(memcmp(&localfilename[1],":/cygdrive",11)!=0 && + mkdir(*localfilename, 0775)<0 && + (errno==EINVAL || errno==ENOENT)) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + mkdir(*localfilename, 0775); + } +#else + if(mkdir(*localfilename, 0775)<0 && errno==EINVAL) + { + unsigned int l; + l=filename_convert(dst_org, src_org, n); + dst=dst_org+l; + (void)mkdir(*localfilename, 0775); + } +#endif + } + } + f_out=fopen(*localfilename,"wb"); + if(f_out) + return f_out; + filename_convert(dst_org, src_org, l2); + return fopen(*localfilename,"wb"); +} diff --git a/subprojects/lib/src/dir.h b/subprojects/lib/src/dir.h new file mode 100644 index 0000000..b4d1802 --- /dev/null +++ b/subprojects/lib/src/dir.h @@ -0,0 +1,117 @@ +/* + + File: dir.h + + Copyright (C) 2004-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _DIR_H +#define _DIR_H +#ifdef __cplusplus +extern "C" { +#endif +#include "dir_common.h" + +/*@ + @ requires \valid(datestr); + @*/ +int set_datestr(char *datestr, size_t n, const time_t timev); + +/*@ + @ requires dir_data==\null || \valid_read(dir_data); + @ requires \valid_read(dir_list); + @ requires \separated(dir_data, dir_list); + @*/ +int dir_aff_log(const dir_data_t *dir_data, const file_info_t*dir_list); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \valid_read(list); + @*/ +void log_list_file(const disk_t *disk_car, const partition_t *partition, const dir_data_t *dir_data, const file_info_t*list); + +/*@ + @ requires \valid(list); + @*/ +unsigned int delete_list_file(file_info_t *list); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \separated(disk_car, partition, dir_data); + @*/ +int dir_whole_partition_log(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode); + +/*@ + @ requires \valid_read(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \separated(disk_car, partition, dir_data); + @*/ +void dir_whole_partition_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode); + +/*@ + @ requires \valid(str + (0 .. 9)); + @ assigns str[0 .. 9]; + @*/ +void mode_string (const unsigned int mode, char *str); + +/*@ + @ requires valid_read_string(pathname); + @*/ +int set_mode(const char *pathname, unsigned int mode); + +/*@ + @ requires valid_read_string(filename); + @ requires \separated(localfilename, localroot, filename); + @*/ +FILE *fopen_local(char **localfilename, const char *localroot, const char *filename); + +/*@ + @ requires valid_read_string(filename); + @*/ +char *gen_local_filename(const char *filename); + +/*@ + @ requires valid_read_string(localroot); + @ requires valid_read_string(pathname); + @*/ +char *mkdir_local(const char *localroot, const char *pathname); + +/*@ + @ requires valid_read_string(filename); + @*/ +void mkdir_local_for_file(const char *filename); + +/*@ + @ requires \valid_read(a); + @ requires \valid_read(b); + @*/ +int filesort(const struct td_list_head *a, const struct td_list_head *b); +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/dir_common.h b/subprojects/lib/src/dir_common.h new file mode 100644 index 0000000..8463d67 --- /dev/null +++ b/subprojects/lib/src/dir_common.h @@ -0,0 +1,123 @@ +/* + + File: dir_common.h + + Copyright (C) 2020 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _DIR_COMMON_H +#define _DIR_COMMON_H +#ifdef __cplusplus +extern "C" { +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include "list.h" +#define DIR_NAME_LEN 1024 +#define FLAG_LIST_DELETED 1 +#define FLAG_LIST_MASK12 2 +#define FLAG_LIST_MASK16 4 +#define FLAG_LIST_PATHNAME 8 +#define FLAG_LIST_ADS 16 +#define FLAG_LIST_SYSTEM 32 +/* capabilities */ +#define CAPA_LIST_DELETED 1 +#define CAPA_LIST_ADS 2 + +typedef enum { DIR_PART_ENOIMP=-3, DIR_PART_ENOSYS=-2, DIR_PART_EIO=-1, DIR_PART_OK=0} dir_partition_t; +typedef struct dir_data dir_data_t; +typedef struct +{ + struct td_list_head list; + char *name; + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_size; + time_t td_atime; /* time of last access */ + time_t td_mtime; /* time of last modification */ + time_t td_ctime; /* time of last status change */ + unsigned int status; +} file_info_t; + +struct dir_data +{ + void *display; + char current_directory[DIR_NAME_LEN]; + unsigned long int current_inode; + int verbose; + unsigned int param; + unsigned int capabilities; + int(*get_dir)(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_inode, file_info_t*list); + int (*copy_file)(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file); + void (*close)(dir_data_t *dir_data); + char *local_dir; + void *private_dir_data; +}; + +#define FILE_STATUS_DELETED 1 +#define FILE_STATUS_MARKED 2 +#define FILE_STATUS_ADS 4 + +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFSOCK 0140000 +#define LINUX_S_IFLNK 0120000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_IFBLK 0060000 +#define LINUX_S_IFDIR 0040000 +#define LINUX_S_IFCHR 0020000 +#define LINUX_S_IFIFO 0010000 +#define LINUX_S_ISUID 0004000 +#define LINUX_S_ISGID 0002000 +#define LINUX_S_ISVTX 0001000 + + +#define LINUX_S_IRWXU 00700 +#define LINUX_S_IRUSR 00400 +#define LINUX_S_IWUSR 00200 +#define LINUX_S_IXUSR 00100 + +#define LINUX_S_IRWXG 00070 +#define LINUX_S_IRGRP 00040 +#define LINUX_S_IWGRP 00020 +#define LINUX_S_IXGRP 00010 + +#define LINUX_S_IRWXO 00007 +#define LINUX_S_IROTH 00004 +#define LINUX_S_IWOTH 00002 +#define LINUX_S_IXOTH 00001 + +#define LINUX_S_IRWXUGO (LINUX_S_IRWXU|LINUX_S_IRWXG|LINUX_S_IRWXO) +#define LINUX_S_IALLUGO (LINUX_S_ISUID|LINUX_S_ISGID|LINUX_S_ISVTX|LINUX_S_IRWXUGO) +#define LINUX_S_IRUGO (LINUX_S_IRUSR|LINUX_S_IRGRP|LINUX_S_IROTH) +#define LINUX_S_IWUGO (LINUX_S_IWUSR|LINUX_S_IWGRP|LINUX_S_IWOTH) +#define LINUX_S_IXUGO (LINUX_S_IXUSR|LINUX_S_IXGRP|LINUX_S_IXOTH) + +#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK) +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) +#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) +#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR) +#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK) +#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO) +#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK) + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ewf.c b/subprojects/lib/src/ewf.c new file mode 100644 index 0000000..e7c6391 --- /dev/null +++ b/subprojects/lib/src/ewf.c @@ -0,0 +1,605 @@ +/* + + File: ewf.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_LIBEWF +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF) + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include /* lseek, read, write, close */ +#endif + +#ifdef HAVE_FCNTL_H +#include /* open */ +#endif + +#include +#include + +#ifdef HAVE_STDLIB_H +#include /* free */ +#endif + +#include "types.h" +#include "common.h" +#include "ewf.h" +#include "fnctdsk.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include + +#if !defined( LIBEWF_HANDLE ) +/* libewf version 2 no longer defines LIBEWF_HANDLE + */ +#define HAVE_LIBEWF_V2_API +#endif + +#if !defined( HAVE_LIBEWF_V2_API ) && defined( HAVE_GLOB_H ) +#include +#endif + +#include "log.h" +#include "hdaccess.h" + +extern const arch_fnct_t arch_none; + +static const char *fewf_description(disk_t *disk); +static const char *fewf_description_short(disk_t *disk); +static void fewf_clean(disk_t *disk); +static int fewf_pread(disk_t *disk, void *buffer, const unsigned int count, const uint64_t offset); +static int fewf_nopwrite(disk_t *disk, const void *buffer, const unsigned int count, const uint64_t offset); +static int fewf_pwrite(disk_t *disk, const void *buffer, const unsigned int count, const uint64_t offset); +static int fewf_sync(disk_t *disk); + +struct info_fewf_struct +{ +#if defined( HAVE_LIBEWF_V2_API ) + libewf_handle_t *handle; +#else + LIBEWF_HANDLE *handle; +#endif + uint64_t offset; + char *file_name; + int mode; + void *buffer; + unsigned int buffer_size; +}; + +#if defined( HAVE_LIBEWF_V2_API ) +disk_t *fewf_init(const char *device, const int mode) +{ + unsigned int num_files=0; + char **filenames= NULL; + disk_t *disk=NULL; + struct info_fewf_struct *data; + libewf_error_t *ewf_error = NULL; + data=(struct info_fewf_struct *)MALLOC(sizeof(struct info_fewf_struct)); + memset(data, 0, sizeof(struct info_fewf_struct)); + data->file_name = strdup(device); + if(data->file_name==NULL) + { + free(data); + return NULL; + } + data->handle=NULL; + data->mode = mode; + +#ifdef DEBUG_EWF + libewf_notify_set_stream( stderr, NULL ); + libewf_notify_set_verbose( 1 ); +#endif + + if( libewf_glob( + data->file_name, + strlen(data->file_name), + LIBEWF_FORMAT_UNKNOWN, + &filenames, + (int *)&num_files, + &ewf_error) < 0 ) + { + char buffer[4096]; + libewf_error_sprint(ewf_error, buffer, sizeof(buffer)); + log_error("libewf_glob(%s) failed: %s\n", device, buffer); + libewf_error_free(&ewf_error); + free(data->file_name); + free(data); + return NULL; + } + + if((mode&TESTDISK_O_RDWR)==TESTDISK_O_RDWR) + { + if( libewf_handle_initialize( + &( data->handle ), + &ewf_error) != 1 ) + { + char buffer[4096]; + log_error("libewf_handle_initialize failed\n"); + libewf_error_sprint(ewf_error, buffer, sizeof(buffer)); + log_error("%s\n", buffer); + libewf_error_free(&ewf_error); + libewf_glob_free( + filenames, + num_files, + NULL ); + free(data->file_name); + free(data); + return NULL; + } + if( libewf_handle_open( + data->handle, + filenames, + num_files, +#ifdef LIBEWF_OPEN_READ_WRITE + LIBEWF_OPEN_READ_WRITE, +#else + LIBEWF_OPEN_READ | LIBEWF_OPEN_WRITE, +#endif + &ewf_error) != 1 ) + { + char buffer[4096]; + log_error("libewf_handle_open(%s) in RW mode failed\n", device); + libewf_error_sprint(ewf_error, buffer, sizeof(buffer)); + log_error("%s\n", buffer); + libewf_error_free(&ewf_error); + ewf_error=NULL; + libewf_handle_free( + &( data->handle ), + NULL ); + data->handle=NULL; + } + } + if(data->handle==NULL) + { + data->mode&=~TESTDISK_O_RDWR; + if( libewf_handle_initialize( + &( data->handle ), + &ewf_error) != 1 ) + { + char buffer[4096]; + log_error("libewf_handle_initialize failed\n"); + libewf_error_sprint(ewf_error, buffer, sizeof(buffer)); + log_error("%s\n", buffer); + libewf_glob_free( + filenames, + num_files, + NULL ); + free(data->file_name); + free(data); + return NULL; + } + if( libewf_handle_open( + data->handle, + filenames, + num_files, + LIBEWF_OPEN_READ, + &ewf_error) != 1 ) + { + char buffer[4096]; + log_error("libewf_handle_open(%s) in RO mode failed\n", device); + libewf_error_sprint(ewf_error, buffer, sizeof(buffer)); + log_error("%s\n", buffer); + + libewf_handle_free( + &( data->handle ), + NULL ); + + libewf_glob_free( + filenames, + num_files, + NULL ); + free(data->file_name); + free(data); + return NULL; + } + } + if( libewf_handle_set_header_values_date_format( + data->handle, + LIBEWF_DATE_FORMAT_DAYMONTH, + NULL ) != 1 ) + { + log_error("%s Unable to set header values date format\n", device); + } + disk=(disk_t *)MALLOC(sizeof(*disk)); + init_disk(disk); + disk->arch=&arch_none; + disk->device=strdup(device); + if(disk->device==NULL) + { + free(disk); + libewf_glob_free( + filenames, + num_files, + NULL ); + free(data->file_name); + free(data); + return NULL; + } + disk->data=data; + disk->description=&fewf_description; + disk->description_short=&fewf_description_short; + disk->pread=&fewf_pread; + disk->pwrite=((data->mode&TESTDISK_O_RDWR)?&fewf_pwrite:&fewf_nopwrite); + disk->sync=&fewf_sync; + disk->access_mode=(data->mode&TESTDISK_O_RDWR); + disk->clean=&fewf_clean; + { + uint32_t bytes_per_sector = 0; + if( libewf_handle_get_bytes_per_sector( + data->handle, + &bytes_per_sector, + NULL ) != 1 ) + { + disk->sector_size=DEFAULT_SECTOR_SIZE; + } + else + { + disk->sector_size=bytes_per_sector; + } + } +// printf("libewf_get_bytes_per_sector %u\n",disk->sector_size); + if(disk->sector_size==0) + disk->sector_size=DEFAULT_SECTOR_SIZE; + /* Set geometry */ + disk->geom.cylinders=0; + disk->geom.heads_per_cylinder=1; + disk->geom.sectors_per_head=1; + disk->geom.bytes_per_sector=disk->sector_size; + { + size64_t media_size = 0; + if( libewf_handle_get_media_size( + data->handle, + &media_size, + NULL ) != 1 ) + { + disk->disk_real_size=0; + } + disk->disk_real_size=media_size; + } + update_disk_car_fields(disk); + libewf_glob_free( + filenames, + num_files, + NULL ); + return disk; +} +#else +disk_t *fewf_init(const char *device, const int mode) +{ + unsigned int num_files=0; + char **filenames= NULL; + disk_t *disk=NULL; + struct info_fewf_struct *data; +#if defined( HAVE_GLOB_H ) + glob_t globbuf; +#endif + data=(struct info_fewf_struct *)MALLOC(sizeof(struct info_fewf_struct)); + memset(data, 0, sizeof(struct info_fewf_struct)); + data->file_name = strdup(device); + if(data->file_name==NULL) + { + free(data); + return NULL; + } + data->handle=NULL; + data->mode = mode; + +#ifdef DEBUG_EWF + libewf_set_notify_values( stderr, 1 ); +#endif + +#if defined( HAVE_GLOB_H ) + { + globbuf.gl_offs = 0; + glob(data->file_name, GLOB_DOOFFS, NULL, &globbuf); + if(globbuf.gl_pathc>0) + { + filenames=(char **)MALLOC(globbuf.gl_pathc * sizeof(*filenames)); + for (num_files=0; num_filesfile_name); + free(data); + return NULL; + } +#else + { + filenames=(char **)MALLOC(1*sizeof(*filenames)); + filenames[num_files] = data->file_name; + num_files++; + } +#endif + + if((mode&TESTDISK_O_RDWR)==TESTDISK_O_RDWR) + { + data->handle=libewf_open(filenames, num_files, LIBEWF_OPEN_READ_WRITE); + if(data->handle==NULL) + { + log_error("libewf_open(%s) in RW mode failed\n", device); + } + } + if(data->handle==NULL) + { + data->mode&=~TESTDISK_O_RDWR; + data->handle=libewf_open(filenames, num_files, LIBEWF_OPEN_READ); + if(data->handle==NULL) + { + log_error("libewf_open(%s) in RO mode failed\n", device); +#if defined( HAVE_GLOB_H ) + globfree(&globbuf); +#endif + free(filenames); + free(data->file_name); + free(data); + return NULL; + } + } + + if( libewf_parse_header_values( data->handle, LIBEWF_DATE_FORMAT_DAYMONTH) != 1 ) + { + log_error("%s Unable to parse EWF header values\n", device); + } + disk=(disk_t *)MALLOC(sizeof(*disk)); + init_disk(disk); + disk->arch=&arch_none; + disk->device=strdup(device); + if(disk->device==NULL) + { + free(disk); +#if defined( HAVE_GLOB_H ) + globfree(&globbuf); +#endif + free(filenames); + free(data->file_name); + free(data); + return NULL; + } + disk->data=data; + disk->description=&fewf_description; + disk->description_short=&fewf_description_short; + disk->pread=&fewf_pread; + disk->pwrite=((data->mode&TESTDISK_O_RDWR)?&fewf_pwrite:&fewf_nopwrite); + disk->sync=&fewf_sync; + disk->access_mode=(data->mode&TESTDISK_O_RDWR); + disk->clean=&fewf_clean; +#if defined( LIBEWF_GET_BYTES_PER_SECTOR_HAVE_TWO_ARGUMENTS ) + { + uint32_t bytes_per_sector = 0; + if( libewf_get_bytes_per_sector(data->handle, &bytes_per_sector)<0) + { + disk->sector_size=DEFAULT_SECTOR_SIZE; + } + else + { + disk->sector_size=bytes_per_sector; + } + } +#else + disk->sector_size=libewf_get_bytes_per_sector(data->handle); +#endif +// printf("libewf_get_bytes_per_sector %u\n",disk->sector_size); + if(disk->sector_size==0) + disk->sector_size=DEFAULT_SECTOR_SIZE; + /* Set geometry */ + disk->geom.cylinders=0; + disk->geom.heads_per_cylinder=1; + disk->geom.sectors_per_head=1; + disk->geom.bytes_per_sector=disk->sector_size; +#if defined( LIBEWF_GET_MEDIA_SIZE_HAVE_TWO_ARGUMENTS ) + { + size64_t media_size = 0; + if(libewf_get_media_size(data->handle, &media_size)<0) + { + disk->disk_real_size=0; + } + else + { + disk->disk_real_size=media_size; + } + } +#else + disk->disk_real_size=libewf_get_media_size(data->handle); +#endif + update_disk_car_fields(disk); +#if defined( HAVE_GLOB_H ) + globfree(&globbuf); +#endif + free(filenames); + return disk; +} +#endif + +static const char *fewf_description(disk_t *disk) +{ + const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk->data; + char buffer_disk_size[100]; + size_to_unit(disk->disk_size, buffer_disk_size); + snprintf(disk->description_txt, sizeof(disk->description_txt),"Image %s - %s - CHS %lu %u %u%s", + data->file_name, buffer_disk_size, + disk->geom.cylinders, disk->geom.heads_per_cylinder, disk->geom.sectors_per_head, + ((data->mode&O_RDWR)==O_RDWR?"":" (RO)")); + return disk->description_txt; +} + +static const char *fewf_description_short(disk_t *disk) +{ + const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk->data; + char buffer_disk_size[100]; + size_to_unit(disk->disk_size, buffer_disk_size); + snprintf(disk->description_short_txt, sizeof(disk->description_txt),"Image %s - %s%s", + data->file_name, buffer_disk_size, + ((data->mode&O_RDWR)==O_RDWR?"":" (RO)")); + return disk->description_short_txt; +} + +static void fewf_clean(disk_t *disk) +{ + if(disk->data!=NULL) + { + struct info_fewf_struct *data=(struct info_fewf_struct *)disk->data; +#if defined( HAVE_LIBEWF_V2_API ) + libewf_handle_close( + data->handle, + NULL); + libewf_handle_free( + &( data->handle ), + NULL ); +#else + libewf_close(data->handle); +#endif + free(data->file_name); + data->file_name=NULL; + + free(data->buffer); + data->buffer=NULL; + + free(disk->data); + disk->data=NULL; + } + generic_clean(disk); +} + +static int fewf_sync(disk_t *disk) +{ + errno=EINVAL; + return -1; +} + +static int fewf_pread(disk_t *disk, void *buffer, const unsigned int count, const uint64_t offset) +{ + struct info_fewf_struct *data=(struct info_fewf_struct *)disk->data; + int64_t taille; +#if defined( HAVE_LIBEWF_V2_API ) +#if defined( HAVE_LIBEWF_HANDLE_READ_BUFFER_AT_OFFSET ) + taille = libewf_handle_read_buffer_at_offset( + data->handle, + buffer, + count, + offset, + NULL ); +#else + taille = libewf_handle_read_random( + data->handle, + buffer, + count, + offset, + NULL ); +#endif +#else + taille=libewf_read_random(data->handle, buffer, count, offset); +#endif + if(taille!=count) + { + log_error("fewf_pread(xxx,%u,buffer,%lu(%u/%u/%u)) read err: ", + (unsigned)(count/disk->sector_size), (long unsigned)(offset/disk->sector_size), + offset2cylinder(disk,offset), offset2head(disk,offset), offset2sector(disk,offset)); + if(taille<0) + log_error("%s\n", strerror(errno)); + else if(taille==0) + log_error("read after end of file\n"); + else + log_error("Partial read\n"); + if(taille<=0) + return -1; + } + return taille; +} + +static int fewf_pwrite(disk_t *disk, const void *buffer, const unsigned int count, const uint64_t offset) +{ + struct info_fewf_struct *data=(struct info_fewf_struct *)disk->data; + int64_t taille; +#if defined( HAVE_LIBEWF_V2_API ) +#if defined( HAVE_LIBEWF_HANDLE_WRITE_BUFFER_AT_OFFSET ) + taille = libewf_handle_write_buffer_at_offset( + data->handle, + buffer, + count, + offset, + NULL ); +#else + taille = libewf_handle_write_random( + data->handle, + buffer, + count, + offset, + NULL ); +#endif +#else + taille=libewf_write_random(data->handle, buffer, count, offset); +#endif + if(taille!=count) + { + log_error("fewf_pwrite(xxx,%u,buffer,%lu(%u/%u/%u)) write err: ", + (unsigned)(count/disk->sector_size), (long unsigned)(offset/disk->sector_size), + offset2cylinder(disk,offset), offset2head(disk,offset), offset2sector(disk,offset)); + log_error("%s\n", strerror(errno)); + return -1; + } + return taille; +} + +static int fewf_nopwrite(disk_t *disk, const void *buffer, const unsigned int count, const uint64_t offset) +{ + log_error("fewf_nopwrite(xx,%u,buffer,%lu(%u/%u/%u)) write refused\n", + (unsigned)(count/disk->sector_size), (long unsigned)(offset/disk->sector_size), + offset2cylinder(disk,offset), offset2head(disk,offset), offset2sector(disk,offset)); + return -1; +} + +const char*td_ewf_version(void) +{ +#ifdef LIBEWF_VERSION_STRING + return (const char*)LIBEWF_VERSION_STRING; +#elif defined(LIBEWF_VERSION) + return LIBEWF_VERSION; +#else + return "available"; +#endif +} +#else +#include "ewf.h" +const char*td_ewf_version(void) +{ + return "none"; +} +#endif /* defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF) */ diff --git a/subprojects/lib/src/ewf.h b/subprojects/lib/src/ewf.h new file mode 100644 index 0000000..105080a --- /dev/null +++ b/subprojects/lib/src/ewf.h @@ -0,0 +1,45 @@ +/* + + File: ewf.h + + Copyright (C) 2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EWF_H +#define _EWF_H +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_LIBEWF +#endif + +#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF) +/*@ + @ requires valid_read_string(device); + @ ensures valid_disk(\result); + @*/ +disk_t *fewf_init(const char *device, const int testdisk_mode); +#endif +/*@ assigns \nothing; */ +const char*td_ewf_version(void); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/exfat.c b/subprojects/lib/src/exfat.c new file mode 100644 index 0000000..8aef785 --- /dev/null +++ b/subprojects/lib/src/exfat.c @@ -0,0 +1,120 @@ +/* + + File: exfat.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "exfat.h" +#include "log.h" + +extern const arch_fnct_t arch_none; + +uint64_t exfat_cluster_to_offset(const struct exfat_super_block *exfat_header, const unsigned int cluster) +{ + return ((uint64_t)(((cluster-2) << exfat_header->block_per_clus_bits) + le32(exfat_header->clus_blocknr))) << exfat_header->blocksize_bits; +} + +int exfat_read_cluster(disk_t *disk, const partition_t *partition, const struct exfat_super_block*exfat_header, void *buffer, const unsigned int cluster) +{ + return disk->pread(disk, + buffer, + 1 << (exfat_header->block_per_clus_bits + exfat_header->blocksize_bits), + partition->part_offset + exfat_cluster_to_offset(exfat_header, cluster)); +} + +/*@ + @ requires \valid(partition); + @ requires \valid_read(exfat_header); + @ requires \separated(partition, exfat_header); + @*/ +static void set_exFAT_info(partition_t *partition, const struct exfat_super_block*exfat_header) +{ + partition->upart_type=UP_EXFAT; + partition->blocksize=1<<(exfat_header->block_per_clus_bits + exfat_header->blocksize_bits); + partition->fsname[0]='\0'; + if(partition->sb_offset==0) + snprintf(partition->info, sizeof(partition->info), "exFAT, blocksize=%u", partition->blocksize); + else + snprintf(partition->info, sizeof(partition->info), "exFAT found using backup sector, blocksize=%u", partition->blocksize); +} + +int check_exFAT(disk_t *disk, partition_t *partition) +{ + unsigned char *buffer=(unsigned char*)MALLOC(EXFAT_BS_SIZE); + if(disk->pread(disk, buffer, EXFAT_BS_SIZE, partition->part_offset) != EXFAT_BS_SIZE) + { + free(buffer); + return 1; + } + if(test_exFAT((struct exfat_super_block*)buffer)!=0) + { + free(buffer); + return 1; + } + set_exFAT_info(partition, (struct exfat_super_block*)buffer); + free(buffer); + return 0; +} + +int test_exFAT(const struct exfat_super_block *exfat_header) +{ + if(le16(exfat_header->signature)!=0xAA55) + return 1; + if(memcmp(exfat_header->oem_id, "EXFAT ", sizeof(exfat_header->oem_id))!=0) + return 1; + return 0; +} + +int recover_exFAT(const disk_t *disk, const struct exfat_super_block *exfat_header, partition_t *partition) +{ + if(test_exFAT(exfat_header)!=0) + return 1; + partition->sborg_offset=0; + partition->sb_size=12 << exfat_header->blocksize_bits; + partition->part_type_i386=P_EXFAT; + partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA; + partition->part_size=(uint64_t)le64(exfat_header->nr_sectors) * disk->sector_size; +#ifdef DEBUG_exFAT + log_info("recover_exFAT:\n"); + log_info("start_sector=%llu\n", (long long unsigned)le64(exfat_header->start_sector)); + log_info("blocksize=%u\n", (12<blocksize_bits)); + log_info("part_offset=%llu\n", partition->part_offset); +#endif + if((le64(exfat_header->start_sector) * disk ->sector_size + + (12 << exfat_header->blocksize_bits) == partition->part_offset) || + (disk->arch==&arch_none && ((uint64_t)12 << exfat_header->blocksize_bits) == partition->part_offset)) + { + partition->sb_offset=12 << exfat_header->blocksize_bits; + partition->part_offset-=partition->sb_offset; + } + set_exFAT_info(partition, exfat_header); + return 0; +} diff --git a/subprojects/lib/src/exfat.h b/subprojects/lib/src/exfat.h new file mode 100644 index 0000000..29e0eee --- /dev/null +++ b/subprojects/lib/src/exfat.h @@ -0,0 +1,138 @@ +/* + + file: exfat.h + + Copyright (C) 2010-2011 Christophe GRENIER + + this software is free software; you can redistribute it and/or modify + it under the terms of the gnu general public license as published by + the free software foundation; either version 2 of the license, or + (at your option) any later version. + + this program is distributed in the hope that it will be useful, + but without any warranty; without even the implied warranty of + merchantability or fitness for a particular purpose. see the + gnu general public license for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXFAT_H +#define _EXFAT_H +#ifdef __cplusplus +extern "C" { +#endif +#define EXFAT_BS_SIZE 512 + +struct exfat_super_block { + unsigned char jmp_boot[3]; /* boot strap short or near jump */ + unsigned char oem_id[8]; /* oem-id */ + unsigned char unused0; /* 0x00... */ + uint32_t unused1[13]; + uint64_t start_sector; /* 0x40 start sector of partition */ + uint64_t nr_sectors; /* number of sectors of partition */ + uint32_t fat_blocknr; /* 0x50 start blocknr of FAT */ + uint32_t fat_block_counts; /* number of FAT blocks */ + uint32_t clus_blocknr; /* start blocknr of cluster */ + uint32_t total_clusters; /* number of total clusters */ + uint32_t rootdir_clusnr; /* 0x60 start clusnr of rootdir */ + uint32_t serial_number; /* volume serial number */ + unsigned char xxxx01; /* ??? (0x00 or any value (?)) */ + unsigned char xxxx02; /* ??? (0x01 or 0x00 (?)) */ + uint16_t state; /* state of this volume */ + unsigned char blocksize_bits; /* 0x6c bits of block size */ + unsigned char block_per_clus_bits; /* bits of blocks per cluster */ + unsigned char number_of_fats; + unsigned char drive_select; /* Used by INT 13 */ + unsigned char allocated_percent; /* 0x70 percentage of allocated space (?) */ + unsigned char xxxx05[397]; /* ??? (0x00...) */ + uint16_t signature; /* 0xaa55 */ +} __attribute__ ((gcc_struct, __packed__)); + +struct exfat_file_entry +{ + uint8_t type; + uint8_t sec_count; + uint16_t checksum; + uint16_t attr; + uint16_t reserved1; + uint16_t ctime; + uint16_t cdate; + uint16_t mtime; + uint16_t mdate; + uint16_t atime; + uint16_t adate; + uint8_t cms; + uint8_t mms; + uint8_t ctz; + uint8_t mtz; + uint8_t reserved2[7]; +} __attribute__ ((gcc_struct, __packed__)); + +struct exfat_stream_ext_entry +{ + uint8_t type; + uint8_t sec_flags; + uint8_t reserved1; + uint8_t name_length; + uint16_t name_hash; + uint16_t reserved2; + uint64_t valid_data_length; + uint32_t reserved3; + uint32_t first_cluster; + uint64_t data_length; +} __attribute__ ((gcc_struct, __packed__)); + +struct exfat_alloc_bitmap_entry +{ + uint8_t type; + uint8_t bitmap_flags; + uint8_t reserved[18]; + uint32_t first_cluster; + uint64_t data_length; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(exfat_header); + @ assigns \nothing; + @*/ +uint64_t exfat_cluster_to_offset(const struct exfat_super_block *exfat_header, const unsigned int cluster); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires \valid_read(exfat_header); + @ requires \separated(disk, partition, exfat_header, (char *)buffer); + @*/ +int exfat_read_cluster(disk_t *disk, const partition_t *partition, const struct exfat_super_block*exfat_header, void *buffer, const unsigned int cluster); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires \separated(disk, partition); + @*/ +int check_exFAT(disk_t *disk, partition_t *partition); + +/*@ + @ requires \valid_read(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, exfat_header, partition); + @*/ +int recover_exFAT(const disk_t *disk, const struct exfat_super_block *exfat_header, partition_t *partition); + +/*@ + @ requires \valid_read(exfat_header); + @ assigns \nothing; + @*/ +int test_exFAT(const struct exfat_super_block *exfat_header); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/exfatp.c b/subprojects/lib/src/exfatp.c new file mode 100644 index 0000000..edcb36a --- /dev/null +++ b/subprojects/lib/src/exfatp.c @@ -0,0 +1,126 @@ +/* + + File: fatp.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "types.h" +#include "common.h" +#include "list.h" +#include "filegen.h" +#include "photorec.h" +#include "exfatp.h" +#include "exfat.h" +#include "log.h" +#include "fat.h" + +/*@ + @ requires \valid_read(buffer + ( 0 .. size-1)); + @ assigns \nothing; + @*/ +static struct exfat_alloc_bitmap_entry *exfat_get_bitmap(unsigned char*buffer, const unsigned int size) +{ + unsigned int i; + /*@ loop assigns i; */ + for(i=0; ipread(disk, exfat_header, 0x200, partition->part_offset) != 0x200) + { + log_error("Can't read exFAT boot sector.\n"); + free(exfat_header); + return 0; + } + cluster_shift=exfat_header->block_per_clus_bits + exfat_header->blocksize_bits; + /* Load bitmap information */ + { + const struct exfat_alloc_bitmap_entry *bitmap; + const uint64_t start=partition->part_offset + + exfat_cluster_to_offset(exfat_header, le32(exfat_header->rootdir_clusnr)); + unsigned char *buffer_rootdir=(unsigned char *)MALLOC(1<fat_blocknr) << exfat_header->blocksize_bits; + uint64_t start_free=0; + uint64_t end_free=0; + if(disk->pread(disk, buffer_rootdir, 1 << cluster_shift, start) != (1<first_cluster); + log_trace("exfat_remove_used_space\n"); + buffer=(unsigned char *)MALLOC(1<total_clusters)+2; i++) + { + const unsigned int offset_o=(i-2)%(8<>(offset_o%8))&1) != 0) + { + /* Not free */ + if(end_free+1==partition->part_offset + exfat_cluster_to_offset(exfat_header, i)) + end_free+=(1<part_offset + exfat_cluster_to_offset(exfat_header, i); + end_free=start_free + (1< + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXFATP_H +#define _EXFATP_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(disk, partition, list_search_space); + @*/ +// ensures valid_list_search_space(list_search_space); +unsigned int exfat_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2.c b/subprojects/lib/src/ext2.c new file mode 100644 index 0000000..6916a3d --- /dev/null +++ b/subprojects/lib/src/ext2.c @@ -0,0 +1,183 @@ +/* + + File: ext2.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "ext2.h" +#include "fnctdsk.h" +#include "log.h" +#include "guid_cpy.h" + +static void set_EXT2_info(const struct ext2_super_block *sb, partition_t *partition, const int verbose); + +int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose) +{ + unsigned char *buffer=(unsigned char*)MALLOC(EXT2_SUPERBLOCK_SIZE); + if(disk_car->pread(disk_car, buffer, EXT2_SUPERBLOCK_SIZE, partition->part_offset + 0x400) != EXT2_SUPERBLOCK_SIZE) + { + free(buffer); + return 1; + } + if(test_EXT2((struct ext2_super_block*)buffer, partition)!=0) + { + free(buffer); + return 1; + } + set_EXT2_info((struct ext2_super_block*)buffer, partition, verbose); + free(buffer); + return 0; +} + +static void set_EXT2_info(const struct ext2_super_block *sb, partition_t *partition, const int verbose) +{ + if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_HUGE_FILE)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_GDT_CSUM)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_DIR_NLINK)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)!=0 || + EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_64BIT)!=0 || + EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_MMP)!=0) + partition->upart_type=UP_EXT4; + else if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0) + partition->upart_type=UP_EXT3; + else + partition->upart_type=UP_EXT2; + partition->blocksize=EXT2_MIN_BLOCK_SIZE<s_log_block_size); + set_part_name(partition,sb->s_volume_name,16); + /* sb->s_last_mounted seems to be unemployed in kernel 2.2.16 */ + if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_HUGE_FILE)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_GDT_CSUM)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_DIR_NLINK)!=0 || + EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)!=0 || + EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_64BIT)!=0 || + EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_MMP)!=0) + snprintf(partition->info, sizeof(partition->info), "ext4 blocksize=%u", partition->blocksize); + else if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0) + snprintf(partition->info, sizeof(partition->info), "ext3 blocksize=%u", partition->blocksize); + else + snprintf(partition->info, sizeof(partition->info), "ext2 blocksize=%u", partition->blocksize); + if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_LARGE_FILE)!=0) + strcat(partition->info," Large_file"); + if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)!=0) + strcat(partition->info," Sparse_SB"); + if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_RECOVER)!=0) + strcat(partition->info," Recover"); + if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)!=0) + strcat(partition->info," Journal_dev"); + if(le16(sb->s_block_group_nr)!=0) + { + strcat(partition->info," Backup_SB"); + if(verbose>0) + { + log_warning("\nblock_group_nr %u\n",le16(sb->s_block_group_nr)); + } + } + /* last mounted => date */ +} + +/* +Primary superblock is at 1024 (SUPERBLOCK_OFFSET) +Group 0 begin at s_first_data_block +*/ +int recover_EXT2(const disk_t *disk, const struct ext2_super_block *sb, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_EXT2(sb, partition)!=0) + return 1; + if(dump_ind!=0) + { + if(partition!=NULL && disk!=NULL) + log_info("\nEXT2/EXT3 magic value at %u/%u/%u\n", + offset2cylinder(disk,partition->part_offset), + offset2head(disk,partition->part_offset), + offset2sector(disk,partition->part_offset)); + /* There is a little offset ... */ + dump_log(sb,DEFAULT_SECTOR_SIZE); + } + if(partition==NULL) + return 0; + set_EXT2_info(sb, partition, verbose); + partition->part_type_i386=P_LINUX; + partition->part_type_mac=PMAC_LINUX; + partition->part_type_sun=PSUN_LINUX; + partition->part_type_gpt=GPT_ENT_TYPE_LINUX_DATA; + partition->part_size=td_ext2fs_blocks_count(sb) * EXT2_MIN_BLOCK_SIZE<s_log_block_size); + guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->s_uuid); + if(verbose>0) + { + log_info("\n"); + } + partition->sborg_offset=0x400; + partition->sb_size=EXT2_SUPERBLOCK_SIZE; + if(le16(sb->s_block_group_nr)>0) + { + const unsigned long int block_nr=(le32(sb->s_first_data_block)+le16(sb->s_block_group_nr)*le32(sb->s_blocks_per_group)); + if(partition->part_offset< (uint64_t)block_nr * (EXT2_MIN_BLOCK_SIZE<s_log_block_size))) + { + log_error("recover_EXT2: part_offset problem\n"); + return 1; + } + partition->sb_offset=(uint64_t)block_nr * (EXT2_MIN_BLOCK_SIZE<s_log_block_size)); + partition->part_offset-=partition->sb_offset; + log_warning("recover_EXT2: \"e2fsck -b %lu -B %u device\" may be needed\n", + block_nr, partition->blocksize); + } + else + { + partition->sb_offset=0; + } + if(verbose>0) + { + log_info("recover_EXT2: s_block_group_nr=%u/%u, s_mnt_count=%u/%u, s_blocks_per_group=%u, s_inodes_per_group=%u\n", + le16(sb->s_block_group_nr), + (unsigned int)(td_ext2fs_blocks_count(sb) /le32(sb->s_blocks_per_group)), + le16(sb->s_mnt_count), le16(sb->s_max_mnt_count), + (unsigned int)le32(sb->s_blocks_per_group), + (unsigned int)le32(sb->s_inodes_per_group)); + log_info("recover_EXT2: s_blocksize=%u\n", partition->blocksize); + log_info("recover_EXT2: s_blocks_count %lu\n", (long unsigned int)td_ext2fs_blocks_count(sb)); + if(disk==NULL) + log_info("recover_EXT2: part_size %lu\n", (long unsigned)(partition->part_size / DEFAULT_SECTOR_SIZE)); + else + log_info("recover_EXT2: part_size %lu\n", (long unsigned)(partition->part_size / disk->sector_size)); + } + if(sb->s_mkfs_time>0) + { + const time_t tm=le32(sb->s_mkfs_time); + log_info("Filesystem created: %s", ctime(&tm)); + } + if(sb->s_mtime>0) + { + const time_t tm=le32(sb->s_mtime); + log_info("Last mount time: %s", ctime(&tm)); + } + return 0; +} diff --git a/subprojects/lib/src/ext2.h b/subprojects/lib/src/ext2.h new file mode 100644 index 0000000..bee4d59 --- /dev/null +++ b/subprojects/lib/src/ext2.h @@ -0,0 +1,48 @@ +/* + + File: ext2.h + + Copyright (C) 1998-2004,2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXT2_H +#define _EXT2_H +#include "ext2_common.h" +#ifdef __cplusplus +extern "C" { +#endif +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_EXT2(disk_t *disk_car, partition_t *partition, const int verbose); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(sb); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int recover_EXT2(const disk_t *disk_car, const struct ext2_super_block *sb, partition_t *partition, const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2_common.c b/subprojects/lib/src/ext2_common.c new file mode 100644 index 0000000..d3d557a --- /dev/null +++ b/subprojects/lib/src/ext2_common.c @@ -0,0 +1,94 @@ +/* + + File: ext2_common.c + + Copyright (C) 1998-2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "ext2_common.h" + +uint64_t td_ext2fs_blocks_count(const struct ext2_super_block *super) +{ + return le32(super->s_blocks_count) | + (EXT2_HAS_INCOMPAT_FEATURE(super, EXT4_FEATURE_INCOMPAT_64BIT) ? + (uint64_t) le32(super->s_blocks_count_hi) << 32 : 0); +} + +uint64_t td_ext2fs_free_blocks_count(const struct ext2_super_block *super) +{ + return le32(super->s_free_blocks_count) | + (EXT2_HAS_INCOMPAT_FEATURE(super, EXT4_FEATURE_INCOMPAT_64BIT) ? + (uint64_t) le32(super->s_free_blocks_hi) << 32 : 0); +} + +int test_EXT2(const struct ext2_super_block *sb, const partition_t *partition) +{ + const unsigned int s_errors=le16(sb->s_errors); + const uint64_t blocks_count=td_ext2fs_blocks_count(sb); + const uint32_t s_log_block_size=le32(sb->s_log_block_size); + /* There is a little offset ... */ + if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC) + return 1; + if (td_ext2fs_free_blocks_count(sb) > blocks_count) + return 2; + if (le32(sb->s_free_inodes_count) > le32(sb->s_inodes_count)) + return 3; + if (s_errors!=0 && + (s_errors != EXT2_ERRORS_CONTINUE) && + (s_errors != EXT2_ERRORS_RO) && + (s_errors != EXT2_ERRORS_PANIC)) + return 4; + if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0) + return 5; + if(blocks_count == 0) /* reject empty filesystem */ + return 6; + switch(s_log_block_size) + { + case 0: + case 1: + case 2: /* block size = 4096 (default) */ + case 3: /* can be 8192 on alpha */ + case 4: /* non standard blocksize */ + case 5: /* non standard blocksize */ + case 6: /* 64 KiB */ + break; + default: + return 7; + } + if(le32(sb->s_blocks_per_group)==0) + return 8; + if(partition==NULL) + return 0; + if(partition->part_size!=0 && + partition->part_size < blocks_count * + (EXT2_MIN_BLOCK_SIZE<s_log_block_size))) + return 8; + return 0; +} diff --git a/subprojects/lib/src/ext2_common.h b/subprojects/lib/src/ext2_common.h new file mode 100644 index 0000000..40c630a --- /dev/null +++ b/subprojects/lib/src/ext2_common.h @@ -0,0 +1,233 @@ +/* + + File: ext2_common.h + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef EXT2_COMMON_H +#define EXT2_COMMON_H +#ifdef __cplusplus +extern "C" { +#endif + +#define EXT2_SUPERBLOCK_SIZE 1024 + +#define EXT2_SB(sb) (sb) + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 + +#define EXT2_MIN_BLOCK (EXT2_MIN_BLOCK_SIZE/DEFAULT_SECTOR_SIZE) + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Feature set definitions + */ +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( le32(EXT2_SB(sb)->s_feature_compat) & (mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( le32(EXT2_SB(sb)->s_feature_ro_compat) & (mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( le32(EXT2_SB(sb)->s_feature_incompat) & (mask) ) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040 +#define EXT2_FEATURE_COMPAT_ANY 0xffffffff + + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +//#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +/* + * Structure of the super block + */ +struct ext2_super_block { + uint32_t s_inodes_count; /* Inodes count */ + uint32_t s_blocks_count; /* Blocks count */ + uint32_t s_r_blocks_count; /* Reserved blocks count */ + uint32_t s_free_blocks_count; /* Free blocks count */ + uint32_t s_free_inodes_count; /* Free inodes count */ + uint32_t s_first_data_block; /* First Data Block */ + uint32_t s_log_block_size; /* Block size */ + int32_t s_log_frag_size; /* Fragment size */ + uint32_t s_blocks_per_group; /* # Blocks per group */ + uint32_t s_frags_per_group; /* # Fragments per group */ + uint32_t s_inodes_per_group; /* # Inodes per group */ + uint32_t s_mtime; /* Mount time */ + uint32_t s_wtime; /* Write time */ + uint16_t s_mnt_count; /* Mount count */ + int16_t s_max_mnt_count; /* Maximal mount count */ + uint16_t s_magic; /* Magic signature */ + uint16_t s_state; /* File system state */ + uint16_t s_errors; /* Behaviour when detecting errors */ + uint16_t s_minor_rev_level; /* minor revision level */ + uint32_t s_lastcheck; /* time of last check */ + uint32_t s_checkinterval; /* max. time between checks */ + uint32_t s_creator_os; /* OS */ + uint32_t s_rev_level; /* Revision level */ + uint16_t s_def_resuid; /* Default uid for reserved blocks */ + uint16_t s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + uint32_t s_first_ino; /* First non-reserved inode */ + uint16_t s_inode_size; /* size of inode structure */ + uint16_t s_block_group_nr; /* block group # of this superblock */ + uint32_t s_feature_compat; /* compatible feature set */ + uint32_t s_feature_incompat; /* incompatible feature set */ + uint32_t s_feature_ro_compat; /* readonly-compatible feature set */ + uint8_t s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + uint32_t s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_COMPAT_PREALLOC flag is on. + */ + uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */ + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ + uint8_t s_journal_uuid[16]; /* uuid of journal superblock */ + uint32_t s_journal_inum; /* inode number of journal file */ + uint32_t s_journal_dev; /* device number of journal file */ + uint32_t s_last_orphan; /* start of list of inodes to delete */ + uint32_t s_hash_seed[4]; /* HTREE hash seed */ + uint8_t s_def_hash_version; /* Default hash version to use */ + uint8_t s_jnl_backup_type; /* Default type of journal backup */ + uint16_t s_desc_size; /* Group desc. size: INCOMPAT_64BIT */ + uint32_t s_default_mount_opts; + uint32_t s_first_meta_bg; /* First metablock group */ + uint32_t s_mkfs_time; /* When the filesystem was created */ + uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */ + uint32_t s_blocks_count_hi; /* Blocks count high 32bits */ + uint32_t s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/ + uint32_t s_free_blocks_hi; /* Free blocks count */ + uint16_t s_min_extra_isize; /* All inodes have at least # bytes */ + uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */ + uint32_t s_flags; /* Miscellaneous flags */ + uint16_t s_raid_stride; /* RAID stride */ + uint16_t s_mmp_update_interval; /* # seconds to wait in MMP checking */ + uint64_t s_mmp_block; /* Block for multi-mount protection */ + uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + uint8_t s_log_groups_per_flex; /* FLEX_BG group size */ + uint8_t s_reserved_char_pad; + uint16_t s_reserved_pad; /* Padding to next 32bits */ + uint64_t s_kbytes_written; /* nr of lifetime kilobytes written */ + uint32_t s_snapshot_inum; /* Inode number of active snapshot */ + uint32_t s_snapshot_id; /* sequential ID of active snapshot */ + uint64_t s_snapshot_r_blocks_count; /* reserved blocks for active + snapshot's future use */ + uint32_t s_snapshot_list; /* inode number of the head of the on-disk snapshot list */ + uint32_t s_error_count; /* number of fs errors */ + uint32_t s_first_error_time; /* first time an error happened */ + uint32_t s_first_error_ino; /* inode involved in first error */ + uint64_t s_first_error_block; /* block involved of first error */ + uint8_t s_first_error_func[32]; /* function where the error happened */ + uint32_t s_first_error_line; /* line number where error happened */ + uint32_t s_last_error_time; /* most recent time of an error */ + uint32_t s_last_error_ino; /* inode involved in last error */ + uint32_t s_last_error_line; /* line number where error happened */ + uint64_t s_last_error_block; /* block involved of last error */ + uint8_t s_last_error_func[32]; /* function where the error happened */ + uint8_t s_mount_opts[64]; + uint32_t s_usr_quota_inum; /* inode number of user quota file */ + uint32_t s_grp_quota_inum; /* inode number of group quota file */ + uint32_t s_overhead_blocks; /* overhead blocks/clusters in fs */ + uint32_t s_reserved[108]; /* Padding to the end of the block */ + uint32_t s_checksum; /* crc32c(superblock) */ +}; + +/*@ + @ requires \valid_read(super); + @ assigns \nothing; + @*/ +uint64_t td_ext2fs_blocks_count(const struct ext2_super_block *super); + +/*@ + @ requires \valid_read(super); + @ assigns \nothing; + @*/ +uint64_t td_ext2fs_free_blocks_count(const struct ext2_super_block *super); + +/*@ + @ requires \valid_read(sb); + @ requires \initialized(sb); + @ requires partition==\null || (\valid_read(partition) && valid_partition(partition)); + @ requires \separated(sb, partition); + @ assigns \nothing; + @ ensures \result == 7 ==> le32(sb->s_log_block_size) > 6; + @ ensures \result == 0 ==> le32(sb->s_log_block_size) <= 6; + @ */ +int test_EXT2(const struct ext2_super_block *sb, const partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2_dir.c b/subprojects/lib/src/ext2_dir.c new file mode 100644 index 0000000..efc19a3 --- /dev/null +++ b/subprojects/lib/src/ext2_dir.c @@ -0,0 +1,404 @@ +/* + + File: ext2_dir.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_LIBEXT2FS +#endif + +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#if defined(HAVE_LIBEXT2FS) +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include "ext2fs/ext2_fs.h" +#endif +#ifdef HAVE_EXT2FS_EXT2FS_H +#include "ext2fs/ext2fs.h" +#endif +#endif + +#include "types.h" +#include "common.h" +#include "intrf.h" +#include "dir.h" +#include "ext2_dir.h" +#include "ext2_inc.h" +#include "log.h" +#include "setdate.h" + +#if defined(HAVE_LIBEXT2FS) +#define DIRENT_DELETED_FILE 4 +/* + * list directory + */ + +#define LONG_OPT 0x0001 + +/* + * I/O Manager routine prototypes + */ +static errcode_t my_open(const char *dev, int flags, io_channel *channel); +static errcode_t my_close(io_channel channel); +static errcode_t my_set_blksize(io_channel channel, int blksize); +static errcode_t my_read_blk(io_channel channel, unsigned long block, int count, void *buf); +static errcode_t my_write_blk(io_channel channel, unsigned long block, int count, const void *buf); +static errcode_t my_flush(io_channel channel); +static errcode_t my_read_blk64(io_channel channel, unsigned long long block, int count, void *buf); +static errcode_t my_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf); + +static void dir_partition_ext2_close(dir_data_t *dir_data); +static int ext2_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file); + +static struct struct_io_manager my_struct_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name ="TestDisk I/O Manager", + .open = &my_open, + .close = &my_close, + .set_blksize = &my_set_blksize, + .read_blk = &my_read_blk, + .write_blk= &my_write_blk, + .flush = &my_flush, + .write_byte= NULL, +#ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_SET_OPTION + .set_option= NULL, +#endif +#ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_READ_BLK64 + .read_blk64=&my_read_blk64, +#endif +#ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_WRITE_BLK64 + .write_blk64=&my_write_blk64, +#endif +}; + +static io_channel shared_ioch=NULL; +/* + * Macro taken from unix_io.c + * For checking structure magic numbers... + */ + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +/* + * Allocate libext2fs structures associated with I/O manager + */ +static io_channel alloc_io_channel(const disk_t *disk_car,my_data_t *my_data) +{ + io_channel ioch; +#ifdef DEBUG_EXT2 + log_info("alloc_io_channel start\n"); +#endif + ioch = (io_channel)MALLOC(sizeof(struct struct_io_channel)); + if (ioch==NULL) + return NULL; + memset(ioch, 0, sizeof(struct struct_io_channel)); + ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL; + ioch->manager = &my_struct_manager; + ioch->name=strdup(my_data->partition->fsname); + if (ioch->name==NULL) { + free(ioch); + return NULL; + } + ioch->private_data = my_data; + ioch->block_size = 1024; /* The smallest ext2fs block size */ + ioch->read_error = 0; + ioch->write_error = 0; +#ifdef DEBUG_EXT2 + log_info("alloc_io_channel end\n"); +#endif + return ioch; +} + +static errcode_t my_open(const char *dev, int flags, io_channel *channel) +{ + *channel = shared_ioch; +#ifdef DEBUG_EXT2 + log_info("my_open %s done\n", dev); +#endif + return 0; +} + +static errcode_t my_close(io_channel channel) +{ + free(channel->private_data); + free(channel->name); + free(channel); +#ifdef DEBUG_EXT2 + log_info("my_close done\n"); +#endif + return 0; +} + +static errcode_t my_set_blksize(io_channel channel, int blksize) +{ + channel->block_size = blksize; +#ifdef DEBUG_EXT2 + log_info("my_set_blksize done\n"); +#endif + return 0; +} + +static errcode_t my_read_blk64(io_channel channel, unsigned long long block, int count, void *buf) +{ + ssize_t size; + const my_data_t *my_data=(const my_data_t*)channel->private_data; + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + size = (count < 0) ? -count : count * channel->block_size; +#ifdef DEBUG_EXT2 + log_info("my_read_blk start size=%lu, offset=%lu name=%s, block=%lu, count=%d, buf=%p\n", + (long unsigned)size, (unsigned long)(block*channel->block_size), + my_data->partition->fsname, block, count, buf); +#endif + if(my_data->disk_car->pread(my_data->disk_car, buf, size, my_data->partition->part_offset + (uint64_t)block * channel->block_size) != size) + return 1; +#ifdef DEBUG_EXT2 + log_info("my_read_blk done\n"); +#endif + return 0; +} + +static errcode_t my_read_blk(io_channel channel, unsigned long block, int count, void *buf) +{ + return my_read_blk64(channel, block, count, buf); +} + +static errcode_t my_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); +#if 1 + { + const my_data_t *my_data=(const my_data_t*)channel; + if(my_data->disk_car->pwrite(my_data->disk_car, buf, count * channel->block_size, my_data->partition->part_offset + (uint64_t)block * channel->block_size) != count * channel->block_size) + return 1; + return 0; + } +#else + return 1; +#endif +} + +static errcode_t my_write_blk(io_channel channel, unsigned long block, int count, const void *buf) +{ + return my_write_blk64(channel, block, count, buf); +} + +static errcode_t my_flush(io_channel channel) +{ + return 0; +} + +static int list_dir_proc2(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *privateinfo) +{ + struct ext2_inode inode; + ext2_ino_t ino; + const struct ext2_dir_struct *ls = (const struct ext2_dir_struct *) privateinfo; + file_info_t *new_file; + errcode_t retval; + if(entry==DIRENT_DELETED_FILE && (ls->dir_data->param & FLAG_LIST_DELETED)==0) + return 0; + ino = dirent->inode; + if(ino==0) + return 0; + if ((retval=ext2fs_read_inode(ls->current_fs,ino, &inode))!=0) + { + log_error("ext2fs_read_inode(ino=%u) failed with error %ld.\n",(unsigned)ino, (long)retval); + return 0; + } + if(inode.i_mode==0) + return 0; + new_file=(file_info_t *)MALLOC(sizeof(*new_file)); + { + const unsigned int thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ? + (dirent->name_len & 0xFF) : EXT2_NAME_LEN; + new_file->name=(char *)MALLOC(thislen+1); + memcpy(new_file->name, dirent->name, thislen); + new_file->name[thislen] = '\0'; + } + if(entry==DIRENT_DELETED_FILE) + new_file->status=FILE_STATUS_DELETED; + else + new_file->status=0; + new_file->st_ino=ino; + new_file->st_mode=inode.i_mode; +// new_file->st_nlink=inode.i_links_count; + new_file->st_uid=inode.i_uid; + new_file->st_gid=inode.i_gid; + new_file->st_size=LINUX_S_ISDIR(inode.i_mode)?inode.i_size: + inode.i_size| ((uint64_t)inode.i_size_high << 32); +// new_file->st_blksize=blocksize; +// new_file->st_blocks=inode.i_blocks; + new_file->td_atime=inode.i_atime; + new_file->td_mtime=inode.i_mtime; + new_file->td_ctime=inode.i_ctime; + td_list_add_tail(&new_file->list, &ls->dir_list->list); + return 0; +} + +static int ext2_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int cluster, file_info_t *dir_list) +{ + errcode_t retval; + struct ext2_dir_struct *ls=(struct ext2_dir_struct*)dir_data->private_dir_data; + ls->dir_list=dir_list; + if((retval=ext2fs_dir_iterate2(ls->current_fs, cluster, ls->flags, 0, list_dir_proc2, ls))!=0) + { + log_error("ext2fs_dir_iterate failed with error %ld.\n",(long)retval); + return -1; + } + return 0; +} + +static void dir_partition_ext2_close(dir_data_t *dir_data) +{ + struct ext2_dir_struct *ls=(struct ext2_dir_struct *)dir_data->private_dir_data; + ext2fs_close (ls->current_fs); + /* ext2fs_close call the close function that freed my_data */ + free(ls); +} + +static int ext2_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file) +{ + int error=0; + FILE *f_out; + const struct ext2_dir_struct *ls = (const struct ext2_dir_struct *)dir_data->private_dir_data; + char *new_file; + f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory); + if(!f_out) + { + log_critical("Can't create file %s: %s\n", new_file, strerror(errno)); + free(new_file); + return -4; + } + { + errcode_t retval; + struct ext2_inode inode; + char buffer[8192]; + ext2_file_t e2_file; + + if (ext2fs_read_inode(ls->current_fs, file->st_ino, &inode)!=0) + { + free(new_file); + fclose(f_out); + return -1; + } + + retval = ext2fs_file_open(ls->current_fs, file->st_ino, 0, &e2_file); + if (retval) { + log_error("Error while opening ext2 file %s\n", dir_data->current_directory); + free(new_file); + fclose(f_out); + return -2; + } + while (1) + { + int nbytes; + unsigned int got; + retval = ext2fs_file_read(e2_file, buffer, sizeof(buffer), &got); + if (retval) + { + log_error("Error while reading ext2 file %s\n", dir_data->current_directory); + error = -3; + } + if (got == 0) + break; + nbytes = fwrite(buffer, 1, got, f_out); + if ((unsigned) nbytes != got) + { + log_error("Error while writing file %s\n", new_file); + error = -5; + } + } + retval = ext2fs_file_close(e2_file); + if (retval) + { + log_error("Error while closing ext2 file\n"); + error = -6; + } + fclose(f_out); + set_date(new_file, file->td_atime, file->td_mtime); + (void)set_mode(new_file, file->st_mode); + } + free(new_file); + return error; +} +#endif + +dir_partition_t dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose) +{ +#if defined(HAVE_LIBEXT2FS) + struct ext2_dir_struct *ls=(struct ext2_dir_struct *)MALLOC(sizeof(*ls)); + io_channel ioch; + my_data_t *my_data; + ls->dir_list=NULL; + /* ls->flags = DIRENT_FLAG_INCLUDE_EMPTY; */ + ls->flags = DIRENT_FLAG_INCLUDE_REMOVED; + ls->dir_data=dir_data; + my_data=(my_data_t *)MALLOC(sizeof(*my_data)); + my_data->partition=partition; + my_data->disk_car=disk_car; + ioch=alloc_io_channel(disk_car,my_data); + shared_ioch=ioch; + /* An alternate superblock may be used if the calling function has set an IO redirection */ + if(ext2fs_open ("/dev/testdisk", 0, 0, 0, &my_struct_manager, &ls->current_fs)!=0) + { +// free(my_data); + free(ls); + return DIR_PART_EIO; + } + strncpy(dir_data->current_directory,"/",sizeof(dir_data->current_directory)); + dir_data->current_inode=EXT2_ROOT_INO; + dir_data->param=FLAG_LIST_DELETED; + dir_data->verbose=verbose; + dir_data->capabilities=CAPA_LIST_DELETED; + dir_data->get_dir=&ext2_dir; + dir_data->copy_file=&ext2_copy; + dir_data->close=&dir_partition_ext2_close; + dir_data->local_dir=NULL; + dir_data->private_dir_data=ls; + return DIR_PART_OK; +#else + return DIR_PART_ENOSYS; +#endif +} + +const char*td_ext2fs_version(void) +{ + const char *ext2fs_version="none"; +#if defined(HAVE_LIBEXT2FS) + ext2fs_get_library_version(&ext2fs_version,NULL); +#endif + return ext2fs_version; +} diff --git a/subprojects/lib/src/ext2_dir.h b/subprojects/lib/src/ext2_dir.h new file mode 100644 index 0000000..5dbb8d5 --- /dev/null +++ b/subprojects/lib/src/ext2_dir.h @@ -0,0 +1,41 @@ +/* + + File: ext2_dir.h + + Copyright (C) 1998-2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXT2_DIR_H +#define _EXT2_DIR_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @*/ +dir_partition_t dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose); + +/*@ assigns \nothing; */ +const char*td_ext2fs_version(void); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2_inc.h b/subprojects/lib/src/ext2_inc.h new file mode 100644 index 0000000..d1cb086 --- /dev/null +++ b/subprojects/lib/src/ext2_inc.h @@ -0,0 +1,45 @@ +/* + + File: ext2_inc.h + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXT2_INC_H +#define _EXT2_INC_H + +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_LIBEXT2FS +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(HAVE_LIBEXT2FS) +struct ext2_dir_struct { + file_info_t *dir_list; + ext2_filsys current_fs; + int flags; + dir_data_t *dir_data; +}; +#endif + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2grp.c b/subprojects/lib/src/ext2grp.c new file mode 100644 index 0000000..8cdfb52 --- /dev/null +++ b/subprojects/lib/src/ext2grp.c @@ -0,0 +1,112 @@ +/* + + File: ext2grp.c + + Copyright (C) 2008-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "types.h" +#include "common.h" +#include "list.h" +#include "filegen.h" +#include "dir.h" +#include "ext2grp.h" +#include "ext2_common.h" +#include "log.h" +#include "photorec.h" + +unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, const partition_t *partition) +{ + struct td_list_head *search_walker = NULL; + unsigned char *buffer; + unsigned int blocksize; + if(partition->upart_type!=UP_EXT2 && + partition->upart_type!=UP_EXT3 && + partition->upart_type!=UP_EXT4) + { + log_error("Not a valid ext2/ext3/ext4 filesystem"); + free_search_space(list_search_space); + return 0; + } + + buffer=(unsigned char*)MALLOC(EXT2_SUPERBLOCK_SIZE); + if(disk->pread(disk, buffer, EXT2_SUPERBLOCK_SIZE, partition->part_offset + 0x400) != EXT2_SUPERBLOCK_SIZE) + { + free(buffer); + return 0; + } + { + const struct ext2_super_block *sb=(const struct ext2_super_block *)buffer; + const unsigned int mult=(unsigned int)le32(sb->s_blocks_per_group) * (EXT2_MIN_BLOCK_SIZE<s_log_block_size)); + td_list_for_each(search_walker, &list_search_space->list) + { + alloc_data_t *current_search_space; + current_search_space=td_list_entry(search_walker, alloc_data_t, list); + log_info("ext2_group: %llu\n", (long long unsigned)current_search_space->start); + current_search_space->start=current_search_space->start*mult + (le32(sb->s_log_block_size)==0?1024:0); + current_search_space->end=current_search_space->end*mult+mult-1 + (le32(sb->s_log_block_size)==0?1024:0); + } + blocksize=EXT2_MIN_BLOCK_SIZE<s_log_block_size); + } + free(buffer); + return blocksize; +} + +unsigned int ext2_fix_inode(alloc_data_t *list_search_space, disk_t *disk, const partition_t *partition) +{ + struct td_list_head *search_walker = NULL; + unsigned char *buffer; + unsigned int blocksize; + if(partition->upart_type!=UP_EXT2 && + partition->upart_type!=UP_EXT3 && + partition->upart_type!=UP_EXT4) + { + log_error("Not a valid ext2/ext3/ext4 filesystem"); + free_search_space(list_search_space); + return 0; + } + + buffer=(unsigned char*)MALLOC(EXT2_SUPERBLOCK_SIZE); + if(disk->pread(disk, buffer, EXT2_SUPERBLOCK_SIZE, partition->part_offset + 0x400) != EXT2_SUPERBLOCK_SIZE) + { + free(buffer); + return 0; + } + { + const struct ext2_super_block *sb=(const struct ext2_super_block *)buffer; + const unsigned int divd=(unsigned int)le32(sb->s_inodes_per_group); + const unsigned int mult=(unsigned int)le32(sb->s_blocks_per_group) * (EXT2_MIN_BLOCK_SIZE<s_log_block_size)); + td_list_for_each(search_walker, &list_search_space->list) + { + alloc_data_t *current_search_space; + current_search_space=td_list_entry(search_walker, alloc_data_t, list); + log_info("ext2_inode: %llu\n", (long long unsigned)current_search_space->start); + current_search_space->start=current_search_space->start/divd*mult + (sb->s_log_block_size==0?1024:0); + current_search_space->end=current_search_space->end/divd*mult+mult-1 + (sb->s_log_block_size==0?1024:0); + } + blocksize=EXT2_MIN_BLOCK_SIZE<s_log_block_size); + } + free(buffer); + return blocksize; +} diff --git a/subprojects/lib/src/ext2grp.h b/subprojects/lib/src/ext2grp.h new file mode 100644 index 0000000..231db84 --- /dev/null +++ b/subprojects/lib/src/ext2grp.h @@ -0,0 +1,57 @@ +/* + + File: ext2grp.h + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXT2GRP_H +#define _EXT2GRP_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires valid_disk(disk); + @ requires valid_partition(partition); + @ requires \valid(disk); + @ requires \valid_read(partition); + @ requires \separated(list_search_space, disk, partition); + @ ensures valid_disk(disk); + @*/ +// ensures valid_list_search_space(list_search_space); +// ensures valid_partition(partition); +unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, const partition_t *partition); + +/*@ + @ requires valid_list_search_space(list_search_space); + @ requires valid_disk(disk); + @ requires valid_partition(partition); + @ requires \valid(disk); + @ requires \valid_read(partition); + @ requires \separated(list_search_space, disk, partition); + @ ensures valid_disk(disk); + @*/ +// ensures valid_list_search_space(list_search_space); +// ensures valid_partition(partition); +unsigned int ext2_fix_inode(alloc_data_t *list_search_space, disk_t *disk, const partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/ext2p.c b/subprojects/lib/src/ext2p.c new file mode 100644 index 0000000..2e57e43 --- /dev/null +++ b/subprojects/lib/src/ext2p.c @@ -0,0 +1,126 @@ +/* + + File: ext2p.c + + Copyright (C) 2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) || defined(MAIN_photorec) +#undef HAVE_LIBEXT2FS +#endif + +#if defined(HAVE_LIBEXT2FS) +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "list.h" +#include "filegen.h" +#include "photorec.h" +#include "intrf.h" +#include "dir.h" +#ifdef HAVE_EXT2FS_EXT2_FS_H +#include "ext2fs/ext2_fs.h" +#endif +#ifdef HAVE_EXT2FS_EXT2FS_H +#include "ext2fs/ext2fs.h" +#endif +#include "ext2p.h" +#include "ext2_inc.h" +#include "ext2_dir.h" +#include "log.h" +#include "log_part.h" + +unsigned int ext2_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space) +{ + dir_data_t dir_data; + switch(dir_partition_ext2_init(disk, partition, &dir_data, 0)) + { + case DIR_PART_ENOIMP: + case DIR_PART_ENOSYS: + return 0; + case DIR_PART_EIO: + log_partition(disk, partition); + log_error("Can't open filesystem. Filesystem seems damaged.\n"); + return 0; + case DIR_PART_OK: + break; + } + { + const unsigned int sizeof_buffer=512; + struct ext2_dir_struct *ls=(struct ext2_dir_struct *)dir_data.private_dir_data; + unsigned char *buffer; + uint64_t start_free=0; + uint64_t end_free=0; + unsigned long int block; + unsigned long int start,end; + const unsigned int blocksize=ls->current_fs->blocksize; + ext2fs_block_bitmap bitmap; + if(ext2fs_read_block_bitmap(ls->current_fs)) + { + log_error("ext2fs_read_block_bitmap failed\n"); + return 0; + } + bitmap=ls->current_fs->block_map; + if(bitmap==NULL) + return 0; +#ifdef HAVE_EXT2FS_GET_GENERIC_BITMAP_START + start=ext2fs_get_generic_bitmap_start(bitmap); + end=ext2fs_get_generic_bitmap_end(bitmap); +#else + start=bitmap->start; + end=bitmap->end; +#endif + log_trace("ext2_remove_used_space %lu-%lu\n", start, end); + buffer=(unsigned char *)MALLOC(sizeof_buffer); + for(block=start;block<=end;block++) + { +#ifdef HAVE_EXT2FS_GET_GENERIC_BITMAP_START + if(ext2fs_test_generic_bitmap(bitmap,block)!=0) +#else + if(ext2fs_test_bit(block - bitmap->start, bitmap->bitmap)!=0) +#endif + { + /* Not free */ + if(end_free+1==partition->part_offset+(uint64_t)block*blocksize) + end_free+=blocksize; + else + { + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); + start_free=partition->part_offset+(uint64_t)block*blocksize; + end_free=start_free+(uint64_t)blocksize-1; + } + } + } + free(buffer); + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); + dir_data.close(&dir_data); + return blocksize; + } +} +#endif diff --git a/subprojects/lib/src/ext2p.h b/subprojects/lib/src/ext2p.h new file mode 100644 index 0000000..1dc8fbc --- /dev/null +++ b/subprojects/lib/src/ext2p.h @@ -0,0 +1,43 @@ +/* + + File: ext2p.h + + Copyright (C) 2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _EXT2P_H +#define _EXT2P_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_LIBEXT2FS +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(disk, partition, list_search_space); + @ ensures valid_list_search_space(list_search_space); + @*/ +unsigned int ext2_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space); +#endif + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/f2fs.c b/subprojects/lib/src/f2fs.c new file mode 100644 index 0000000..f4c7822 --- /dev/null +++ b/subprojects/lib/src/f2fs.c @@ -0,0 +1,101 @@ +/* + + File: f2fs.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "f2fs_fs.h" +#include "f2fs.h" +#include "log.h" + +extern const arch_fnct_t arch_none; + +static void set_f2fs_info(partition_t *partition, const struct f2fs_super_block*hdr) +{ + partition->upart_type=UP_F2FS; + partition->blocksize=1<log_blocksize); + partition->fsname[0]='\0'; + if(partition->sb_offset==0) + snprintf(partition->info, sizeof(partition->info), "F2FS, blocksize=%u", partition->blocksize); + else + snprintf(partition->info, sizeof(partition->info), "F2FS found using backup sector, blocksize=%u", partition->blocksize); +} + +int check_f2fs(disk_t *disk, partition_t *partition) +{ + unsigned char *buffer=(unsigned char*)MALLOC(F2FS_BLKSIZE); + if(disk->pread(disk, buffer, F2FS_BLKSIZE, partition->part_offset + F2FS_SUPER_OFFSET) != F2FS_BLKSIZE) + { + free(buffer); + return 1; + } + if(test_f2fs((struct f2fs_super_block*)buffer)!=0) + { + free(buffer); + return 1; + } + set_f2fs_info(partition, (struct f2fs_super_block*)buffer); + free(buffer); + return 0; +} + +int test_f2fs(const struct f2fs_super_block *hdr) +{ + if(le32(hdr->magic) != F2FS_SUPER_MAGIC) + return 1; + /* Currently, support 512/1024/2048/4096 bytes sector size */ + if(le32(hdr->log_sectorsize) < 9 || le32(hdr->log_sectorsize) > 12) + return 1; + /* Currently, support only 4KB block size */ + if(le32(hdr->log_blocksize) != F2FS_BLKSIZE_BITS) + return 1; + if(le32(hdr->log_sectorsize) + le32(hdr->log_sectors_per_block) != le32(hdr->log_blocksize)) + return 1; + /* check log blocks per segment */ + if(le32(hdr->log_blocks_per_seg) != 9) + return 1; + if(le64(hdr->block_count) == 0) + return 1; + return 0; +} + +int recover_f2fs(const disk_t *disk, const struct f2fs_super_block *hdr, partition_t *partition) +{ + if(test_f2fs(hdr)!=0) + return 1; + partition->sborg_offset=0; + partition->sb_size=F2FS_BLKSIZE; + partition->part_type_i386=P_LINUX; + partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA; + partition->part_size=(uint64_t)le64(hdr->block_count) << le32(hdr->log_blocksize); + set_f2fs_info(partition, hdr); + return 0; +} diff --git a/subprojects/lib/src/f2fs.h b/subprojects/lib/src/f2fs.h new file mode 100644 index 0000000..46949bf --- /dev/null +++ b/subprojects/lib/src/f2fs.h @@ -0,0 +1,53 @@ +/* + + File: f2fs.h + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _F2FS_H +#define _F2FS_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires \separated(disk, partition); + @*/ +int check_f2fs(disk_t *disk, partition_t *partition); + +/*@ + @ requires \valid_read(hdr); + @*/ +int test_f2fs(const struct f2fs_super_block *hdr); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(hdr); + @ requires \valid(partition); + @ requires \separated(disk, hdr, partition); + @*/ +int recover_f2fs(const disk_t *disk, const struct f2fs_super_block *hdr, partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/f2fs_fs.h b/subprojects/lib/src/f2fs_fs.h new file mode 100644 index 0000000..07d0a89 --- /dev/null +++ b/subprojects/lib/src/f2fs_fs.h @@ -0,0 +1,107 @@ +/* + File: f2fs_fs.h + + Copyright (C) 2018 Christophe GRENIER + + Superblock information from Samsung Electronics Co., Ltd. http://www.samsung.com/ + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*/ +#ifndef F2FS_FS_H +#define F2FS_FS_H + +#define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */ + +#define F2FS_SUPER_OFFSET 1024 /* byte-size offset */ +#define F2FS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */ +#define F2FS_MAX_LOG_SECTOR_SIZE 12 /* 12 bits for 4096 bytes */ +#define F2FS_LOG_SECTORS_PER_BLOCK 3 /* log number for sector/blk */ +#define F2FS_BLKSIZE 4096 /* support only 4KB block */ +#define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ +#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ +#define F2FS_EXTENSION_LEN 8 /* max size of extension */ +#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS) + +/* + * For further optimization on multi-head logs, on-disk layout supports maximum + * 16 logs by default. The number, 16, is expected to cover all the cases + * enoughly. The implementaion currently uses no more than 6 logs. + * Half the logs are used for nodes, and the other half are used for data. + */ +#define MAX_ACTIVE_LOGS 16 +#define MAX_ACTIVE_NODE_LOGS 8 +#define MAX_ACTIVE_DATA_LOGS 8 + +#define VERSION_LEN 256 +#define MAX_VOLUME_NAME 512 +#define MAX_PATH_LEN 64 +#define MAX_DEVICES 8 + +#define F2FS_MAX_QUOTAS 3 + +/* + * For superblock + */ +struct f2fs_device { + uint8_t path[MAX_PATH_LEN]; + uint32_t total_segments; +} __attribute__ ((gcc_struct, __packed__)); + +struct f2fs_super_block { + uint32_t magic; /* Magic Number */ + uint16_t major_ver; /* Major Version */ + uint16_t minor_ver; /* Minor Version */ + uint32_t log_sectorsize; /* log2 sector size in bytes */ + uint32_t log_sectors_per_block; /* log2 # of sectors per block */ + uint32_t log_blocksize; /* log2 block size in bytes */ + uint32_t log_blocks_per_seg; /* log2 # of blocks per segment */ + uint32_t segs_per_sec; /* # of segments per section */ + uint32_t secs_per_zone; /* # of sections per zone */ + uint32_t checksum_offset; /* checksum offset inside super block */ + uint64_t block_count; /* total # of user blocks */ + uint32_t section_count; /* total # of sections */ + uint32_t segment_count; /* total # of segments */ + uint32_t segment_count_ckpt; /* # of segments for checkpoint */ + uint32_t segment_count_sit; /* # of segments for SIT */ + uint32_t segment_count_nat; /* # of segments for NAT */ + uint32_t segment_count_ssa; /* # of segments for SSA */ + uint32_t segment_count_main; /* # of segments for main area */ + uint32_t segment0_blkaddr; /* start block address of segment 0 */ + uint32_t cp_blkaddr; /* start block address of checkpoint */ + uint32_t sit_blkaddr; /* start block address of SIT */ + uint32_t nat_blkaddr; /* start block address of NAT */ + uint32_t ssa_blkaddr; /* start block address of SSA */ + uint32_t main_blkaddr; /* start block address of main area */ + uint32_t root_ino; /* root inode number */ + uint32_t node_ino; /* node inode number */ + uint32_t meta_ino; /* meta inode number */ + uint8_t uuid[16]; /* 128-bit uuid for volume */ + uint16_t volume_name[MAX_VOLUME_NAME]; /* volume name */ + uint32_t extension_count; /* # of extensions below */ + uint8_t extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */ + uint32_t cp_payload; + uint8_t version[VERSION_LEN]; /* the kernel version */ + uint8_t init_version[VERSION_LEN]; /* the initial kernel version */ + uint32_t feature; /* defined features */ + uint8_t encryption_level; /* versioning level for encryption */ + uint8_t encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ + struct f2fs_device devs[MAX_DEVICES]; /* device list */ + uint32_t qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ + uint8_t hot_ext_count; /* # of hot file extension */ + uint8_t reserved[314]; /* valid reserved region */ +} __attribute__ ((gcc_struct, __packed__)); + +#endif /* F2FS_FS_H */ diff --git a/subprojects/lib/src/fat.c b/subprojects/lib/src/fat.c new file mode 100644 index 0000000..3b30885 --- /dev/null +++ b/subprojects/lib/src/fat.c @@ -0,0 +1,1191 @@ +/* + + File: fat.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include "types.h" +#include "common.h" +#include "fat.h" +#include "lang.h" +#include "fnctdsk.h" +#include "intrf.h" +#include "log.h" +#include "log_part.h" +#include "dir.h" +#include "fat_dir.h" + +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) +extern const arch_fnct_t arch_i386; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) +extern const arch_fnct_t arch_mac; +#endif + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +static int is_fat12(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +static int is_fat16(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +static int is_fat32(const partition_t *partition); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires \valid_read(fat_header); + @ requires \separated(disk_car, partition, fat_header); + @*/ +static int fat32_set_part_name(disk_t *disk_car, partition_t *partition, const struct fat_boot_sector*fat_header) +{ + partition->fsname[0]='\0'; + if((fat_header->sectors_per_cluster>0)&&(fat_header->sectors_per_cluster<=128)) + { + const unsigned int cluster_size=fat_header->sectors_per_cluster*disk_car->sector_size; + unsigned char *buffer=(unsigned char*)MALLOC(cluster_size); + if((unsigned)disk_car->pread(disk_car, buffer, cluster_size, + partition->part_offset + (le16(fat_header->reserved) + fat_header->fats * le32(fat_header->fat32_length) + (uint64_t)(le32(fat_header->root_cluster) - 2) * fat_header->sectors_per_cluster) * disk_car->sector_size) != cluster_size) + { + log_error("fat32_set_part_name() cannot read FAT32 root cluster.\n"); + } + else + { + int i; + int stop=0; + for(i=0;(i<16*fat_header->sectors_per_cluster)&&(stop==0);i++) + { /* Test attribut volume name and check if the volume name is erased or not */ + if(((buffer[i*0x20+0xB] & ATTR_EXT) !=ATTR_EXT) && ((buffer[i*0x20+0xB] & ATTR_VOLUME) !=0) && (buffer[i*0x20]!=0xE5)) + { + set_part_name_chomp(partition,&buffer[i*0x20],11); + if(check_VFAT_volume_name(partition->fsname, 11)) + partition->fsname[0]='\0'; + } + if(buffer[i*0x20]==0) + { + stop=1; + } + } + } + free(buffer); + } + if(partition->fsname[0]=='\0') + { + log_info("set_FAT_info: name from BS used\n"); + set_part_name_chomp(partition,((const unsigned char*)fat_header)+FAT32_PART_NAME,11); + if(check_VFAT_volume_name(partition->fsname, 11)) + partition->fsname[0]='\0'; + } + return 0; +} + +/*@ + @ requires \valid(disk_car); + @ requires \valid_read(fat_header); + @ requires \valid(partition); + @ requires \separated(disk_car, fat_header, partition); + @*/ +static void set_FAT_info(disk_t *disk_car, const struct fat_boot_sector *fat_header, partition_t *partition) +{ + uint64_t start_fat1; + uint64_t start_data; + uint64_t part_size; + unsigned long int no_of_cluster; + unsigned long int fat_length; + const char *buffer=(const char*)fat_header; + partition->fsname[0]='\0'; + partition->blocksize=fat_sector_size(fat_header)* fat_header->sectors_per_cluster; + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+fat_sector_size(fat_header)-1)/fat_sector_size(fat_header); + no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster; + if(no_of_cluster<4085) + { + partition->upart_type=UP_FAT12; + snprintf(partition->info, sizeof(partition->info), "FAT12, blocksize=%u", partition->blocksize); + if(buffer[38]==0x29) /* BS_BootSig */ + { + set_part_name_chomp(partition,((const unsigned char*)fat_header)+FAT1X_PART_NAME,11); + if(check_VFAT_volume_name(partition->fsname, 11)) + partition->fsname[0]='\0'; + } + } + else if(no_of_cluster<65525) + { + partition->upart_type=UP_FAT16; + snprintf(partition->info, sizeof(partition->info), "FAT16, blocksize=%u", partition->blocksize); + if(buffer[38]==0x29) /* BS_BootSig */ + { + set_part_name_chomp(partition,((const unsigned char*)fat_header)+FAT1X_PART_NAME,11); + if(check_VFAT_volume_name(partition->fsname, 11)) + partition->fsname[0]='\0'; + } + } + else + { + partition->upart_type=UP_FAT32; + if(partition->sb_offset==0) + snprintf(partition->info, sizeof(partition->info), "FAT32, blocksize=%u", partition->blocksize); + else + snprintf(partition->info, sizeof(partition->info), "FAT32 found using backup sector, blocksize=%u", partition->blocksize); + fat32_set_part_name(disk_car,partition,fat_header); + } +} + +/*@ + @ requires \valid_read(fh1); + @*/ +static int log_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size) +{ + log_info("sector_size %u\n", fat_sector_size(fh1)); + log_info("cluster_size %u\n", fh1->sectors_per_cluster); + log_info("reserved %u\n", le16(fh1->reserved)); + log_info("fats %u\n", fh1->fats); + log_info("dir_entries %u\n", get_dir_entries(fh1)); + log_info("sectors %u\n", fat_sectors(fh1)); + log_info("media %02X\n", fh1->media); + log_info("fat_length %u\n", le16(fh1->fat_length)); + log_info("secs_track %u\n", le16(fh1->secs_track)); + log_info("heads %u\n", le16(fh1->heads)); + log_info("hidden %u\n", (unsigned int)le32(fh1->hidden)); + log_info("total_sect %u\n", (unsigned int)le32(fh1->total_sect)); + if(upart_type==UP_FAT32) + { + log_info("fat32_length %u\n", (unsigned int)le32(fh1->fat32_length)); + log_info("flags %04X\n", le16(fh1->flags)); + log_info("version %u.%u\n", fh1->version[0], fh1->version[1]); + log_info("root_cluster %u\n", (unsigned int)le32(fh1->root_cluster)); + log_info("info_sector %u\n", le16(fh1->info_sector)); + log_info("backup_boot %u\n", le16(fh1->backup_boot)); + if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF) + log_info("free_count uninitialised\n"); + else + log_info("free_count %lu\n",fat32_get_free_count((const unsigned char*)fh1,sector_size)); + if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF) + log_info("next_free uninitialised\n"); + else + log_info("next_free %lu\n",fat32_get_next_free((const unsigned char*)fh1,sector_size)); + } + return 0; +} + +int log_fat2_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size) +{ + switch(upart_type) + { + case UP_FAT12: + log_info("\nFAT12\n"); + break; + case UP_FAT16: + log_info("\nFAT16\n"); + break; + case UP_FAT32: + log_info("\nFAT32\n"); + break; + default: + return 1; + } + log_info("sector_size %u %u\n", fat_sector_size(fh1),fat_sector_size(fh2)); + log_info("cluster_size %u %u\n", fh1->sectors_per_cluster,fh2->sectors_per_cluster); + log_info("reserved %u %u\n", le16(fh1->reserved),le16(fh2->reserved)); + log_info("fats %u %u\n", fh1->fats,fh2->fats); + log_info("dir_entries %u %u\n", get_dir_entries(fh1),get_dir_entries(fh2)); + log_info("sectors %u %u\n", fat_sectors(fh1),fat_sectors(fh2)); + log_info("media %02X %02X\n", fh1->media,fh2->media); + log_info("fat_length %u %u\n", le16(fh1->fat_length),le16(fh2->fat_length)); + log_info("secs_track %u %u\n", le16(fh1->secs_track),le16(fh2->secs_track)); + log_info("heads %u %u\n", le16(fh1->heads),le16(fh2->heads)); + log_info("hidden %u %u\n", (unsigned int)le32(fh1->hidden),(unsigned int)le32(fh2->hidden)); + log_info("total_sect %u %u\n", (unsigned int)le32(fh1->total_sect),(unsigned int)le32(fh2->total_sect)); + if(upart_type==UP_FAT32) + { + log_info("fat32_length %u %u\n", (unsigned int)le32(fh1->fat32_length),(unsigned int)le32(fh2->fat32_length)); + log_info("flags %04X %04X\n", le16(fh1->flags),le16(fh2->flags)); + log_info("version %u.%u %u.%u\n", fh1->version[0], fh1->version[1],fh2->version[0], fh2->version[1]); + log_info("root_cluster %u %u\n", (unsigned int)le32(fh1->root_cluster),(unsigned int)le32(fh2->root_cluster)); + log_info("info_sector %u %u\n", le16(fh1->info_sector),le16(fh2->info_sector)); + log_info("backup_boot %u %u\n", le16(fh1->backup_boot),le16(fh2->backup_boot)); + log_info("free_count "); + if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF) + log_info("uninitialised "); + else + log_info("%lu ",fat32_get_free_count((const unsigned char*)fh1,sector_size)); + if(fat32_get_free_count((const unsigned char*)fh2,sector_size)==0xFFFFFFFF) + log_info("uninitialised"); + else + log_info("%lu",fat32_get_free_count((const unsigned char*)fh2,sector_size)); + log_info("\nnext_free "); + if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF) + log_info("uninitialised "); + else + log_info("%lu ",fat32_get_next_free((const unsigned char*)fh1,sector_size)); + if(fat32_get_next_free((const unsigned char*)fh2,sector_size)==0xFFFFFFFF) + log_info("uninitialised\n"); + else + log_info("%lu\n",fat32_get_next_free((const unsigned char*)fh2,sector_size)); + } + return 0; +} + +int check_FAT(disk_t *disk_car, partition_t *partition, const int verbose) +{ + unsigned char *buffer; + buffer=(unsigned char *)MALLOC(3*disk_car->sector_size); + if((unsigned)disk_car->pread(disk_car, buffer, 3 * disk_car->sector_size, partition->part_offset) != 3 * disk_car->sector_size) + { + screen_buffer_add("check_FAT: can't read FAT boot sector\n"); + log_error("check_FAT: can't read FAT boot sector\n"); + free(buffer); + return 1; + } + if(test_FAT(disk_car,(const struct fat_boot_sector *)buffer,partition,verbose,0)!=0) + { + if(verbose>0) + { + log_error("\n\ntest_FAT()\n"); + log_partition(disk_car,partition); + log_fat_info((const struct fat_boot_sector*)buffer, partition->upart_type,disk_car->sector_size); + } + free(buffer); + return 1; + } + set_FAT_info(disk_car,(const struct fat_boot_sector *)buffer,partition); + /* screen_buffer_add("Ok\n"); */ + free(buffer); + return 0; +} + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, partition); + @*/ +static unsigned int get_next_cluster_fat12(disk_t *disk, const partition_t *partition, const int offset, const unsigned int cluster) +{ + unsigned int next_cluster; + unsigned long int offset_s; + unsigned long int offset_o; + unsigned char *buffer=(unsigned char*)MALLOC(2*disk->sector_size); + offset_s=(cluster+cluster/2)/disk->sector_size; + offset_o=(cluster+cluster/2)%disk->sector_size; + if((unsigned)disk->pread(disk, buffer, 2 * disk->sector_size, + partition->part_offset + (uint64_t)(offset + offset_s) * disk->sector_size) != 2 * disk->sector_size) + { + log_error("get_next_cluster_fat12 read error\n"); + free(buffer); + return 0; + } + if((cluster&1)!=0) + next_cluster=le16((*((uint16_t*)&buffer[offset_o])))>>4; + else + next_cluster=le16(*((uint16_t*)&buffer[offset_o]))&0x0FFF; + free(buffer); + return next_cluster; +} + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, partition); + @*/ +static unsigned int get_next_cluster_fat16(disk_t *disk, const partition_t *partition, const int offset, const unsigned int cluster) +{ + unsigned int next_cluster; + unsigned long int offset_s; + unsigned long int offset_o; + unsigned char *buffer=(unsigned char*)MALLOC(disk->sector_size); + const uint16_t *p16=(const uint16_t*)buffer; + offset_s=cluster/(disk->sector_size/2); + offset_o=cluster%(disk->sector_size/2); + if((unsigned)disk->pread(disk, buffer, disk->sector_size, + partition->part_offset + (uint64_t)(offset + offset_s) * disk->sector_size) != disk->sector_size) + { + log_error("get_next_cluster_fat16 read error\n"); + free(buffer); + return 0; + } + next_cluster=le16(p16[offset_o]); + free(buffer); + return next_cluster; +} + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, partition); + @*/ +static unsigned int get_next_cluster_fat32(disk_t *disk, const partition_t *partition, const int offset, const unsigned int cluster) +{ + unsigned int next_cluster; + unsigned long int offset_s; + unsigned long int offset_o; + unsigned char *buffer=(unsigned char*)MALLOC(disk->sector_size); + const uint32_t *p32=(const uint32_t*)buffer; + offset_s=cluster/(disk->sector_size/4); + offset_o=cluster%(disk->sector_size/4); + if((unsigned)disk->pread(disk, buffer, disk->sector_size, + partition->part_offset + (uint64_t)(offset + offset_s) * disk->sector_size) != disk->sector_size) + { + log_error("get_next_cluster_fat32 read error\n"); + free(buffer); + return 0; + } + /* FAT32 used 28 bits, the 4 high bits are reserved + * 0x00000000: free cluster + * 0x0FFFFFF7: bad cluster + * 0x0FFFFFF8+: EOC End of cluster + * */ + next_cluster=le32(p32[offset_o])&0xFFFFFFF; + free(buffer); + return next_cluster; +} + +unsigned int get_next_cluster(disk_t *disk,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster) +{ + /* Offset can be offset to FAT1 or to FAT2 */ + switch(upart_type) + { + case UP_FAT12: + return get_next_cluster_fat12(disk, partition, offset, cluster); + case UP_FAT16: + return get_next_cluster_fat16(disk, partition, offset, cluster); + case UP_FAT32: + return get_next_cluster_fat32(disk, partition, offset, cluster); + default: + log_critical("fat.c get_next_cluster unknown fat type\n"); + return 0; + } +} + +int set_next_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster, const unsigned int next_cluster) +{ + unsigned char *buffer; + unsigned long int offset_s,offset_o; + const unsigned int buffer_size=(upart_type==UP_FAT12?2*disk_car->sector_size:disk_car->sector_size); + buffer=(unsigned char*)MALLOC(buffer_size); + /* Offset can be offset to FAT1 or to FAT2 */ + /* log_trace("set_next_cluster(upart_type=%u,offset=%u,cluster=%u,next_cluster=%u)\n",upart_type,offset,cluster,next_cluster); */ + switch(upart_type) + { + case UP_FAT12: + offset_s=(cluster+cluster/2)/disk_car->sector_size; + offset_o=(cluster+cluster/2)%disk_car->sector_size; + break; + case UP_FAT16: + offset_s=cluster/(disk_car->sector_size/2); + offset_o=cluster%(disk_car->sector_size/2); + break; + case UP_FAT32: + offset_s=cluster/(disk_car->sector_size/4); + offset_o=cluster%(disk_car->sector_size/4); + break; + default: + log_critical("fat.c set_next_cluster unknown fat type\n"); + free(buffer); + return 1; + } + if((unsigned)disk_car->pread(disk_car, buffer, buffer_size, + partition->part_offset + (uint64_t)(offset + offset_s) * disk_car->sector_size) != buffer_size) + { + log_error("set_next_cluster read error\n"); + free(buffer); + return 1; + } + switch(upart_type) + { + case UP_FAT12: + if((cluster&1)!=0) + (*((uint16_t*)&buffer[offset_o]))=le16((next_cluster<<4) | (le16(*((uint16_t*)&buffer[offset_o]))&0xF)); + else + (*((uint16_t*)&buffer[offset_o]))=le16((next_cluster) | (le16(*((uint16_t*)&buffer[offset_o]))&0xF000)); + break; + case UP_FAT16: + { + uint16_t *p16=(uint16_t*)buffer; + p16[offset_o]=le16(next_cluster); + } + break; + case UP_FAT32: + { + uint32_t *p32=(uint32_t*)buffer; + /* FAT32 used 28 bits, the 4 high bits are reserved + * 0x00000000: free cluster + * 0x0FFFFFF7: bad cluster + * 0x0FFFFFF8+: EOC End of cluster + * */ + p32[offset_o]=le32(next_cluster); + } + break; + default: /* Avoid compiler warning */ + break; + } + if((unsigned)disk_car->pwrite(disk_car, buffer, buffer_size, partition->part_offset + (uint64_t)(offset + offset_s) * disk_car->sector_size) != buffer_size) + { + log_error("Write error: set_next_cluster write error\n"); + free(buffer); + return 1; + } + free(buffer); + return 0; +} + +unsigned int fat32_get_prev_cluster(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int cluster, const unsigned int no_of_cluster) +{ + const uint32_t *p32; + uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*disk_car->sector_size; + unsigned int prev_cluster; + unsigned char *buffer=(unsigned char *)MALLOC(disk_car->sector_size); + p32=(const uint32_t*)buffer; + + for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++) + { + const unsigned int offset_o=prev_cluster%(disk_car->sector_size/4); + if((offset_o==0)||(prev_cluster==2)) + { + if((unsigned)disk_car->pread(disk_car, buffer, disk_car->sector_size, hd_offset) != disk_car->sector_size) + { + log_error("fat32_get_prev_cluster error\n"); return 0; + } + hd_offset+=disk_car->sector_size; + } + if((le32(p32[offset_o]) & 0xFFFFFFF) ==cluster) + { + free(buffer); + return prev_cluster; + } + } + free(buffer); + return 0; +} + +/* +static unsigned int get_prev_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster, const unsigned int no_of_cluster) +{ + unsigned int prev_cluster; + for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++) + { + if(get_next_cluster(disk_car,partition,upart_type,offset, prev_cluster)==cluster) + return prev_cluster; + } + return 0; +} +*/ + +int test_FAT(disk_t *disk_car, const struct fat_boot_sector *fat_header, const partition_t *partition, const int verbose, const int dump_ind) +{ + uint64_t start_fat1; + uint64_t start_fat2; + uint64_t start_rootdir; + uint64_t start_data; + uint64_t part_size; + uint64_t end_data; + unsigned long int no_of_cluster; + unsigned long int fat_length; + unsigned long int fat_length_calc; + const char *buffer=(const char*)fat_header; + if(!(le16(fat_header->marker)==0xAA55 + && (fat_header->ignored[0]==0xeb || fat_header->ignored[0]==0xe9) + && (fat_header->fats==1 || fat_header->fats==2))) + return 1; /* Obviously not a FAT */ + if(verbose>1 || dump_ind!=0) + { + log_trace("test_FAT\n"); + log_partition(disk_car, partition); + } + if(dump_ind!=0) + dump_log(fat_header, DEFAULT_SECTOR_SIZE); + if(!((fat_header->ignored[0]==0xeb && fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9)) + { + screen_buffer_add(msg_CHKFAT_BAD_JUMP); + log_error(msg_CHKFAT_BAD_JUMP); + return 1; + } + switch(fat_header->sectors_per_cluster) + { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + break; + default: + screen_buffer_add(msg_CHKFAT_SECT_CLUSTER); + log_error(msg_CHKFAT_SECT_CLUSTER); + return 1; + } + switch(fat_header->fats) + { + case 1: + screen_buffer_add("check_FAT: Unusual, only one FAT\n"); + log_warning("check_FAT: Unusual, only one FAT\n"); + break; + case 2: + break; + default: + screen_buffer_add("check_FAT: Bad number %u of FAT\n", fat_header->fats); + log_error("check_FAT: Bad number %u of FAT\n", fat_header->fats); + return 1; + } + if(fat_sector_size(fat_header)!=disk_car->sector_size) + { + screen_buffer_add("check_FAT: number of bytes per sector mismatches %u (FAT) != %u (HD)\n", + fat_sector_size(fat_header), disk_car->sector_size); + log_error("check_FAT: number of bytes per sector mismatches %u (FAT) != %u (HD)\n", + fat_sector_size(fat_header), disk_car->sector_size); + return 1; + } + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_fat2=start_fat1+(fat_header->fats>1?fat_length:0); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+fat_sector_size(fat_header)-1)/fat_sector_size(fat_header); + no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster; + end_data=start_data+no_of_cluster*fat_header->sectors_per_cluster-1; + if(verbose>1) + { + log_info("number of cluster = %lu\n",no_of_cluster); + } + if(fat_header->media!=0xF0 && fat_header->media<0xF8) + { /* Legal values are 0xF0, 0xF8-0xFF */ + screen_buffer_add("check_FAT: Bad media descriptor (0x%02x!=0xf8)\n",fat_header->media); + log_error("check_FAT: Bad media descriptor (0x%02x!=0xf8)\n",fat_header->media); + return 1; + } + if(no_of_cluster<4085) + { + if(verbose>0) + { + log_info("FAT12 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + if(fat_sectors(fat_header)==0) + { + screen_buffer_add(msg_CHKFAT_SIZE); + log_error(msg_CHKFAT_SIZE); + } + if(le16(fat_header->reserved)!=1) + { + screen_buffer_add("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved)); + log_warning("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved)); + } + if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0)) + { + screen_buffer_add(msg_CHKFAT_ENTRY); + log_error(msg_CHKFAT_ENTRY); + return 1; + } + if((le16(fat_header->fat_length)>256)||(le16(fat_header->fat_length)==0)) + { + screen_buffer_add(msg_CHKFAT_SECTPFAT); + log_error(msg_CHKFAT_SECTPFAT); + return 1; + } + start_rootdir=start_fat2+fat_length; + fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)*2/3-1)*3/2/fat_sector_size(fat_header)); + if(memcmp(buffer+FAT_NAME1,"FAT12 ",8)!=0) /* 2 Mo max */ + { + screen_buffer_add("Should be marked as FAT12\n"); + log_warning("Should be marked as FAT12\n"); + } + if(fat_header->media!=0xF0) + { + screen_buffer_add("check_FAT: Unusual media descriptor (0x%02x!=0xf0)\n", fat_header->media); + log_warning("check_FAT: Unusual media descriptor (0x%02x!=0xf0)\n", fat_header->media); + } + } + else if(no_of_cluster<65525) + { + if(verbose>0) + { + log_info("FAT16 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + if(le16(fat_header->reserved)!=1) + { + screen_buffer_add("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved)); + log_warning("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved)); + } + if(le16(fat_header->fat_length)==0) + { + screen_buffer_add(msg_CHKFAT_SECTPFAT); + log_error(msg_CHKFAT_SECTPFAT); + return 1; + } + if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0)) + { + screen_buffer_add(msg_CHKFAT_ENTRY); + log_error(msg_CHKFAT_ENTRY); + return 1; + } + start_rootdir=start_fat2+fat_length; + fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)/2-1)*2/fat_sector_size(fat_header)); + if(memcmp(buffer+FAT_NAME1,"FAT16 ",8)!=0) + { + screen_buffer_add("Should be marked as FAT16\n"); + log_warning("Should be marked as FAT16\n"); + } + if(fat_header->media!=0xF8) + { /* the only value I have ever seen is 0xF8 */ + screen_buffer_add("check_FAT: Unusual media descriptor (0x%02x!=0xf8)\n", fat_header->media); + log_warning("check_FAT: Unusual media descriptor (0x%02x!=0xf8)\n", fat_header->media); + } + } + else + { + if(verbose>0) + { + log_info("FAT32 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + if(fat_sectors(fat_header)!=0) + { + screen_buffer_add(msg_CHKFAT_SIZE); + log_error(msg_CHKFAT_SIZE); + return 1; + } + if(get_dir_entries(fat_header)!=0) + { + screen_buffer_add(msg_CHKFAT_ENTRY); + log_error(msg_CHKFAT_ENTRY); + return 1; + } + if((fat_header->version[0]!=0) || (fat_header->version[1]!=0)) + { + screen_buffer_add(msg_CHKFAT_BADFAT32VERSION); + log_error(msg_CHKFAT_BADFAT32VERSION); + } + if((le32(fat_header->root_cluster)<2) ||(le32(fat_header->root_cluster)>=2+no_of_cluster)) + { + screen_buffer_add("Bad root_cluster\n"); + log_error("Bad root_cluster\n"); + return 1; + } + start_rootdir=start_data+(uint64_t)(le32(fat_header->root_cluster)-2)*fat_header->sectors_per_cluster; + fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)/4-1)*4/fat_sector_size(fat_header)); + if(memcmp(buffer+FAT_NAME2,"FAT32 ",8)!=0) + { + screen_buffer_add("Should be marked as FAT32\n"); + log_warning("Should be marked as FAT32\n"); + } + if(fat_header->media!=0xF8) + { /* the only value I have ever seen is 0xF8 */ + screen_buffer_add("check_FAT: Unusual media descriptor (0x%02x!=0xf8)\n", fat_header->media); + log_warning("check_FAT: Unusual media descriptor (0x%02x!=0xf8)\n", fat_header->media); + } + if(fat_header->BS_DrvNum!=0 && (fat_header->BS_DrvNum<0x80 || fat_header->BS_DrvNum>0x87)) + { + screen_buffer_add("Warning: Unusual drive number (0x%02x!=0x80)\n", fat_header->BS_DrvNum); + log_warning("Warning: Unusual drive number (0x%02x!=0x80)\n", fat_header->BS_DrvNum); + } + } + if(partition->part_size>0) + { + if(part_size > partition->part_size/fat_sector_size(fat_header)) + { + screen_buffer_add( "Error: size boot_sector %lu > partition %lu\n", + (long unsigned)part_size, + (long unsigned)(partition->part_size/fat_sector_size(fat_header))); + log_error("test_FAT size boot_sector %lu > partition %lu\n", + (long unsigned)part_size, + (long unsigned)(partition->part_size/fat_sector_size(fat_header))); + return 1; + } + else + { + if(verbose>0 && part_size!=partition->part_size) + log_info("Info: size boot_sector %lu, partition %lu\n", + (long unsigned)part_size, + (long unsigned)(partition->part_size/fat_sector_size(fat_header))); + } + } + if(verbose>0) + { + log_info("FAT1 : %lu-%lu\n", (long unsigned)start_fat1, (long unsigned)(start_fat1+fat_length-1)); + log_info("FAT2 : %lu-%lu\n", (long unsigned)start_fat2, (long unsigned)(start_fat2+fat_length-1)); + log_info("start_rootdir : %lu", (long unsigned)start_rootdir); + if(no_of_cluster >= 65525) /* FAT32 */ + log_info(" root cluster : %u",(unsigned int)le32(fat_header->root_cluster)); + log_info("\nData : %lu-%lu\n", (long unsigned)start_data, (long unsigned)end_data); + log_info("sectors : %lu\n", (long unsigned)part_size); + log_info("cluster_size : %u\n", fat_header->sectors_per_cluster); + log_info("no_of_cluster : %lu (2 - %lu)\n", no_of_cluster,no_of_cluster+1); + log_info("fat_length %lu calculated %lu\n",fat_length,fat_length_calc); + } + if(fat_lengthfats>1) + comp_FAT(disk_car,partition,fat_length,le16(fat_header->reserved)); + if(le16(fat_header->heads)!=disk_car->geom.heads_per_cylinder) + { + screen_buffer_add("Warning: number of heads/cylinder mismatches %u (FAT) != %u (HD)\n", + le16(fat_header->heads), disk_car->geom.heads_per_cylinder); + log_warning("heads/cylinder %u (FAT) != %u (HD)\n", + le16(fat_header->heads), disk_car->geom.heads_per_cylinder); + } + if(le16(fat_header->secs_track)!=disk_car->geom.sectors_per_head) + { + screen_buffer_add("Warning: number of sectors per track mismatches %u (FAT) != %u (HD)\n", + le16(fat_header->secs_track), disk_car->geom.sectors_per_head); + log_warning("sect/track %u (FAT) != %u (HD)\n", + le16(fat_header->secs_track), disk_car->geom.sectors_per_head); + } + return 0; +} + +int comp_FAT(disk_t *disk, const partition_t *partition, const unsigned long int fat_size, const unsigned long int sect_res) +{ + /* + return 0 if FATs match + */ + unsigned int reste; + uint64_t hd_offset; + uint64_t hd_offset2; + unsigned char *buffer; + unsigned char *buffer2; + buffer=(unsigned char *)MALLOC(16*disk->sector_size); + buffer2=(unsigned char *)MALLOC(16*disk->sector_size); + hd_offset=partition->part_offset+(uint64_t)sect_res*disk->sector_size; + hd_offset2=hd_offset+(uint64_t)fat_size*disk->sector_size; + reste=(fat_size>1000?1000:fat_size); /* Quick check ! */ + reste*=disk->sector_size; + while(reste>0) + { + const unsigned int read_size=(reste > 16 * disk->sector_size ? 16 * disk->sector_size :reste); + reste-=read_size; + if((unsigned)disk->pread(disk, buffer, read_size, hd_offset) != read_size) + { + log_error("comp_FAT: can't read FAT1\n"); + free(buffer2); + free(buffer); + return 1; + } + if((unsigned)disk->pread(disk, buffer2, read_size, hd_offset2) != read_size) + { + log_error("comp_FAT: can't read FAT2\n"); + free(buffer2); + free(buffer); + return 1; + } + if(memcmp(buffer, buffer2, read_size)!=0) + { + log_error("FAT differs, FAT sectors=%lu-%lu/%lu\n", + (unsigned long) ((hd_offset-partition->part_offset)/disk->sector_size-sect_res), + (unsigned long) ((hd_offset-partition->part_offset+read_size)/disk->sector_size-sect_res), + fat_size); + free(buffer2); + free(buffer); + return 1; + } + hd_offset+=read_size; + hd_offset2+=read_size; + } + free(buffer2); + free(buffer); + return 0; +} + +unsigned long int fat32_get_free_count(const unsigned char *boot_fat32, const unsigned int sector_size) +{ + const struct fat_fsinfo *fsinfo=(const struct fat_fsinfo *)&boot_fat32[sector_size]; + return le32(fsinfo->freecnt); +} + +unsigned long int fat32_get_next_free(const unsigned char *boot_fat32, const unsigned int sector_size) +{ + const struct fat_fsinfo *fsinfo=(const struct fat_fsinfo *)&boot_fat32[sector_size]; + return le32(fsinfo->nextfree); +} + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \separated(disk, partition); + @*/ +static int fat_has_EFI_entry(disk_t *disk, const partition_t *partition, const int verbose) +{ + dir_data_t dir_data; + struct td_list_head *file_walker = NULL; + file_info_t dir_list; + const dir_partition_t res=dir_partition_fat_init(disk, partition, &dir_data, verbose); + if(res!=DIR_PART_OK) + return 0; + TD_INIT_LIST_HEAD(&dir_list.list); + dir_data.get_dir(disk, partition, &dir_data, 0, &dir_list); + td_list_for_each(file_walker, &dir_list.list) + { + const file_info_t *current_file=td_list_entry_const(file_walker, const file_info_t, list); + if(strcmp(current_file->name, "EFI")==0) + { + delete_list_file(&dir_list); + dir_data.close(&dir_data); + return 1; + } + } + delete_list_file(&dir_list); + dir_data.close(&dir_data); + return 0; +} + +int recover_FAT(disk_t *disk_car, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind, const int backup) +{ + int efi=0; + if(test_FAT(disk_car, fat_header, partition, verbose, dump_ind)) + return 1; + partition->part_size=(uint64_t)(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)) * + fat_sector_size(fat_header); + /* test_FAT has set partition->upart_type */ + partition->sborg_offset=0; + partition->sb_size=512; + partition->sb_offset=0; + set_FAT_info(disk_car, fat_header, partition); + switch(partition->upart_type) + { + case UP_FAT12: + if(verbose||dump_ind) + { + log_info("\nFAT12 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + partition->part_type_i386=P_12FAT; + partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA; + break; + case UP_FAT16: + if(verbose||dump_ind) + { + log_info("\nFAT16 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + if(fat_sectors(fat_header)!=0) + partition->part_type_i386=P_16FAT; + else if(offset2cylinder(disk_car,partition->part_offset+partition->part_size-1)<=1024) + partition->part_type_i386=P_16FATBD; + else + partition->part_type_i386=P_16FATBD_LBA; + partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA; + break; + case UP_FAT32: + if(verbose||dump_ind) + { + log_info("\nFAT32 at %u/%u/%u\n", + offset2cylinder(disk_car,partition->part_offset), + offset2head(disk_car,partition->part_offset), + offset2sector(disk_car,partition->part_offset)); + } + if(offset2cylinder(disk_car,partition->part_offset+partition->part_size-1)<=1024) + partition->part_type_i386=P_32FAT; + else + partition->part_type_i386=P_32FAT_LBA; + partition->part_type_mac=PMAC_FAT32; + partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA; + if(backup) + { + partition->sb_offset=6*512; + partition->part_offset-=partition->sb_offset; /* backup sector */ + } + break; + default: + log_critical("recover_FAT unknown FAT type\n"); + return 1; + } + if(memcmp(partition->fsname,"EFI",4)==0) + efi=1; + if(efi==0) + efi=fat_has_EFI_entry(disk_car, partition, verbose); + if(efi) + { + partition->part_type_gpt=GPT_ENT_TYPE_EFI; + strcpy(partition->partname, "EFI System Partition"); + } + return 0; +} + +/*@ + @ requires \valid_read(disk); + @ requires valid_disk(disk); + @ requires \valid_read(fat_header); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @*/ +static int test_OS2MB(const disk_t *disk, const struct fat_boot_sector *fat_header, const partition_t *partition, const int verbose, const int dump_ind) +{ + const char*buffer=(const char*)fat_header; + if(le16(fat_header->marker)==0xAA55 && memcmp(buffer+FAT_NAME1,"FAT ",8)==0) + { +#ifndef __FRAMAC__ + if(verbose||dump_ind) + { + log_info("OS2MB at %u/%u/%u\n", + offset2cylinder(disk, partition->part_offset), + offset2head(disk, partition->part_offset), + offset2sector(disk, partition->part_offset)); + } +#endif + if(dump_ind) + dump_log(buffer, DEFAULT_SECTOR_SIZE); + return 0; + } + return 1; +} + +int check_OS2MB(disk_t *disk, partition_t *partition, const int verbose) +{ + unsigned char *buffer=(unsigned char *)MALLOC(disk->sector_size); + if((unsigned)disk->pread(disk, buffer, disk->sector_size, partition->part_offset) != disk->sector_size) + { + screen_buffer_add("check_OS2MB: Read error\n"); + log_error("check_OS2MB: Read error\n"); + free(buffer); + return 1; + } + if(test_OS2MB(disk,(const struct fat_boot_sector *)buffer,partition,verbose,0)!=0) + { + if(verbose>0) + { + log_info("\n\ntest_OS2MB()\n"); + log_partition(disk, partition); + } + free(buffer); + return 1; + } + partition->upart_type=UP_OS2MB; + free(buffer); + return 0; +} + +int recover_OS2MB(const disk_t *disk, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_OS2MB(disk, fat_header, partition, verbose, dump_ind)) + return 1; + /* 1 cylinder */ + partition->upart_type=UP_OS2MB; + partition->part_size=(uint64_t)disk->geom.heads_per_cylinder * disk->geom.sectors_per_head * disk->sector_size; + partition->part_type_i386=P_OS2MB; + partition->fsname[0]='\0'; + partition->info[0]='\0'; + return 0; +} + +int is_fat(const partition_t *partition) +{ + return (is_fat12(partition)||is_fat16(partition)||is_fat32(partition)); +} + +int is_part_fat(const partition_t *partition) +{ + return (is_part_fat12(partition)||is_part_fat16(partition)||is_part_fat32(partition)); +} + +int is_part_fat12(const partition_t *partition) +{ +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + if(partition->arch==&arch_i386) + { + switch(partition->part_type_i386) + { + case P_12FAT: + case P_12FATH: + return 1; + default: + break; + } + } +#endif + return 0; +} + +static int is_fat12(const partition_t *partition) +{ + return (is_part_fat12(partition) || partition->upart_type==UP_FAT12); +} + +int is_part_fat16(const partition_t *partition) +{ +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + if(partition->arch==&arch_i386) + { + switch(partition->part_type_i386) + { + case P_16FAT: + case P_16FATH: + case P_16FATBD_LBA: + case P_16FATBD: + case P_16FATBDH: + case P_16FATBD_LBAH: + return 1; + default: + break; + } + } +#endif + return 0; +} + +static int is_fat16(const partition_t *partition) +{ + return (is_part_fat16(partition) || partition->upart_type==UP_FAT16); +} + +int is_part_fat32(const partition_t *partition) +{ +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) + if(partition->arch==&arch_i386) + { + switch(partition->part_type_i386) + { + case P_32FAT: + case P_32FAT_LBA: + case P_32FATH: + case P_32FAT_LBAH: + return 1; + default: + break; + } + } +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_MAC) + if(partition->arch==&arch_mac) + { + if(partition->part_type_mac==PMAC_FAT32) + return 1; + } +#endif + return 0; +} + +static int is_fat32(const partition_t *partition) +{ + return (is_part_fat32(partition) || partition->upart_type==UP_FAT32); +} + +int fat32_free_info(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int no_of_cluster, unsigned int *next_free, unsigned int*free_count) +{ + unsigned char *buffer; + const uint32_t *p32; + unsigned int prev_cluster; + uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*disk_car->sector_size; + buffer=(unsigned char *)MALLOC(disk_car->sector_size); + p32=(const uint32_t*)buffer; + *next_free=0; + *free_count=0; + for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++) + { + unsigned long int cluster; + unsigned int offset_o; + offset_o=prev_cluster%(disk_car->sector_size/4); + if((offset_o==0)||(prev_cluster==2)) + { + if((unsigned)disk_car->pread(disk_car, buffer, disk_car->sector_size, hd_offset) != disk_car->sector_size) + { + log_error("fat32_free_info read error\n"); + *next_free=0xFFFFFFFF; + *free_count=0xFFFFFFFF; + return 1; + } + hd_offset+=disk_car->sector_size; + } + cluster=le32(p32[offset_o]) & 0xFFFFFFF; + if(cluster==0) + { + (*free_count)++; + if(*next_free==0) + *next_free=prev_cluster; + } + } + log_info("next_free %u, free_count %u\n",*next_free,*free_count); + free(buffer); + return 0; +} + +int check_VFAT_volume_name(const char *name, const unsigned int max_size) +{ + unsigned int i; + /*@ + @ loop assigns i; + @*/ + for(i=0; i': + case ':': + case '"': + case '/': + case '\\': + case '|': + case '?': + case '*': + return 1; + } + } + return 0; /* Ok */ +} diff --git a/subprojects/lib/src/fat.h b/subprojects/lib/src/fat.h new file mode 100644 index 0000000..04603de --- /dev/null +++ b/subprojects/lib/src/fat.h @@ -0,0 +1,182 @@ +/* + + File: fat.h + + Copyright (C) 1998-2004,2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _FAT_H +#define _FAT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "fat_common.h" +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +int comp_FAT(disk_t *disk, const partition_t *partition, const unsigned long int fat_size, const unsigned long int sect_res); + +/*@ + @ requires \valid_read(fh1); + @ requires \valid_read(fh2); + @*/ +int log_fat2_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +unsigned int get_next_cluster(disk_t *disk, const partition_t *partition, const upart_type_t upart_type, const int offset, const unsigned int cluster); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +int set_next_cluster(disk_t *disk, const partition_t *partition, const upart_type_t upart_type, const int offset, const unsigned int cluster, const unsigned int next_cluster); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +int is_fat(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +int is_part_fat(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +int is_part_fat12(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +int is_part_fat16(const partition_t *partition); + +/*@ + @ requires \valid_read(partition); + @ assigns \nothing; + @*/ +int is_part_fat32(const partition_t *partition); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +unsigned int fat32_get_prev_cluster(disk_t *disk, const partition_t *partition, const unsigned int fat_offset, const unsigned int cluster, const unsigned int no_of_cluster); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @ requires \valid(next_free); + @ requires \valid(free_count); + @*/ +int fat32_free_info(disk_t *disk, const partition_t *partition, const unsigned int fat_offset, const unsigned int no_of_cluster, unsigned int *next_free, unsigned int *free_count); + +/*@ + @ requires \valid_read(boot_fat32 + (0 .. sector_size-1)); + @ assigns \nothing; + @*/ +unsigned long int fat32_get_free_count(const unsigned char *boot_fat32, const unsigned int sector_size); + +/*@ + @ requires \valid_read(boot_fat32 + (0 .. sector_size-1)); + @ assigns \nothing; + @*/ +unsigned long int fat32_get_next_free(const unsigned char *boot_fat32, const unsigned int sector_size); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(fat_header); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition, fat_header); + @*/ +int recover_FAT(disk_t *disk, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind, const int backup); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +int check_FAT(disk_t *disk, partition_t *partition, const int verbose); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(fat_header); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition, fat_header); + @*/ +int test_FAT(disk_t *disk, const struct fat_boot_sector *fat_header, const partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(fat_header); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition, fat_header); + @*/ +int recover_OS2MB(const disk_t *disk, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind); + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid(partition); + @ requires valid_partition(partition); + @ requires separation: \separated(disk, partition); + @*/ +int check_OS2MB(disk_t *disk, partition_t *partition, const int verbose); + +/*@ + @ requires \valid_read(name); + @ assigns \nothing; + @*/ +int check_VFAT_volume_name(const char *name, const unsigned int max_size); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/fat_common.c b/subprojects/lib/src/fat_common.c new file mode 100644 index 0000000..cb4e6c2 --- /dev/null +++ b/subprojects/lib/src/fat_common.c @@ -0,0 +1,66 @@ +/* + + File: fat_common.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "fat_common.h" + +unsigned int fat_sector_size(const struct fat_boot_sector *fat_header) +{ + const unsigned int res=(fat_header->sector_size[1]<<8)+fat_header->sector_size[0]; + /*@ assert res <= 65535; */ + return res; +} + +unsigned int get_dir_entries(const struct fat_boot_sector *fat_header) +{ + const unsigned int res=(fat_header->dir_entries[1]<<8)+fat_header->dir_entries[0]; + /*@ assert res <= 65535; */ + return res; +} + +unsigned int fat_sectors(const struct fat_boot_sector *fat_header) +{ + const unsigned int res=(fat_header->sectors[1]<<8)+fat_header->sectors[0]; + /*@ assert res <= 65535; */ + return res; +} + +unsigned int fat_get_cluster_from_entry(const struct msdos_dir_entry *entry) +{ + return (((unsigned long int)le16(entry->starthi))<<16) | le16(entry->start); +} + +int is_fat_directory(const unsigned char *buffer) +{ + return(buffer[0]=='.' && + memcmp(buffer, ". ", 8+3)==0 && + memcmp(&buffer[0x20], ".. ", 8+3)==0 && + buffer[0xB]!=ATTR_EXT && (buffer[0xB]&ATTR_DIR)!=0 && + buffer[1*0x20+0xB]!=ATTR_EXT && (buffer[1*0x20+0xB]&ATTR_DIR)!=0); +} diff --git a/subprojects/lib/src/fat_common.h b/subprojects/lib/src/fat_common.h new file mode 100644 index 0000000..2b43e79 --- /dev/null +++ b/subprojects/lib/src/fat_common.h @@ -0,0 +1,177 @@ +/* + + File: fat_common.h + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FAT_COMMON_H +#define _FAT_COMMON_H +#ifdef __cplusplus +extern "C" { +#endif + +#define FAT1X_PART_NAME 0x2B +#define FAT32_PART_NAME 0x47 +#define FAT_NAME1 0x36 +#define FAT_NAME2 0x52 /* FAT32 only */ + +#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ +#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG) +#define ATTR_RO 1 /* read-only */ +#define ATTR_HIDDEN 2 /* hidden */ +#define ATTR_SYS 4 /* system */ +#define ATTR_VOLUME 8 /* volume label */ +#define ATTR_DIR 16 /* directory */ +#define ATTR_ARCH 32 /* archived */ + +#define ATTR_NONE 0 /* no attribute bits */ +#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN) + /* attribute bits that are copied "as is" */ +#define ATTR_EXT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) +#define ATTR_EXT_MASK (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME | ATTR_DIR | ATTR_ARCH) + /* bits that are used by the Windows 95/Windows NT extended FAT */ +#define FAT12_BAD 0x0FF7 +#define FAT12_EOC 0x0FF8 +#define FAT16_BAD 0xFFF7 +#define FAT16_EOC 0xFFF8 +#define FAT32_BAD 0x0FFFFFF7 +#define FAT32_EOC 0x0FFFFFF8 +#define FAT1x_BOOT_SECTOR_SIZE 0x200 + +/* + * FAT partition boot sector information, taken from the Linux + * kernel sources. + */ + +struct fat_boot_sector { + uint8_t ignored[3]; /* 0x00 Boot strap short or near jump */ + int8_t system_id[8]; /* 0x03 Name - can be used to special case + partition manager volumes */ + uint8_t sector_size[2]; /* 0x0B bytes per logical sector */ + uint8_t sectors_per_cluster; /* 0x0D sectors/cluster */ + uint16_t reserved; /* 0x0E reserved sectors */ + uint8_t fats; /* 0x10 number of FATs */ + uint8_t dir_entries[2]; /* 0x11 root directory entries */ + uint8_t sectors[2]; /* 0x13 number of sectors */ + uint8_t media; /* 0x15 media code (unused) */ + uint16_t fat_length; /* 0x16 sectors/FAT */ + uint16_t secs_track; /* 0x18 sectors per track */ + uint16_t heads; /* 0x1A number of heads */ + uint32_t hidden; /* 0x1C hidden sectors (unused) */ + uint32_t total_sect; /* 0x20 number of sectors (if sectors == 0) */ + + /* The following fields are only used by FAT32 */ + uint32_t fat32_length; /* 0x24=36 sectors/FAT */ + uint16_t flags; /* 0x28 bit 8: fat mirroring, low 4: active fat */ + uint8_t version[2]; /* 0x2A major, minor filesystem version */ + uint32_t root_cluster; /* 0x2C first cluster in root directory */ + uint16_t info_sector; /* 0x30 filesystem info sector */ + uint16_t backup_boot; /* 0x32 backup boot sector */ + uint8_t BPB_Reserved[12]; /* 0x34 Unused */ + uint8_t BS_DrvNum; /* 0x40 */ + uint8_t BS_Reserved1; /* 0x41 */ + uint8_t BS_BootSig; /* 0x42 */ + uint8_t BS_VolID[4]; /* 0x43 */ + uint8_t BS_VolLab[11]; /* 0x47 */ + uint8_t BS_FilSysType[8]; /* 0x52=82*/ + + /* */ + uint8_t nothing[420]; /* 0x5A */ + uint16_t marker; +} __attribute__ ((gcc_struct, __packed__)); + +struct fat_fsinfo { + uint32_t leadsig; /* 0x41615252 */ + uint8_t reserved1[480]; + uint32_t strucsig; /* 0x61417272 */ + uint32_t freecnt; /* free clusters 0xfffffffff if unknown */ + uint32_t nextfree; /* next free cluster */ + uint8_t reserved3[12]; + uint32_t magic3; /* 0xAA550000 */ +} __attribute__ ((gcc_struct, __packed__)); + +struct msdos_dir_entry { + uint8_t name[8]; /* 00 name and extension */ + uint8_t ext[3]; + uint8_t attr; /* 0B attribute bits */ + uint8_t lcase; /* 0C Case for base and extension */ + uint8_t ctime_ms; /* 0D Creation time, milliseconds */ + uint16_t ctime; /* 0E Creation time */ + uint16_t cdate; /* 10 Creation date */ + uint16_t adate; /* 12 Last access date */ + uint16_t starthi; /* 14 High 16 bits of cluster in FAT32 */ + uint16_t time; /* 16 time, date and first cluster */ + uint16_t date; /* 18 */ + uint16_t start; /* 1A */ + uint32_t size; /* 1C file size (in bytes) */ +} __attribute__ ((gcc_struct, __packed__)); + +/* Up to 13 characters of the name */ +struct msdos_dir_slot { + uint8_t id; /* 00 sequence number for slot */ + uint8_t name0_4[10]; /* 01 first 5 characters in name */ + uint8_t attr; /* 0B attribute byte */ + uint8_t reserved; /* 0C always 0 */ + uint8_t alias_checksum; /* 0D checksum for 8.3 alias */ + uint8_t name5_10[12]; /* 0E 6 more characters in name */ + uint16_t start; /* 1A starting cluster number, 0 in long slots */ + uint8_t name11_12[4]; /* 1C last 2 characters in name */ +}; + + +/*@ + @ requires \valid_read(entry); + @ requires \initialized(entry); + @ assigns \nothing; + @ */ +unsigned int fat_get_cluster_from_entry(const struct msdos_dir_entry *entry); + +/*@ + @ requires \valid_read(buffer + (0 .. 0x40-1)); + @ assigns \nothing; + @ */ +int is_fat_directory(const unsigned char *buffer); + +/*@ + @ requires \valid_read(fat_header); + @ requires \initialized(fat_header); + @ ensures \result <= 65535; + @ assigns \nothing; + @ */ +unsigned int get_dir_entries(const struct fat_boot_sector *fat_header); + +/*@ + @ requires \valid_read(fat_header); + @ requires \initialized(fat_header); + @ ensures \result <= 65535; + @ assigns \nothing; + @ */ +unsigned int fat_sector_size(const struct fat_boot_sector *fat_header); + +/*@ + @ requires \valid_read(fat_header); + @ requires \initialized(fat_header); + @ ensures \result <= 65535; + @ assigns \nothing; + @ */ +unsigned int fat_sectors(const struct fat_boot_sector *fat_header); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/fat_dir.c b/subprojects/lib/src/fat_dir.c new file mode 100644 index 0000000..2e53f91 --- /dev/null +++ b/subprojects/lib/src/fat_dir.c @@ -0,0 +1,612 @@ +/* + + File: fat_dir.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "fat.h" +#include "fat_common.h" +#include "lang.h" +#include "intrf.h" +#include "dir.h" +#include "fat_dir.h" +#include "log.h" +#include "setdate.h" + +#define MSDOS_MKMODE(a,m) ((m & ((a & ATTR_RO) ? LINUX_S_IRUGO|LINUX_S_IXUGO : LINUX_S_IRWXUGO)) | ((a & ATTR_DIR) ? LINUX_S_IFDIR : LINUX_S_IFREG)) +struct fat_dir_struct +{ + struct fat_boot_sector*boot_sector; +}; + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \valid_read(fat_header); + @ requires \valid(dir_list); + @ requires \separated(disk_car, partition, dir_data, fat_header, dir_list); + @*/ +static int fat1x_rootdir(disk_t *disk_car, const partition_t *partition, const dir_data_t *dir_data, const struct fat_boot_sector*fat_header, file_info_t *dir_list); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \valid(file); + @ requires \separated(disk_car, partition, dir_data, file); + @*/ +static int fat_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file); + +/*@ + @ requires \valid(dir_data); + @*/ +static void dir_partition_fat_close(dir_data_t *dir_data); + +/*@ + @ requires len > 0; + @ requires \valid_read(src + (0 .. 2*len-1)); + @ requires \valid((char *)dst + (0 .. 2*len-1)); + @*/ +static inline void fat16_towchar(wchar_t *dst, const uint8_t *src, size_t len) +{ + /*@ loop assigns len, *dst, dst, src; */ + while (len--) { + *dst++ = src[0] | (src[1] << 8); + src += 2; + } +} + +int dir_fat_aux(const unsigned char*buffer, const unsigned int size, const unsigned int param, file_info_t *dir_list) +{ + const struct msdos_dir_entry *de=(const struct msdos_dir_entry*)buffer; + wchar_t unicode[1000]; + unsigned char long_slots; + unsigned int status; + unsigned int inode; + int utf8=1; +#ifdef HAVE_WCTOMB + if(wctomb(NULL, 0) < 0) + utf8=0; +#endif +GetNew: + status=0; + long_slots = 0; + unicode[0]=0; + if (de->attr == ATTR_EXT && + de->name[0] == DELETED_FLAG && + (param & FLAG_LIST_DELETED)==FLAG_LIST_DELETED) + { + unsigned int i; + const struct msdos_dir_slot *ds; + const struct msdos_dir_entry *de_initial; + unsigned char slot; + unsigned char sum; + unsigned char alias_checksum; +ParseLongDeleted: + de_initial=de; + long_slots = 0; + ds = (const struct msdos_dir_slot *) de; + alias_checksum = ds->alias_checksum; + /* The number of slot has been overwritten, try to find it */ + while (1) + { + if((const void*)de>=(const void*)(buffer+size)) + return 0; + ds = (const struct msdos_dir_slot *) de; + if(de->name[0] != DELETED_FLAG) + goto GetNew; + if (ds->attr != ATTR_EXT) + goto ParseLongDeletedNext; + if (ds->alias_checksum != alias_checksum) + goto ParseLongDeleted; + de++; + long_slots++; + } +ParseLongDeletedNext: + if ((de->attr & ATTR_VOLUME)!=0) + { + long_slots=0; + goto RecEnd; + } + { + ds = (const struct msdos_dir_slot *) de_initial; + unicode[long_slots * 13] = 0; + for(slot=long_slots;slot!=0;) + { + int offset; + slot--; + offset = slot * 13; + fat16_towchar(unicode + offset, ds->name0_4, 5); + fat16_towchar(unicode + offset + 5, ds->name5_10, 6); + fat16_towchar(unicode + offset + 11, ds->name11_12, 2); + ds++; + } + } + /* The first char of the short filename has been overwritten, + use the uppercase version of the first char from the unicode filename + */ + for (sum = toupper(unicode[0]), i = 1; i < 8; i++) + sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; + for (i = 0; i < 3; i++) + sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->ext[i]; + /* If checksum don't match, use the short filename */ + if (sum != alias_checksum) + long_slots = 0; + else + status=FILE_STATUS_DELETED; + } + else if (de->attr == ATTR_EXT) + { + unsigned int i; + const struct msdos_dir_slot *ds; + unsigned char id; + unsigned char sum; + unsigned char alias_checksum; +ParseLong: + ds = (const struct msdos_dir_slot *) de; + id = ds->id; + if ((id & 0x40)==0) + goto RecEnd; + { + unsigned char slots; + unsigned char slot; + slots = id & ~0x40; + if (slots > 20 || slots==0) /* ceil(256 * 2 / 26) */ + goto RecEnd; + long_slots = slots; + alias_checksum = ds->alias_checksum; + + slot = slots; + while (1) { + int offset; + + slot--; + offset = slot * 13; + fat16_towchar(unicode + offset, ds->name0_4, 5); + fat16_towchar(unicode + offset + 5, ds->name5_10, 6); + fat16_towchar(unicode + offset + 11, ds->name11_12, 2); + + if ((ds->id & 0x40)!=0) { + unicode[offset + 13] = 0; + } + de++; + if((const void*)de>=(const void*)(buffer+size)) + return 0; + if (slot == 0) + break; + ds = (const struct msdos_dir_slot *) de; + if (ds->attr != ATTR_EXT) + { + long_slots=0; + goto RecEnd; /* XXX */ + } + if ((ds->id & ~0x40) != slot) + goto ParseLong; + if (ds->alias_checksum != alias_checksum) + goto ParseLong; + } + } + if (de->attr == ATTR_EXT) + goto ParseLong; + if (IS_FREE(de->name) || ((de->attr & ATTR_VOLUME)!=0)) + { + long_slots=0; + goto RecEnd; + } + for (sum = 0, i = 0; i < 8; i++) + sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i]; + for (i = 0; i < 3; i++) + sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->ext[i]; + if (sum != alias_checksum) + long_slots = 0; + } +RecEnd: + inode=(le16(de->starthi)<<16)|le16(de->start); + if((param&FLAG_LIST_MASK12)!=0) + inode&=0xfff; + else if((param&FLAG_LIST_MASK16)!=0) + inode&=0xffff; + else + inode&=0xfffffff; + if(long_slots==0 && de->attr != ATTR_EXT) + { /* short name 8.3 */ + int i; + int j=0; + for(i=0;(i<8)&&(de->name[i]!=' ');i++) + unicode[j++]=de->name[i]; + if(de->ext[0]!=' ') + { + unicode[j++]='.'; + for(i=0;(i<3)&&(de->ext[i]!=' ');i++) + unicode[j++]=de->ext[i]; + } + unicode[j]=0; + if((unicode[0] == DELETED_FLAG) && + ((param & FLAG_LIST_DELETED)==FLAG_LIST_DELETED) && + inode!=0 && de->name[1]!='\0' && + de->name[2]!='\0' && de->name[3]!='\0' && + de->name[4]!='\0' && de->name[5]!='\0' && + de->name[6]!='\0' && de->name[7]!='\0') + { + status=FILE_STATUS_DELETED; + if((de->attr&ATTR_DIR)==ATTR_DIR && + ((td_list_empty(&dir_list->list) && unicode[1]=='\0') || + (!td_list_empty(&dir_list->list) && dir_list->list.next==dir_list->list.prev && unicode[1]=='.' && unicode[2]=='\0'))) + unicode[0]='.'; /* "." and ".." are the first two entries */ + else + unicode[0]='_'; + } + } + if (((de->attr != ATTR_EXT)||(long_slots!=0)) && + !(de->attr & ATTR_VOLUME)) + { + if(unicode[0]==0) + return 0; + if(unicode[0] != DELETED_FLAG) + { + unsigned int i,o; + file_info_t *new_file=(file_info_t *)MALLOC(sizeof(*new_file)); + new_file->name=(char*)MALLOC(DIR_NAME_LEN); + for(i=0,o=0; o0x7f) + { +#ifdef HAVE_WCTOMB + const int sizec=wctomb(&new_file->name[o], unicode[i]); +#else + const int sizec=unicode[i]; +#endif + if(sizec <= 0) + { + new_file->name[o++]=unicode[i]; + utf8=0; + } + else + o += sizec; + } + else + new_file->name[o++]=unicode[i]; + } + new_file->name[o]='\0'; + new_file->st_ino=inode; + new_file->st_mode = MSDOS_MKMODE(de->attr,(LINUX_S_IRWXUGO & ~(LINUX_S_IWGRP|LINUX_S_IWOTH))); + new_file->st_uid=0; + new_file->st_gid=0; + new_file->st_size=le32(de->size); +// new_file->st_blksize=cluster_size; + new_file->td_atime=new_file->td_ctime=new_file->td_mtime=date_dos2unix(le16(de->time),le16(de->date)); + new_file->status=status; + /* log_debug("fat: new file %s de=%p size=%u\n",new_file->name,de,le32(de->size)); */ + td_list_add_tail(&new_file->list, &dir_list->list); + } + } + de++; + if((const void *)de<(const void *)(buffer+size-1) && + de->name[0] != (int8_t) 0) + goto GetNew; + return 0; +} + +typedef enum {FAT_FOLLOW_CLUSTER, FAT_NEXT_FREE_CLUSTER, FAT_NEXT_CLUSTER} fat_method_t; + +/*@ assigns \nothing; */ +static int is_EOC(const unsigned int cluster, const upart_type_t upart_type) +{ + if(upart_type==UP_FAT12) + return ((cluster&0x0ff8)==(unsigned)FAT12_EOC); + else if(upart_type==UP_FAT16) + return ((cluster&0x0fff8)==(unsigned)FAT16_EOC); + else + return((cluster&0xffffff8)==(unsigned)FAT32_EOC); +} + +#define NBR_ENTRIES_MAX 65536 + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid_read(dir_data); + @ requires \valid(dir_list); + @ requires \separated(disk_car, partition, dir_data, dir_list); + @*/ +static int fat_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster, file_info_t *dir_list) +{ + const struct fat_dir_struct *ls=(const struct fat_dir_struct*)dir_data->private_dir_data; + const struct fat_boot_sector*fat_header=ls->boot_sector; + unsigned int cluster=first_cluster; + if(fat_header->sectors_per_cluster<1) + { + log_error("FAT: Can't list files, bad cluster size.\n"); + return -1; + } + if(fat_sector_size(fat_header)==0) + { + log_error("FAT: Can't list files, bad sector size.\n"); + return -1; + } + if(cluster==0) + { + if(partition->upart_type!=UP_FAT32) + return fat1x_rootdir(disk_car, partition, dir_data, fat_header, dir_list); + if(le32(fat_header->root_cluster)<2) + { + log_error("FAT32: Can't list files, bad root cluster.\n"); + return -1; + } + cluster=le32(fat_header->root_cluster); + } + if(get_next_cluster(disk_car, partition, partition->upart_type, le16(fat_header->reserved), cluster)==0) + { + log_warning("FAT: Directory entry is marked as free.\n"); + } + { + const unsigned int cluster_size=fat_header->sectors_per_cluster * fat_sector_size(fat_header); + unsigned char *buffer_dir=(unsigned char *)MALLOC(32*NBR_ENTRIES_MAX); + unsigned int nbr_cluster; + const unsigned int nbr_cluster_max=32*NBR_ENTRIES_MAX/cluster_size; + int stop=0; + uint64_t start_fat1,start_data,part_size; + unsigned long int no_of_cluster,fat_length; + fat_method_t fat_meth=FAT_FOLLOW_CLUSTER; + memset(buffer_dir,0,32*NBR_ENTRIES_MAX); + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size; + no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster; + nbr_cluster=0; + while(!is_EOC(cluster, partition->upart_type) && cluster>=2 && nbr_clusterpart_offset+(uint64_t)(start_data+(cluster-2)*fat_header->sectors_per_cluster)*fat_sector_size(fat_header); +// if(dir_data->verbose>0) + { + log_info("FAT: cluster=%u(0x%x), pos=%lu\n",cluster,cluster,(long unsigned)(start/fat_sector_size(fat_header))); + } + if((unsigned)disk_car->pread(disk_car, buffer_dir + (uint64_t)cluster_size * nbr_cluster, cluster_size, start) != cluster_size) + { + log_error("FAT: Can't read directory cluster.\n"); + stop=1; + } + if(stop==0 && nbr_cluster==0 && + !(partition->upart_type==UP_FAT32 && first_cluster==0) && + !(buffer_dir[0]=='.' && buffer_dir[0x20]=='.' && buffer_dir[0x21]=='.')) + { + stop=1; + } + if(stop==0) + { + if(fat_meth==FAT_FOLLOW_CLUSTER) + { + const unsigned int next_cluster=get_next_cluster(disk_car, partition, partition->upart_type, start_fat1, cluster); + if((next_cluster>=2 && next_cluster<=no_of_cluster+2) || + is_EOC(next_cluster, partition->upart_type)) + cluster=next_cluster; + else if(next_cluster==0) + { +#if 0 + /* FIXME: experimental */ + if(cluster==first_cluster && (dir_data->param & FLAG_LIST_DELETED)==FLAG_LIST_DELETED) + fat_meth=FAT_NEXT_FREE_CLUSTER; /* Recovery of a deleted directory */ + else + cluster=0; /* Stop directory listing */ +#else + cluster=0; /* Stop directory listing */ +#endif + } + else + fat_meth=FAT_NEXT_CLUSTER; /* FAT is corrupted, don't trust it */ + } + if(fat_meth==FAT_NEXT_CLUSTER) + cluster++; + else if(fat_meth==FAT_NEXT_FREE_CLUSTER) + { /* Deleted directories are composed of "free" clusters */ + while(++clusterupart_type, start_fat1, cluster)!=0); + } + nbr_cluster++; + } + } + if(nbr_cluster>0) + dir_fat_aux(buffer_dir, cluster_size*nbr_cluster, dir_data->param, dir_list); + free(buffer_dir); + return 0; + } +} + +static int fat1x_rootdir(disk_t *disk_car, const partition_t *partition, const dir_data_t *dir_data, const struct fat_boot_sector*fat_header, file_info_t *dir_list) +{ + const unsigned int root_size=(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size*disk_car->sector_size; + if(root_size==0) + return -1; + if(dir_data->verbose>1) + { + log_trace("fat1x_rootdir root_size=%u sectors\n",root_size/disk_car->sector_size); + } + { + int res; + uint64_t start; + unsigned char *buffer_dir; + buffer_dir=(unsigned char*)MALLOC(root_size); + start=partition->part_offset+(uint64_t)((le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length))*disk_car->sector_size); + if((unsigned)disk_car->pread(disk_car, buffer_dir, root_size, start) != root_size) + { + log_error("FAT 1x: Can't read root directory.\n"); + /* Don't return yet, it may have been a partial read */ + } + res=dir_fat_aux(buffer_dir, root_size, dir_data->param, dir_list); + free(buffer_dir); + return res; + } +} + + +dir_partition_t dir_partition_fat_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose) +{ + static unsigned char *buffer; + static struct fat_dir_struct *ls; + buffer=(unsigned char*)MALLOC(0x200); + if(disk_car->pread(disk_car, buffer, 0x200, partition->part_offset) != 0x200) + { + log_error("Can't read FAT boot sector.\n"); + free(buffer); + return DIR_PART_EIO; + } + set_secwest(); + ls=(struct fat_dir_struct *)MALLOC(sizeof(*ls)); + ls->boot_sector=(struct fat_boot_sector*)buffer; + strncpy(dir_data->current_directory,"/",sizeof(dir_data->current_directory)); + dir_data->current_inode=0; + dir_data->param=FLAG_LIST_DELETED; + if(partition->upart_type==UP_FAT12) + dir_data->param|=FLAG_LIST_MASK12; + else if(partition->upart_type==UP_FAT16) + dir_data->param|=FLAG_LIST_MASK16; + dir_data->verbose=verbose; + dir_data->capabilities=CAPA_LIST_DELETED; + dir_data->copy_file=&fat_copy; + dir_data->close=&dir_partition_fat_close; + dir_data->local_dir=NULL; + dir_data->private_dir_data=ls; + dir_data->get_dir=&fat_dir; + return DIR_PART_OK; +} + +static void dir_partition_fat_close(dir_data_t *dir_data) +{ + struct fat_dir_struct *ls=(struct fat_dir_struct*)dir_data->private_dir_data; + free(ls->boot_sector); + free(ls); +} + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(dir_data); + @ requires \valid_read(file); + @ requires \separated(disk_car, partition, dir_data, file); + @*/ +static int fat_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file) +{ + char *new_file; + FILE *f_out; + const struct fat_dir_struct *ls=(const struct fat_dir_struct*)dir_data->private_dir_data; + const struct fat_boot_sector *fat_header=ls->boot_sector; + const unsigned int sectors_per_cluster=fat_header->sectors_per_cluster; + const unsigned int block_size=fat_sector_size(fat_header)*sectors_per_cluster; + unsigned char *buffer_file=(unsigned char *)MALLOC(block_size); + unsigned int cluster; + unsigned int file_size=file->st_size; + fat_method_t fat_meth=FAT_FOLLOW_CLUSTER; + uint64_t start_fat1,start_data,part_size; + unsigned long int no_of_cluster,fat_length; + f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory); + if(!f_out) + { + log_critical("Can't create file %s: \n",new_file); + free(new_file); + free(buffer_file); + return -1; + } + cluster = file->st_ino; + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size; + no_of_cluster=(part_size-start_data)/sectors_per_cluster; + log_trace("fat_copy dst=%s first_cluster=%u (%llu) size=%lu\n", new_file, + cluster, + (long long unsigned)start_data+(cluster-2)*sectors_per_cluster, + (long unsigned)file_size); + + while(cluster>=2 && cluster<=no_of_cluster+2 && file_size>0) + { + const uint64_t start=partition->part_offset+(uint64_t)(start_data+(cluster-2)*sectors_per_cluster)*fat_sector_size(fat_header); + unsigned int toread = block_size; + if (toread > file_size) + toread = file_size; + if((unsigned)disk_car->pread(disk_car, buffer_file, toread, start) != toread) + { + log_error("fat_copy: Can't read cluster %u.\n", cluster); + } + if(fwrite(buffer_file, 1, toread, f_out) != toread) + { + log_error("fat_copy: failed to write data %s\n", strerror(errno)); + fclose(f_out); + set_date(new_file, file->td_atime, file->td_mtime); + free(new_file); + free(buffer_file); + return -1; + } + file_size -= toread; + if(file_size>0) + { + if(fat_meth==FAT_FOLLOW_CLUSTER) + { + const unsigned int next_cluster=get_next_cluster(disk_car, partition, partition->upart_type, start_fat1, cluster); + if(next_cluster>=2 && next_cluster<=no_of_cluster+2) + cluster=next_cluster; + else if(cluster==file->st_ino && next_cluster==0) + fat_meth=FAT_NEXT_FREE_CLUSTER; /* Recovery of a deleted file */ + else + fat_meth=FAT_NEXT_CLUSTER; /* FAT is corrupted, don't trust it */ + } + if(fat_meth==FAT_NEXT_CLUSTER) + cluster++; + else if(fat_meth==FAT_NEXT_FREE_CLUSTER) + { /* Deleted file are composed of "free" clusters */ + while(++clusterupart_type, start_fat1, cluster)!=0); + } + } + } + fclose(f_out); + set_date(new_file, file->td_atime, file->td_mtime); + free(new_file); + free(buffer_file); + return 0; +} diff --git a/subprojects/lib/src/fat_dir.h b/subprojects/lib/src/fat_dir.h new file mode 100644 index 0000000..9e1d34a --- /dev/null +++ b/subprojects/lib/src/fat_dir.h @@ -0,0 +1,50 @@ +/* + + File: fat_dir.h + + Copyright (C) 2004-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FAT_DIR_H +#define _FAT_DIR_H +#ifdef __cplusplus +extern "C" { +#endif +#include "dir_common.h" + +/*@ + @ requires \valid_read(buffer + (0 .. size-1)); + @ requires \initialized(buffer + (0 .. size-1)); + @ requires \valid(dir_list); + @ requires \separated(dir_list, buffer+(..)); + @*/ +int dir_fat_aux(const unsigned char*buffer, const unsigned int size, const unsigned int param, file_info_t *dir_list); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(dir_data); + @ requires \separated(disk_car, partition, dir_data); + @*/ +dir_partition_t dir_partition_fat_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/fatp.c b/subprojects/lib/src/fatp.c new file mode 100644 index 0000000..a227082 --- /dev/null +++ b/subprojects/lib/src/fatp.c @@ -0,0 +1,241 @@ +/* + + File: fatp.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "types.h" +#include "common.h" +#include "list.h" +#include "filegen.h" +#include "photorec.h" +#include "fatp.h" +#include "fat.h" +#include "fat_common.h" +#include "log.h" + +/*@ + @ requires \valid(disk); + @ requires valid_disk(disk); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(list_search_space); + @ requires \separated(disk, partition, list_search_space); + @*/ +static void fat12_remove_used_space(disk_t *disk,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size) +{ + unsigned char *buffer; + unsigned int cluster; + const uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*sector_size; + uint64_t start_free=0; + uint64_t end_free=0; + unsigned long int offset_s_prev=0; + log_trace("fat12_remove_used_space\n"); + buffer=(unsigned char *)MALLOC(2*sector_size); + del_search_space(list_search_space, partition->part_offset, + partition->part_offset + (uint64_t)start_data * sector_size - 1); + for(cluster=2; cluster<=no_of_cluster+1; cluster++) + { + unsigned long int offset_s,offset_o; + unsigned int next_cluster; + offset_s=(cluster+cluster/2)/disk->sector_size; + offset_o=(cluster+cluster/2)%disk->sector_size; + if(offset_s!=offset_s_prev || cluster==2) + { + offset_s_prev=offset_s; + if((unsigned)disk->pread(disk, buffer, 2*sector_size, hd_offset + offset_s * disk->sector_size) != 2*sector_size) + { + /* Consider these FAT sectors points to free clusters */ + } + } + if((cluster&1)!=0) + next_cluster=le16((*((uint16_t*)&buffer[offset_o])))>>4; + else + next_cluster=le16(*((uint16_t*)&buffer[offset_o]))&0x0FFF; + if(next_cluster!=0) + { + /* Not free */ + if(end_free+1==partition->part_offset+(start_data+(uint64_t)(cluster-2)*cluster_size)*sector_size) + end_free+=cluster_size*sector_size; + else + { + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); + start_free=partition->part_offset+(start_data+(uint64_t)(cluster-2)*cluster_size)*sector_size; + end_free=start_free+(uint64_t)cluster_size*sector_size-1; + } + } + } + free(buffer); + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); +} + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(list_search_space); + @ requires \separated(disk_car, partition, list_search_space); + @*/ +static void fat16_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size) +{ + unsigned char *buffer; + const uint16_t *p16; + unsigned int prev_cluster; + uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*sector_size; + uint64_t start_free=0; + uint64_t end_free=0; + log_trace("fat16_remove_used_space\n"); + buffer=(unsigned char *)MALLOC(sector_size); + p16=(const uint16_t*)buffer; + del_search_space(list_search_space, partition->part_offset, + partition->part_offset + (uint64_t)start_data * sector_size - 1); + for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++) + { + unsigned int offset_o; + offset_o=prev_cluster%(sector_size/2); + if((offset_o==0)||(prev_cluster==2)) + { + if((unsigned)disk_car->pread(disk_car, buffer, sector_size, hd_offset) != sector_size) + { + /* Consider these FAT sectors points to free clusters */ + } + hd_offset+=sector_size; + } + if(le16(p16[offset_o])!=0) + { + /* Not free */ + if(end_free+1==partition->part_offset+(start_data+(uint64_t)(prev_cluster-2)*cluster_size)*sector_size) + end_free+=cluster_size*sector_size; + else + { + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); + start_free=partition->part_offset+(start_data+(uint64_t)(prev_cluster-2)*cluster_size)*sector_size; + end_free=start_free+(uint64_t)cluster_size*sector_size-1; + } + } + } + free(buffer); + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); +} + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires \valid(list_search_space); + @ requires \separated(disk_car, partition, list_search_space); + @*/ +static void fat32_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size) +{ + unsigned char *buffer; + uint32_t *p32; + unsigned int prev_cluster; + uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*sector_size; + uint64_t start_free=0; + uint64_t end_free=0; + log_trace("fat32_remove_used_space\n"); + buffer=(unsigned char *)MALLOC(sector_size); + p32=(uint32_t*)buffer; + del_search_space(list_search_space, partition->part_offset, + partition->part_offset + (uint64_t)start_data * sector_size - 1); + for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++) + { + unsigned long int cluster; + unsigned int offset_o; + offset_o=prev_cluster%(sector_size/4); + if((offset_o==0)||(prev_cluster==2)) + { + if((unsigned)disk_car->pread(disk_car, buffer, sector_size, hd_offset) != sector_size) + { + /* Consider these FAT sectors points to free clusters */ + } + hd_offset+=sector_size; + } + cluster=le32(p32[offset_o]) & 0xFFFFFFF; + if(cluster!=0) + { + /* Not free */ + if(end_free+1==partition->part_offset+(uint64_t)(start_data+(prev_cluster-2)*cluster_size)*sector_size) + end_free+=cluster_size*sector_size; + else + { + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); + start_free=partition->part_offset+(start_data+(uint64_t)(prev_cluster-2)*cluster_size)*sector_size; + end_free=start_free+(uint64_t)cluster_size*sector_size-1; + } + } + } + free(buffer); + if(start_free != end_free) + del_search_space(list_search_space, start_free, end_free); +} + +unsigned int fat_remove_used_space(disk_t *disk_car, const partition_t *partition, alloc_data_t *list_search_space) +{ + unsigned long int fat_length; + unsigned long int start_fat1; + unsigned long int part_size; + unsigned int no_of_cluster; + unsigned int start_data; + unsigned char *buffer; + unsigned int res; + unsigned int sector_size; + const struct fat_boot_sector *fat_header; + buffer=(unsigned char *)MALLOC(3*disk_car->sector_size); + fat_header=(const struct fat_boot_sector *)buffer; + if((unsigned)disk_car->pread(disk_car, buffer, 3 * disk_car->sector_size, partition->part_offset) != 3 * disk_car->sector_size) + { + free(buffer); + return 0; + } + sector_size=fat_sector_size(fat_header); + if(sector_size==0) + { + free(buffer); + return 0; + } + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+sector_size-1)/sector_size; + no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster; + if(partition->upart_type==UP_FAT12) + fat12_remove_used_space(disk_car,partition, list_search_space, start_fat1, no_of_cluster, start_data, fat_header->sectors_per_cluster,sector_size); + else if(partition->upart_type==UP_FAT16) + fat16_remove_used_space(disk_car,partition, list_search_space, start_fat1, no_of_cluster, start_data, fat_header->sectors_per_cluster,sector_size); + else if(partition->upart_type==UP_FAT32) + fat32_remove_used_space(disk_car,partition, list_search_space, start_fat1, no_of_cluster, start_data, fat_header->sectors_per_cluster,sector_size); + res=fat_header->sectors_per_cluster * sector_size; + free(buffer); + return res; +} diff --git a/subprojects/lib/src/fatp.h b/subprojects/lib/src/fatp.h new file mode 100644 index 0000000..699a25e --- /dev/null +++ b/subprojects/lib/src/fatp.h @@ -0,0 +1,42 @@ +/* + + File: fatp.h + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FATP_H +#define _FATP_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(partition); + @ requires valid_partition(partition); + @ requires valid_list_search_space(list_search_space); + @ requires \separated(disk_car, partition, list_search_space); + @*/ +// ensures valid_list_search_space(list_search_space); +unsigned int fat_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/fatx.c b/subprojects/lib/src/fatx.c new file mode 100644 index 0000000..ced7d39 --- /dev/null +++ b/subprojects/lib/src/fatx.c @@ -0,0 +1,68 @@ +/* + + File: fatx.c + + Copyright (C) 2005-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "fatx.h" +static void set_FATX_info(partition_t *partition); + +static int test_fatx(const struct disk_fatx *fatx_block) +{ + if(memcmp(fatx_block->magic,"FATX",4)!=0) + return 1; + return 0; +} + +int check_FATX(disk_t *disk_car,partition_t *partition) +{ + unsigned char buffer[8*DEFAULT_SECTOR_SIZE]; + if(disk_car->pread(disk_car, &buffer, sizeof(buffer), partition->part_offset) != sizeof(buffer)) + { return 1; } + if(test_fatx((const struct disk_fatx *)&buffer)!=0) + return 1; + set_FATX_info(partition); + return 0; +} + +int recover_FATX(const struct disk_fatx *fatx_block, partition_t *partition) +{ + if(test_fatx(fatx_block)!=0) + return 1; + set_FATX_info(partition); + partition->part_type_xbox=PXBOX_FATX; + /* FIXME: Locate the partition but cannot get the part_size unfortunatly */ + partition->part_size=(uint64_t)le32(fatx_block->cluster_size_in_sector)*512; + return 0; +} + +static void set_FATX_info(partition_t *partition) +{ + partition->upart_type=UP_FATX; + partition->fsname[0]='\0'; + strncpy(partition->info,"FATX",sizeof(partition->info)); +} diff --git a/subprojects/lib/src/fatx.h b/subprojects/lib/src/fatx.h new file mode 100644 index 0000000..a6c46ac --- /dev/null +++ b/subprojects/lib/src/fatx.h @@ -0,0 +1,55 @@ +/* + + File: fatx.h + + Copyright (C) 2005 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FATX_H +#define _FATX_H +#ifdef __cplusplus +extern "C" { +#endif + +struct disk_fatx +{ + char magic[4]; + uint32_t volume_id; + uint32_t cluster_size_in_sector; + uint16_t fats; + uint32_t unknown; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_FATX(disk_t *disk_car, partition_t *partition); + +/*@ + @ requires \valid_read(fatx_block); + @ requires \valid(partition); + @ requires \separated(fatx_block, partition); + @*/ +int recover_FATX(const struct disk_fatx *fatx_block, partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_1cd.c b/subprojects/lib/src/file_1cd.c new file mode 100644 index 0000000..06c7f0f --- /dev/null +++ b/subprojects/lib/src/file_1cd.c @@ -0,0 +1,79 @@ +/* + + File: file_1cd.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_1cd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_1cd(file_stat_t *file_stat); + +const file_hint_t file_hint_1cd= { + .extension="1cd", + .description="Russian Finance 1C:Enterprise 8", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_1cd +}; + +struct header_1cd +{ + char magic[8]; + uint32_t version; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct header_1cd); + @ requires separation: \separated(&file_hint_1cd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_1cd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct header_1cd *hdr=(const struct header_1cd *)buffer; + if(le32(hdr->size)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_1cd.extension; + file_recovery_new->calculated_file_size=((uint64_t)le32(hdr->size))<<12; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_1cd(file_stat_t *file_stat) +{ + static const unsigned char header_1cd[9]= { '1', 'C', 'D', 'B', 'M', 'S', 'V', '8', 0x08 }; + register_header_check(0, header_1cd, sizeof(header_1cd), &header_check_1cd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_3dm.c b/subprojects/lib/src/file_3dm.c new file mode 100644 index 0000000..0e0dd48 --- /dev/null +++ b/subprojects/lib/src/file_3dm.c @@ -0,0 +1,70 @@ +/* + + File: file_3dm.c + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_3dm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_3dm(file_stat_t *file_stat); + +const file_hint_t file_hint_3dm= { + .extension="3dm", + .description="Rhino / openNURBS", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_3dm +}; + +/*@ + @ requires separation: \separated(&file_hint_3dm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_3dm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i; + /*@ loop assigns i; */ + for(i=24; + i=buffer_size || buffer[i]<'0' || buffer[i]>'9') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_3dm.extension; + return 1; +} + +static void register_header_check_3dm(file_stat_t *file_stat) +{ + register_header_check(0, "3D Geometry File Format ", 24, &header_check_3dm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_3ds.c b/subprojects/lib/src/file_3ds.c new file mode 100644 index 0000000..be180e2 --- /dev/null +++ b/subprojects/lib/src/file_3ds.c @@ -0,0 +1,84 @@ +/* + + File: file_3ds.c + + Copyright (C) 2019 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_3ds) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_3ds(file_stat_t *file_stat); + +const file_hint_t file_hint_3ds= { + .extension="3ds", + .description="3d Studio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_3ds +}; + +struct chunk_3ds +{ + uint16_t chunk_id; + uint32_t next_chunk; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct chunk_3ds); + @ requires separation: \separated(&file_hint_3ds, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_3ds(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t fs; + const struct chunk_3ds *hdr=(const struct chunk_3ds *)buffer; + if(buffer_size < 0x12) + return 0; + if(buffer[0]!=0x4d || buffer[1]!=0x4d || buffer[0x10]!=0x3d || buffer[0x11]!=0x3d) + return 0; + fs=le32(hdr->next_chunk); + if(fs <= 0x12) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_3ds.extension; + file_recovery_new->calculated_file_size=fs; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_3ds(file_stat_t *file_stat) +{ + static const unsigned char header_3ds[4]= { 0x02, 0x00, 0x0a, 0x00 }; + register_header_check(6, header_3ds, sizeof(header_3ds), &header_check_3ds, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_7z.c b/subprojects/lib/src/file_7z.c new file mode 100644 index 0000000..3d87d6f --- /dev/null +++ b/subprojects/lib/src/file_7z.c @@ -0,0 +1,89 @@ +/* + + File: file_7z.c + + Copyright (C) 2005-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_7z) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_7z(file_stat_t *file_stat); + +const file_hint_t file_hint_7z= { + .extension="7z", + .description="7zip archive file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_7z +}; + +struct header_7z { + unsigned char signature[6]; + uint8_t majorversion; + uint8_t minorversion; + uint32_t crcFromArchive; + uint64_t nextHeaderOffset; + uint64_t nextHeaderSize; + uint64_t nextHeaderCRC; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct header_7z); + @ requires separation: \separated(&file_hint_7z, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_7z(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct header_7z *buffer_7z=(const struct header_7z *)buffer; + if(buffer_7z->majorversion!=0 || + le64(buffer_7z->nextHeaderSize)==0) + return 0; + if( le64(buffer_7z->nextHeaderOffset) > 0x7000000000000000 || + le64(buffer_7z->nextHeaderSize) > 0x7000000000000000) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_7z.extension; + file_recovery_new->min_filesize=31; + /* Signature size 12 + Start header size 20 */ + file_recovery_new->calculated_file_size=(uint64_t)le64(buffer_7z->nextHeaderOffset)+ + le64(buffer_7z->nextHeaderSize) + 12 + 20; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_7z(file_stat_t *file_stat) +{ + static const unsigned char header_7z[6] = {'7','z', 0xbc, 0xaf, 0x27, 0x1c}; + register_header_check(0, header_7z, sizeof(header_7z), &header_check_7z, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_DB.c b/subprojects/lib/src/file_DB.c new file mode 100644 index 0000000..02dd351 --- /dev/null +++ b/subprojects/lib/src/file_DB.c @@ -0,0 +1,65 @@ +/* + + File: file_DB.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_DB) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_DB(file_stat_t *file_stat); + +const file_hint_t file_hint_DB= { + .extension="DB", + .description="", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_DB +}; + +/*@ + @ requires separation: \separated(&file_hint_DB, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_DB(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_DB.extension; + return 1; +} + +static void register_header_check_DB(file_stat_t *file_stat) +{ + static const unsigned char DB_header[6]= { + 0x19, 0x01, 0x00, 0x08, 0x02, 0x20 + }; + register_header_check(0, DB_header,sizeof(DB_header), &header_check_DB, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_a.c b/subprojects/lib/src/file_a.c new file mode 100644 index 0000000..c67c4fb --- /dev/null +++ b/subprojects/lib/src/file_a.c @@ -0,0 +1,85 @@ +/* + + File: file_a.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_a) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_a(file_stat_t *file_stat); + +const file_hint_t file_hint_a= { + .extension="a", + .description="Unix Archive/Debian package", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_a +}; + +struct file_header +{ + char name[16]; + char mtime[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char magic[2]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= 8 + sizeof(struct file_header); + @ requires separation: \separated(&file_hint_a, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_a(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char a_header_debian[14] = { '!','<','a','r','c','h','>','\n','d','e','b','i','a','n'}; + static const char magic[2]= { 0x60, 0x0a}; + const struct file_header *fh=(const struct file_header *)&buffer[8]; + if(memcmp(fh->magic, magic, 2)!=0) + return 0; + /* http://en.wikipedia.org/wiki/Ar_%28Unix%29 */ + reset_file_recovery(file_recovery_new); + if(memcmp(buffer,a_header_debian,sizeof(a_header_debian))==0) + file_recovery_new->extension="deb"; + else + file_recovery_new->extension=file_hint_a.extension; + return 1; +} + +static void register_header_check_a(file_stat_t *file_stat) +{ + static const unsigned char a_header[8] = { '!','<','a','r','c','h','>','\n'}; + register_header_check(0, a_header,sizeof(a_header), &header_check_a, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ab.c b/subprojects/lib/src/file_ab.c new file mode 100644 index 0000000..d710f03 --- /dev/null +++ b/subprojects/lib/src/file_ab.c @@ -0,0 +1,114 @@ +/* + + File: file_addressbook.c + + Copyright (C) 2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_addressbook) +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ab(file_stat_t *file_stat); + +const file_hint_t file_hint_addressbook= { + .extension="ab", + .description="MAC Address Book", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ab +}; + +struct ab_header +{ + char magic[4]; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_addressbook; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + const struct ab_header *ab=(const struct ab_header *)&buffer[i]; + const unsigned int length=be32(ab->size); +#ifdef DEBUG_AB + log_debug("data_check_addressbook i=0x%x buffer_size=0x%x calculated_file_size=%lu file_size=%lu\n", + i, buffer_size, + (long unsigned)file_recovery->calculated_file_size, + (long unsigned)file_recovery->file_size); + dump_log(buffer+i,8); +#endif + if(ab->magic[0]!='L' || ab->magic[1]!='J' || ab->magic[3]!=0x00 || length<8) + return DC_STOP; + file_recovery->calculated_file_size+=length; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct ab_header); + @ requires separation: \separated(&file_hint_addressbook, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ab_header *ab=(const struct ab_header *)buffer; + const unsigned int length=be32(ab->size); + if(ab->magic[0]!='L' || ab->magic[1]!='J' || ab->magic[3]!=0x00 || length<8) + return 0; + if(ab->magic[2]!=0x1a && ab->magic[2]!=0x0a) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_addressbook.extension; + if(file_recovery_new->blocksize >= 8) + { + file_recovery_new->calculated_file_size=length; + file_recovery_new->data_check=&data_check_addressbook; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_ab(file_stat_t *file_stat) +{ + static const unsigned char ab_header[2]={ 'L', 'J' }; + register_header_check(0, ab_header,sizeof(ab_header), &header_check_addressbook, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_abr.c b/subprojects/lib/src/file_abr.c new file mode 100644 index 0000000..0fce242 --- /dev/null +++ b/subprojects/lib/src/file_abr.c @@ -0,0 +1,122 @@ +/* + + File: file_abr.c + + Copyright (C) 2012,2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_abr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_abr(file_stat_t *file_stat); + +struct abr_header +{ + char magic[4]; + char info[4]; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +const file_hint_t file_hint_abr= { + .extension="abr", + .description="Adobe Brush", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_abr +}; + +/*@ + @ requires file_recovery->data_check==&data_check_abr; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_abr(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ assert file_recovery->calculated_file_size <= PHOTOREC_MAX_FILE_SIZE; */ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 12 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 12 ; */ + const struct abr_header *hdr=(const struct abr_header*)&buffer[i]; + /*@ assert \valid_read(hdr); */ + if(memcmp(hdr->magic, "8BIM", 4)!=0) + return DC_STOP; + file_recovery->calculated_file_size+=(uint64_t)12 + be32(hdr->size); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 4 + sizeof(struct abr_header) ; + @ requires separation: \separated(&file_hint_abr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_abr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct abr_header *hdr=(const struct abr_header*)&buffer[4]; + uint64_t i=4; + assert(buffer_size >= 12); + /*@ + @ loop assigns i; + @*/ + while(i < buffer_size - 12 && i < 512 - 12) + { + const struct abr_header *h=(const struct abr_header*)&buffer[i]; + if(memcmp(h->magic, "8BIM", 4)!=0) + return 0; + i+=(uint64_t)12 + be32(h->size); + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_abr.extension; + file_recovery_new->min_filesize=(uint64_t)4+12+be32(hdr->size); + file_recovery_new->calculated_file_size=(uint64_t)4+12+be32(hdr->size); + if(file_recovery_new->blocksize < 12) + return 1; + file_recovery_new->data_check=&data_check_abr; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_abr(file_stat_t *file_stat) +{ + static const unsigned char abr_header[11]= { + 0x00, 0x02, '8' , 'B' , 'I' , 'M' , 's' , 'a' , + 'm' , 'p' , 0x00 + }; + register_header_check(2, abr_header, sizeof(abr_header), &header_check_abr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_acb.c b/subprojects/lib/src/file_acb.c new file mode 100644 index 0000000..33d6597 --- /dev/null +++ b/subprojects/lib/src/file_acb.c @@ -0,0 +1,70 @@ +/* + + File: file_acb.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_acb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_acb(file_stat_t *file_stat); + +const file_hint_t file_hint_acb= { + .extension="acb", + .description="Adobe Color Book", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_acb +}; + +/*@ + @ requires separation: \separated(&file_hint_acb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_acb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_acb.extension; + return 1; +} + +static void register_header_check_acb(file_stat_t *file_stat) +{ + /* http://magnetiq.com/pages/acb-spec/ + * magic: 8BCB + * version: 1 + * identifier 0xB.. */ + static const unsigned char acb_header[7]= { + '8' , 'B' , 'C' , 'B' , 0x00, 0x01, 0x0b + }; + register_header_check(0, acb_header, sizeof(acb_header), &header_check_acb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ace.c b/subprojects/lib/src/file_ace.c new file mode 100644 index 0000000..12be089 --- /dev/null +++ b/subprojects/lib/src/file_ace.c @@ -0,0 +1,234 @@ +/* + + File: file_ace.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ace) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" +#include "crc.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/* #define DEBUG_ACE */ + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_ace(file_stat_t *file_stat); + +const file_hint_t file_hint_ace= { + .extension="ace", + .description="ACE archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ace +}; + +struct header_ace { + uint16_t crc16; /** Lower 16bits of CRC32 over block up from HEAD_TYPE */ + uint16_t size; /** Size of the block from HEAD_TYPE + up to the beginning of the ADDSIZE block */ + uint8_t type; /** indicates type of block */ + uint16_t flags; /** flags related to the block and its content + for all blocks these flags are valid. + bit 0 indicates if field add size is preset */ + uint32_t addsize; /** an optional field which represents the size of + an additional block without specified structure */ +} __attribute__ ((gcc_struct, __packed__)); + +typedef struct header_ace ace_header_t; +#define BUF_SIZE 4096 + +/*@ + @ requires \valid(handle); + @ requires \separated(handle, &errno, &Frama_C_entropy_source); + @ assigns *handle, errno; + @ assigns Frama_C_entropy_source; + @*/ +static int check_ace_crc(FILE *handle, const unsigned int len, const unsigned int crc32_low) +{ + char buffer[BUF_SIZE]; + uint32_t crc32=0xFFFFFFFF; + unsigned int remaining=len; + /*@ + @ loop assigns *handle, errno; + @ loop assigns Frama_C_entropy_source; + @ loop assigns buffer[0 .. BUF_SIZE-1], crc32, remaining; + @*/ + while (remaining>0) + { + const unsigned int count = ((remaining>BUF_SIZE) ? BUF_SIZE : remaining); + if(fread(buffer, 1, count, handle) != count) + { +#ifdef DEBUG_ACE + log_info("file_ace: truncated file\n"); +#endif + return 1; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + crc32=get_crc32(buffer, count, crc32); + remaining -= count; + } + if (crc32_low != (crc32&0xFFFF)) + { +#ifdef DEBUG_ACE + log_info("file_ace: bad CRC: %04X vs %04X\n", crc32_low, crc32&0xFFFF); +#endif + return 1; + } + return 0; +} + +/*@ + @ requires file_recovery->file_check == &file_check_ace; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size, file_recovery->offset_error, file_recovery->offset_ok; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_ace(file_recovery_t *file_recovery) +{ + file_recovery->offset_error = 0; + file_recovery->offset_ok = 0; + file_recovery->file_size = 0; + if(my_fseek(file_recovery->handle, 0, SEEK_SET)<0) + return ; + /*@ + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size, file_recovery->offset_error; + @ loop assigns Frama_C_entropy_source; + @*/ + while (!feof(file_recovery->handle)) + { + char buffer[sizeof(ace_header_t)]; + const ace_header_t *h=(const ace_header_t *)&buffer; + if(fread(&buffer, sizeof(buffer), 1, file_recovery->handle)!= 1) + { + return ; + } + /*@ assert \initialized(&buffer + (0 .. sizeof(buffer)-1)); */ +#ifdef DEBUG_ACE + log_info("file_ace: Block header at 0x%08lx: CRC16=0x%04X size=%u type=%u" + " flags=0x%04X addsize=%u\n", + (long unsigned) file_recovery->file_size, + le16(h->crc16), le16(h->size), h->type, le16(h->flags), + (le16(h->flags)&1) ? le32(h->addsize):0); +#endif + /* Type 0=Archive header, 1=File block, 2=Recovery Record, 5 new_recovery ? */ + if (h->type==0 && le16(h->size)==0) + { + return ; + } + if (h->type!=0 && h->type!=1 && h->type!=2 && h->type!=5) + { +#ifdef DEBUG_ACE + log_info("file_ace: Invalid block type %u\n", h->type); +#endif + return ; + } + + /* Minimal size is type+flags */ + if (le16(h->size) < 1U + 2U) + { +#ifdef DEBUG_ACE + log_info("file_ace: Invalid block size %u\n", le16(h->size)); +#endif + return ; + } + + if(my_fseek(file_recovery->handle, -(off_t)sizeof(ace_header_t)+(off_t)4, SEEK_CUR)<0 || + check_ace_crc(file_recovery->handle, le16(h->size), le16(h->crc16)) != 0) + { + file_recovery->offset_error=file_recovery->file_size; + file_recovery->file_size=0; + return ; + } + + /* Add its header size */ + file_recovery->file_size += (uint64_t)4 + le16(h->size); /* +2: CRC16, +2: size */ + + if(file_recovery->file_size >= 0x8000000000000000-0x100000000) + { + file_recovery->file_size=0; + return ; + } + /* If addsize flag, add complementary size */ + if (le16(h->flags)&1) + { + file_recovery->file_size += le32(h->addsize); + if(my_fseek(file_recovery->handle, file_recovery->file_size, SEEK_SET)<0) + { + file_recovery->offset_error=file_recovery->file_size; + file_recovery->file_size=0; + return; + } + } + } +} + +/*@ + @ requires buffer_size >= sizeof(ace_header_t); + @ requires separation: \separated(&file_hint_ace, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_ace.extension); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_ace); + @ assigns *file_recovery_new; + @*/ +static int header_check_ace(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const ace_header_t *h=(const ace_header_t *)buffer; + if(le16(h->size) < 1+2 || h->type!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ace.extension; + file_recovery_new->min_filesize= + 2 + /* CRC16 */ + 2 + /* Head size */ + 1 + /* Head type */ + 2 + /* Flags */ + 7 + /* Signature */ + 16; /* Minimal size for marker header */ + file_recovery_new->file_check=&file_check_ace; + return 1; +} + +static void register_header_check_ace(file_stat_t *file_stat) +{ + static const unsigned char ace_header[7] = { '*','*','A','C','E','*','*'}; + register_header_check(7, ace_header,sizeof(ace_header), &header_check_ace, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ado.c b/subprojects/lib/src/file_ado.c new file mode 100644 index 0000000..8aea039 --- /dev/null +++ b/subprojects/lib/src/file_ado.c @@ -0,0 +1,66 @@ +/* + + File: file_ado.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ado) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ado(file_stat_t *file_stat); + +const file_hint_t file_hint_ado= { + .extension="ado", + .description="Adobe Duotone Options", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ado +}; + +/*@ + @ requires buffer_size >= 2; + @ requires separation: \separated(&file_hint_ado, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ado(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]!=0 || buffer[1]!=1) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ado.extension; + return 1; +} + +static void register_header_check_ado(file_stat_t *file_stat) +{ + register_header_check(0x2c, "\5Black\0\0", 8, &header_check_ado, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_afdesign.c b/subprojects/lib/src/file_afdesign.c new file mode 100644 index 0000000..0c465f8 --- /dev/null +++ b/subprojects/lib/src/file_afdesign.c @@ -0,0 +1,88 @@ +/* + + File: file_afdesign.c + + Copyright (C) 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_afdesign) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_afdesign(file_stat_t *file_stat); + +const file_hint_t file_hint_afdesign= { + .extension="afdesign", + .description="afdesign", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_afdesign +}; + +/* http://nickbeeuwsaert.github.io/AFDesignLoad/file_format.html */ +struct afdesign_header +{ + uint32_t signature; + uint32_t version; + char prsn[4]; + char info[4]; + uint64_t fat_offset; + uint64_t fat_length; + uint64_t zlib_length; + uint64_t unused1; + uint32_t creation; + uint32_t unused2; + uint64_t fat_entries; + uint64_t fil_entries; +}; + +/*@ + @ requires buffer_size >= sizeof(struct afdesign_header); + @ requires separation: \separated(&file_hint_afdesign, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_afdesign(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct afdesign_header *hdr=(const struct afdesign_header*)buffer; + if(memcmp(hdr->prsn, "nsrP", 4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_afdesign.extension; + file_recovery_new->min_filesize=le64(hdr->zlib_length); + return 1; +} + +static void register_header_check_afdesign(file_stat_t *file_stat) +{ + static const unsigned char afdesign_header[4]= { 0x00, 0xff, 'K' , 'A' }; + register_header_check(0, afdesign_header, sizeof(afdesign_header), &header_check_afdesign, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ahn.c b/subprojects/lib/src/file_ahn.c new file mode 100644 index 0000000..01c6cc5 --- /dev/null +++ b/subprojects/lib/src/file_ahn.c @@ -0,0 +1,68 @@ +/* + + File: file_ahn.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ahn) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ahn(file_stat_t *file_stat); + +const file_hint_t file_hint_ahn= { + .extension="ahn", + .description="Ahnenblatt", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ahn +}; + +/*@ + @ requires buffer_size >= 4; + @ requires separation: \separated(&file_hint_ahn, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ahn(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char ahn_header[4] = {'d','b','f',0x00}; + if(memcmp(buffer, ahn_header, sizeof(ahn_header))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ahn.extension; + return 1; +} + +static void register_header_check_ahn(file_stat_t *file_stat) +{ + static const unsigned char ahn_magic[10] = {'A','H','N','E','N','B','L','A','T','T'}; + register_header_check(8, ahn_magic, sizeof(ahn_magic), &header_check_ahn, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_aif.c b/subprojects/lib/src/file_aif.c new file mode 100644 index 0000000..442405d --- /dev/null +++ b/subprojects/lib/src/file_aif.c @@ -0,0 +1,91 @@ +/* + + File: file_aif.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_aif) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_aif(file_stat_t *file_stat); + +const file_hint_t file_hint_aif= { + .extension="aif", + .description="Audio Interchange File Format", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_aif +}; + +struct aif_header +{ + char ckID[4]; + uint32_t ckSize; + char formType[4]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_aif, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_aif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct aif_header *hdr=(const struct aif_header *)buffer; + if(be32(hdr->ckSize)<4) + return 0; + if(buffer[8]=='A' && buffer[9]=='I' && buffer[10]=='F' && (buffer[11]=='F' || buffer[11]=='C')) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_aif.extension; + file_recovery_new->calculated_file_size=(uint64_t)be32(hdr->ckSize)+8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + if(memcmp(&buffer[8], "ILBMBMHD", 8)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="iff"; + file_recovery_new->calculated_file_size=(uint64_t)be32(hdr->ckSize)+8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_aif(file_stat_t *file_stat) +{ + register_header_check(0, "FORM", 4, &header_check_aif, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_all.c b/subprojects/lib/src/file_all.c new file mode 100644 index 0000000..ae44a08 --- /dev/null +++ b/subprojects/lib/src/file_all.c @@ -0,0 +1,66 @@ +/* + + File: file_all.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_all) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_all(file_stat_t *file_stat); + +const file_hint_t file_hint_all= { + .extension="all", + .description="Cubase Song file: .all", + .max_filesize=50*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_all +}; + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_all, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_all(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=122; + file_recovery_new->extension=file_hint_all.extension; + return 1; +} + +static void register_header_check_all(file_stat_t *file_stat) +{ + static const unsigned char all_header[8]= { 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x06, 0x04}; + register_header_check(0, all_header,sizeof(all_header), &header_check_all, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_als.c b/subprojects/lib/src/file_als.c new file mode 100644 index 0000000..0b46083 --- /dev/null +++ b/subprojects/lib/src/file_als.c @@ -0,0 +1,96 @@ +/* + + File: file_als.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_als) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_als(file_stat_t *file_stat); + +const file_hint_t file_hint_als= { + .extension="als", + .description="Ableton Live Sets", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_als +}; + +/*@ + @ requires file_recovery->file_check == &file_check_als; + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_als(file_recovery_t *file_recovery) +{ + static const unsigned char als_footer[0x16]= { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x01 + }; + file_search_footer(file_recovery, als_footer, sizeof(als_footer), 7); +} + +/*@ + @ requires buffer_size >= 11+13; + @ requires separation: \separated(&file_hint_als, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_als(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char als_header2[13]= { + 0x0c, 'L', 'i', 'v', 'e', 'D', 'o', 'c', + 'u', 'm', 'e', 'n', 't' + }; + if(memcmp(buffer+11,als_header2,sizeof(als_header2))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_als.extension; + file_recovery_new->file_check=&file_check_als; + return 1; +} + +/* Header + * 0000 ab 1e 56 78 03 XX 00 00 00 00 XX 0c 4c 69 76 65 | Vx Live| + * 0010 44 6f 63 75 6d 65 6e 74 XX 00 00 00 00 XX XX XX |Document | + */ +static void register_header_check_als(file_stat_t *file_stat) +{ + static const unsigned char als_header[5]= { + 0xab, 0x1e, 'V', 'x', 0x03 + }; + register_header_check(0, als_header,sizeof(als_header), &header_check_als, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_amd.c b/subprojects/lib/src/file_amd.c new file mode 100644 index 0000000..97e378e --- /dev/null +++ b/subprojects/lib/src/file_amd.c @@ -0,0 +1,101 @@ +/* + + File: file_amd.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_amd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_amd(file_stat_t *file_stat); + +const file_hint_t file_hint_amd= { + .extension="amd", + .description="AlphaCAM (amd/amt/atd/att)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_amd +}; + +/*@ + @ requires buffer_size >= 20; + @ requires separation: \separated(&file_hint_amd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_amd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + /* FIXME: I don't think it's a valid way to distinguish between files */ + if(buffer[16]=='1' && buffer[17]=='.' && buffer[18]=='1' && buffer[19]=='9') + file_recovery_new->extension="atd"; + else + file_recovery_new->extension=file_hint_amd.extension; + return 1; +} + +/*@ + @ requires buffer_size >= 25; + @ requires separation: \separated(&file_hint_amd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_amt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + /* FIXME: I don't think it's a valid way to distinguish between files */ + if(buffer[21]=='1' && buffer[22]=='.' && buffer[23]=='0' && buffer[24]=='8') + file_recovery_new->extension="att"; + else + file_recovery_new->extension="amt"; + return 1; +} + +static void register_header_check_amd(file_stat_t *file_stat) +{ + /* amd 1.36 + * atd 1.19 */ + static const unsigned char amd_header[16]={ + 'L', 'i', 'c', 'o', 'm', '-', 'A', 'P', + 'S', ' ', 'F', 'i', 'l', 'e', ' ', 'V' }; + + /* amt 1.19 + * att 1.08 */ + static const unsigned char amt_header[20]={ + 'L', 'i', 'c', 'o', 'm', '-', 'A', 'P', + 'S', ' ', 'T', 'o', 'o', 'l', ' ', 'F', + 'i', 'l', 'e', ' '}; + + register_header_check(0, amd_header,sizeof(amd_header), &header_check_amd, file_stat); + register_header_check(0, amt_header,sizeof(amt_header), &header_check_amt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_amr.c b/subprojects/lib/src/file_amr.c new file mode 100644 index 0000000..be4e92a --- /dev/null +++ b/subprojects/lib/src/file_amr.c @@ -0,0 +1,112 @@ +/* + + File: file_amr.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_amr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_amr(file_stat_t *file_stat); + +const file_hint_t file_hint_amr= { + .extension="amr", + .description="Adaptive Multi-Rate", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_amr +}; + +/*@ + @ requires file_recovery->data_check==&data_check_amr; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_amr(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4; */ +#ifdef DEBUG_AMR + log_info("data_check_amr %04x %02x %u\n", file_recovery->calculated_file_size, buffer[i], (buffer[i]>>1)&7); +#endif + if((buffer[i]&0x83)!=0) + return DC_STOP; + if(buffer[i]==0 && buffer[i+1]==0 && buffer[i+2]==0 && buffer[i+3]==0) + return DC_STOP; + switch((buffer[i]>>3)&0x7) + { + case 0: file_recovery->calculated_file_size+=13; break; + case 1: file_recovery->calculated_file_size+=14; break; + case 2: file_recovery->calculated_file_size+=16; break; + case 3: file_recovery->calculated_file_size+=18; break; + case 4: file_recovery->calculated_file_size+=20; break; + case 5: file_recovery->calculated_file_size+=21; break; + case 6: file_recovery->calculated_file_size+=27; break; + case 7: file_recovery->calculated_file_size+=32; break; + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_amr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_amr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if((buffer[6]&0x83)!=0) + return 0; + if(buffer[6]==0 && buffer[6+1]==0 && buffer[6+2]==0 && buffer[6+3]==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=6; + file_recovery_new->data_check=&data_check_amr; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->extension=file_hint_amr.extension; + return 1; +} + +/* AMR file format is described in https://tools.ietf.org/html/rfc3267 */ +static void register_header_check_amr(file_stat_t *file_stat) +{ + static const unsigned char amr_header[6]= {'#','!','A','M','R','\n'}; + register_header_check(0, amr_header,sizeof(amr_header), &header_check_amr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_apa.c b/subprojects/lib/src/file_apa.c new file mode 100644 index 0000000..2d3d86d --- /dev/null +++ b/subprojects/lib/src/file_apa.c @@ -0,0 +1,69 @@ +/* + + File: file_apa.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_apa) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_apa(file_stat_t *file_stat); + +const file_hint_t file_hint_apa= { + .extension="apa", + .description="APA Style Helper", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_apa +}; + +/*@ + @ requires buffer_size >= 11+13; + @ requires separation: \separated(&file_hint_apa, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_apa(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_apa.extension; + return 1; +} + +static void register_header_check_apa(file_stat_t *file_stat) +{ + static const unsigned char apa_magic[16]= { + 'c', 'o', 'm', '.', 'a', 'p', 'a', '.', + 'D', 'o', 'c', 'u', 'm', 'e', 'n', 't'}; + register_header_check(8, apa_magic, sizeof(apa_magic), &header_check_apa, file_stat); +} + +#endif diff --git a/subprojects/lib/src/file_ape.c b/subprojects/lib/src/file_ape.c new file mode 100644 index 0000000..f5a5ff0 --- /dev/null +++ b/subprojects/lib/src/file_ape.c @@ -0,0 +1,153 @@ +/* + + File: file_ape.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ape) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ape(file_stat_t *file_stat); + +const file_hint_t file_hint_ape= { + .extension="ape", + .description="Monkey's Audio compressed format", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ape +}; + + +/* cf https://github.com/fernandotcl/monkeys-audio/blob/master/src/MACLib/APEHeader.h */ +struct APE_COMMON_HEADER +{ + char cID[4]; /* should equal 'MAC ' */ + uint16_t nVersion; /* version number * 1000 (3.81 = 3810) */ +}; + +/***************************************************************************************** + * APE header structure for old APE files (3.97 and earlier) + * *****************************************************************************************/ +struct APE_HEADER_OLD +{ + char cID[4]; // should equal 'MAC ' + uint16_t nVersion; // version number * 1000 (3.81 = 3810) + uint16_t nCompressionLevel; // the compression level + uint16_t nFormatFlags; // any format flags (for future use) + uint16_t nChannels; // the number of channels (1 or 2) + uint32_t nSampleRate; // the sample rate (typically 44100) + uint32_t nHeaderBytes; // the bytes after the MAC header that compose the WAV header + uint32_t nTerminatingBytes; // the bytes after that raw data (for extended info) + uint32_t nTotalFrames; // the number of frames in the file + uint32_t nFinalFrameBlocks; // the number of samples in the final frame +}; + +/***************************************************************************************** + * APE_DESCRIPTOR structure (file header that describes lengths, offsets, etc.) + * *****************************************************************************************/ +struct APE_DESCRIPTOR +{ + char cID[4]; // should equal 'MAC ' + uint16_t nVersion; // version number * 1000 (3.81 = 3810) + uint16_t pack1; + uint32_t nDescriptorBytes; // the number of descriptor bytes (allows later expansion of this header) + uint32_t nHeaderBytes; // the number of header APE_HEADER bytes + uint32_t nSeekTableBytes; // the number of bytes of the seek table + uint32_t nHeaderDataBytes; // the number of header data bytes (from original file) + uint64_t nAPEFrameDataBytes; // the number of bytes of APE frame data + uint32_t nTerminatingDataBytes; // the terminating data of the file (not including tag data) + uint8_t cFileMD5[16]; // the MD5 hash of the file (see notes for usage... it's a littly tricky) +} __attribute__ ((gcc_struct, __packed__)); + +/***************************************************************************************** + * APE_HEADER structure (describes the format, duration, etc. of the APE file) + * *****************************************************************************************/ +struct APE_HEADER +{ + uint16_t nCompressionLevel; // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST) + uint16_t nFormatFlags; // any format flags (for future use) + uint32_t nBlocksPerFrame; // the number of audio blocks in one frame + uint32_t nFinalFrameBlocks; // the number of audio blocks in the final frame + uint32_t nTotalFrames; // the total number of frames + uint16_t nBitsPerSample; // the bits per sample (typically 16) + uint16_t nChannels; // the number of channels (1 or 2) + uint32_t nSampleRate; // the sample rate (typically 44100) +}; + +/*@ + @ requires buffer_size >= sizeof(struct APE_HEADER_OLD); + @ requires separation: \separated(&file_hint_ape, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ape(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct APE_HEADER_OLD *ape=(const struct APE_HEADER_OLD*)buffer; + /* Version 3.96 released April 7, 2002, Version 4.06 March 17, 2009 */ + if(le16(ape->nVersion)>=3980) + { + const struct APE_DESCRIPTOR *descr=(const struct APE_DESCRIPTOR*)buffer; + const unsigned int nDescriptorBytes=le32(descr->nDescriptorBytes); + if(nDescriptorBytes < sizeof(struct APE_DESCRIPTOR)) + return 0; + if(le32(descr->nHeaderDataBytes) > 0 && le32(descr->nHeaderDataBytes) < sizeof(struct APE_HEADER)) + return 0; + if(nDescriptorBytes >= buffer_size) + return 0; + if(nDescriptorBytes + sizeof(struct APE_HEADER) >= buffer_size) + return 0; + { + const struct APE_HEADER *apeh=(const struct APE_HEADER*)&buffer[nDescriptorBytes]; + /*@ assert \valid_read(apeh); */ + if(le16(apeh->nChannels)<1 || le16(apeh->nChannels)>2) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ape.extension; + return 1; + } + if(le16(ape->nChannels)<1 || le16(ape->nChannels)>2) + return 0; + if(le32(ape->nSampleRate)==0) + return 0; + if(le32(ape->nTotalFrames)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ape.extension; + /* 4 + le32(ape->nHeaderBytes) + le32(ape->nTerminatingDataBytes) ? */ + return 1; +} + +static void register_header_check_ape(file_stat_t *file_stat) +{ + static const unsigned char ape_header[4]= { 'M', 'A', 'C', ' '}; + register_header_check(0, ape_header,sizeof(ape_header), &header_check_ape, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_apple.c b/subprojects/lib/src/file_apple.c new file mode 100644 index 0000000..baa45b6 --- /dev/null +++ b/subprojects/lib/src/file_apple.c @@ -0,0 +1,65 @@ +/* + + File: file_apple.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_apple) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_apple(file_stat_t *file_stat); + +const file_hint_t file_hint_apple= { + .extension="apple", + .description="AppleSingle/AppleDouble", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_apple +}; + +/*@ + @ requires separation: \separated(&file_hint_apple, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_apple(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_apple.extension; + return 1; +} + +static void register_header_check_apple(file_stat_t *file_stat) +{ + static const unsigned char apple_header[8]= { + 0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00 + }; + register_header_check(0, apple_header,sizeof(apple_header), &header_check_apple, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ari.c b/subprojects/lib/src/file_ari.c new file mode 100644 index 0000000..3b1f2d6 --- /dev/null +++ b/subprojects/lib/src/file_ari.c @@ -0,0 +1,86 @@ +/* + + File: file_ari.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ari) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ari(file_stat_t *file_stat); + +const file_hint_t file_hint_ari= { + .extension="ari", + .description="ARRI Raw Video", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ari +}; + +struct arri_header +{ + uint32_t magic; + uint32_t endian; + uint32_t header_size; + uint32_t version; /* ie. 3 */ + uint32_t unk1; + uint32_t width; + uint32_t height; + uint32_t cam_hwr_rev; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size > sizeof(struct arri_header); + @ requires separation: \separated(&file_hint_ari, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ari(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct arri_header *hdr=(const struct arri_header *)buffer; + if(le32(hdr->version)==0 || + le32(hdr->width)==0 || + le32(hdr->height)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ari.extension; + file_recovery_new->min_filesize=4096; + return 1; +} + +static void register_header_check_ari(file_stat_t *file_stat) +{ + static const unsigned char ari_header[12]= { + 'A' , 'R' , 'R' , 'I' , 0x12, 0x34, 0x56, 0x78, + 0x00, 0x10, 0x00, 0x00}; + register_header_check(0, ari_header, sizeof(ari_header), &header_check_ari, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_arj.c b/subprojects/lib/src/file_arj.c new file mode 100644 index 0000000..2e13a8b --- /dev/null +++ b/subprojects/lib/src/file_arj.c @@ -0,0 +1,181 @@ +/* + + File: file_arj.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_arj) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_arj(file_stat_t *file_stat); + +const file_hint_t file_hint_arj= { + .extension="arj", + .description="ARJ archive", + .max_filesize=PHOTOREC_MAX_SIZE_32, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_arj +}; + +/* + * 60 ea 24 00 22 0b 01 02 10 00 02 XX XX XX 50 48 + * ID HS FH V V OS FL SV FT R DATE/TIME + * + * Extract from "ARJ TECHNICAL INFORMATION April 1993" + http://datacompression.info/ArchiveFormats/arj.txt + Structure of main header (low order byte first): + + Bytes Description +------------------------------------------------------------------- + 2 header id (main and local file) = 0x60 0xEA + 2 basic header size (from 'first_hdr_size' thru 'comment' below) + = first_hdr_size + strlen(filename) + 1 + strlen(comment) + 1 + = 0 if end of archive + maximum header size is 2600 + + 1 first_hdr_size (size up to and including 'extra data') + 1 archiver version number + 1 minimum archiver version to extract + 1 host OS (0 = MSDOS, 1 = PRIMOS, 2 = UNIX, 3 = AMIGA, 4 = MAC-OS) + (5 = OS/2, 6 = APPLE GS, 7 = ATARI ST, 8 = NEXT) + (9 = VAX VMS) + 1 arj flags + (0x01 = NOT USED) + (0x02 = OLD_SECURED_FLAG) + (0x04 = VOLUME_FLAG) indicates presence of succeeding + volume + (0x08 = NOT USED) + (0x10 = PATHSYM_FLAG) indicates archive name translated + ("\" changed to "/") + (0x20 = BACKUP_FLAG) indicates backup type archive + (0x40 = SECURED_FLAG) + 1 security version (2 = current) + 1 file type (must equal 2) + 1 reserved + 4 date time when original archive was created + 4 date time when archive was last modified + 4 archive size (currently used only for secured archives) + 4 security envelope file position + 2 filespec position in filename + 2 length in bytes of security envelope data + 2 (currently not used) + ? (currently none) + + ? filename of archive when created (null-terminated string) + ? archive comment (null-terminated string) + + 4 basic header CRC + + 2 1st extended header size (0 if none) + ? 1st extended header (currently not used) + 4 1st extended header's CRC (not present when 0 extended header size) + */ +struct arj_main_header { + uint16_t header_id; + uint16_t basic_header_size; + uint8_t first_header_size; + uint8_t archiver_ver; + uint8_t archiver_ver_min; + uint8_t host_os; + uint8_t flags; + uint8_t security_ver; + uint8_t file_type; + uint8_t reserved; + uint32_t ctime; + uint32_t mtime; + uint32_t size; + uint32_t security_env_pos; + uint16_t filespec_pos; + uint16_t security_env_size; + uint16_t unused; + char filename; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_arj; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_arj(file_recovery_t *file_recovery) +{ + static const unsigned char arj_footer[4]={0x60, 0xEA, 0x00, 0x00 }; + file_search_footer(file_recovery, arj_footer, sizeof(arj_footer), 0); +} + +/*@ + @ requires buffer_size >= sizeof(struct arj_main_header); + @ requires separation: \separated(&file_hint_arj, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_arj(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct arj_main_header *arj=(const struct arj_main_header*)buffer; + if(le16(arj->basic_header_size) > 0 && + le16(arj->basic_header_size) <= 2600 && + arj->archiver_ver_min <= arj->archiver_ver && + arj->archiver_ver <=12 && + (arj->flags&0x01)==0 && + arj->file_type==2) + { + if((arj->flags&0x040)!=0) + { + if(le32(arj->size) < sizeof(struct arj_main_header)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=le32(arj->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + else + { +// if(le32(arj->size)!=0) +// return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_arj; + } + file_recovery_new->extension=file_hint_arj.extension; + file_recovery_new->time=le32(arj->ctime); + if(file_recovery_new->time < le32(arj->mtime)) + file_recovery_new->time=le32(arj->mtime); + return 1; + } + return 0; +} + +static void register_header_check_arj(file_stat_t *file_stat) +{ + static const unsigned char arj_header[2]={0x60, 0xEA}; + register_header_check(0, arj_header,sizeof(arj_header), &header_check_arj, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_asf.c b/subprojects/lib/src/file_asf.c new file mode 100644 index 0000000..5dcb578 --- /dev/null +++ b/subprojects/lib/src/file_asf.c @@ -0,0 +1,172 @@ +/* + + File: file_asf.c + + Copyright (C) 1998-2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asf) +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_asf(file_stat_t *file_stat); + +const file_hint_t file_hint_asf= { + .extension="asf", + .description="ASF, WMA, WMV: Advanced Streaming Format used for Audio/Video", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_asf +}; + +struct asf_header_obj_s { + unsigned char object_id[16]; + uint64_t object_size; + uint32_t nbr_header_obj; + char reserved1; /* 1 */ + char reserved2; /* 2 */ +} __attribute__ ((gcc_struct, __packed__)); + +struct asf_file_prop_s { + unsigned char object_id[16]; + uint64_t object_size; + unsigned char file_id[16]; + uint64_t file_size; + int64_t file_date; +} __attribute__ ((gcc_struct, __packed__)); + +struct asf_stream_prop_s { + unsigned char object_id[16]; + uint64_t object_size; + unsigned char stream_type[16]; +} __attribute__ ((gcc_struct, __packed__)); + +static const char *extension_wma="wma"; +static const char *extension_wmv="wmv"; + +/*@ + @ requires buffer_size > sizeof(struct asf_header_obj_s); + @ requires separation: \separated(&file_hint_asf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_asf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct asf_header_obj_s *hdr=(const struct asf_header_obj_s*)buffer; + const char *extension=file_hint_asf.extension; + const unsigned int nbr_header_obj=le32(hdr->nbr_header_obj); + uint64_t size=0; + time_t time=0; + unsigned int i; + uint64_t offset_prop=sizeof(struct asf_header_obj_s); + /* Header + File Properties + Stream Properties + Header Extension */ + if(le64(hdr->object_size)<30 || + le64(hdr->object_size) >= PHOTOREC_MAX_FILE_SIZE || + nbr_header_obj<4) + return 0; + /*@ + @ loop assigns extension, i, size, time, offset_prop; + @*/ + for(i=0; + i < nbr_header_obj && offset_prop + 0x28 < buffer_size; + i++) + { + const struct asf_file_prop_s *prop=(const struct asf_file_prop_s*)&buffer[offset_prop]; + const uint64_t object_size=le64(prop->object_size); + // ASF_File_Properties_Object // 8CABDCA1-A947-11CF-8EE4-00C00C205365 + // ASF_Stream_Properties_Object // B7DC0791-A9B7-11CF-8EE6-00C00C205365 + static const unsigned char asf_file_prop_id[16]= { + 0xa1, 0xdc, 0xab, 0x8c, 0x47, 0xa9, 0xcf, 0x11, + 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 + }; + static const unsigned char asf_stream_prop_s[16]= { + 0x91, 0x07, 0xdc, 0xb7, 0xb7, 0xa9, 0xcf, 0x11, + 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 + }; + if(object_size < 0x18) + { +#ifndef __FRAMAC__ + log_info("header_check_asf object_size too small %llu\n", (long long unsigned)object_size); +#endif + return 0; + } + if(object_size > 0x8000000000000000) + return 0; + if(memcmp(prop->object_id, asf_file_prop_id, sizeof(asf_file_prop_id))==0) + { + if(object_size < 0x28) + return 0; + size=le64(prop->file_size); + if(size < sizeof(struct asf_header_obj_s) + sizeof(struct asf_file_prop_s)) + return 0; + time=td_ntfs2utc(le64(prop->file_date)); + } + else if(memcmp(prop->object_id, asf_stream_prop_s, sizeof(asf_stream_prop_s))==0) + { + const struct asf_stream_prop_s *stream=(const struct asf_stream_prop_s *)prop; + const unsigned char wma[16]={ + 0x40, 0x9e, 0x69, 0xf8, 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b + }; + const unsigned char wmv[16]={ + 0xc0, 0xef, 0x19, 0xbc, 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b + }; + if(object_size < 0x28) + return 0; + if(memcmp(stream->stream_type, wma, sizeof(wma))==0) + extension=extension_wma; + else if(memcmp(stream->stream_type, wmv, sizeof(wmv))==0) + extension=extension_wmv; + } + offset_prop+=object_size; + } + if(size > 0 && size < offset_prop) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension; + file_recovery_new->min_filesize=offset_prop; + file_recovery_new->time=time; + if(size > 0) + { + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_asf(file_stat_t *file_stat) +{ + static const unsigned char asf_header[16]= { + 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11, + 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c + }; + register_header_check(0, asf_header,sizeof(asf_header), &header_check_asf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_asl.c b/subprojects/lib/src/file_asl.c new file mode 100644 index 0000000..ae2b6a1 --- /dev/null +++ b/subprojects/lib/src/file_asl.c @@ -0,0 +1,67 @@ +/* + + File: file_asl.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asl) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_asl(file_stat_t *file_stat); + +const file_hint_t file_hint_asl= { + .extension="asl", + .description="Adobe Layer Style", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_asl +}; + +/*@ + @ requires separation: \separated(&file_hint_asl, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_asl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_asl.extension; + return 1; +} + +static void register_header_check_asl(file_stat_t *file_stat) +{ + static const unsigned char asl_header[9]= { + 0x00, 0x02, '8' , 'B' , 'S' , 'L' , 0x00, 0x03, + 0x00 + }; + register_header_check(0, asl_header, sizeof(asl_header), &header_check_asl, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_asm.c b/subprojects/lib/src/file_asm.c new file mode 100644 index 0000000..d1307c8 --- /dev/null +++ b/subprojects/lib/src/file_asm.c @@ -0,0 +1,86 @@ +/* + + File: file_asm.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_asm(file_stat_t *file_stat); + +const file_hint_t file_hint_asm= { + .extension="asm", + .description="Pro/ENGINEER Assembly", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_asm +}; + +/*@ + @ requires file_recovery->file_check == &file_check_asm; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_asm(file_recovery_t *file_recovery) +{ + const unsigned char asm_footer[11]= { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C'}; + file_search_footer(file_recovery, asm_footer, sizeof(asm_footer), 1); +} + +/*@ + @ requires buffer_size > 20; + @ requires separation: \separated(&file_hint_asm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_asm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[16]) || !isprint(buffer[17]) || !isprint(buffer[18]) || !isprint(buffer[19])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_asm; + file_recovery_new->extension=file_hint_asm.extension; + return 1; +} + +static void register_header_check_asm(file_stat_t *file_stat) +{ + static const unsigned char asm_header[16]= { + '#', 'U', 'G', 'C', ':', '2', ' ', 'A', + 'S', 'S', 'E', 'M', 'B', 'L', 'Y', ' '}; + register_header_check(0, asm_header,sizeof(asm_header), &header_check_asm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_atd.c b/subprojects/lib/src/file_atd.c new file mode 100644 index 0000000..ef06469 --- /dev/null +++ b/subprojects/lib/src/file_atd.c @@ -0,0 +1,66 @@ +/* + + File: file_atd.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_atd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_atd(file_stat_t *file_stat); + +const file_hint_t file_hint_atd= { + .extension="atd", + .description="Agelong Tree Database/Abs0luteDatabase", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_atd +}; + +/*@ + @ requires separation: \separated(&file_hint_atd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_atd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_atd.extension; + return 1; +} + +static void register_header_check_atd(file_stat_t *file_stat) +{ + static const unsigned char atd_header[16]= { + 'A' ,'B' ,'S' ,'0' ,'L' ,'U' ,'T' ,'E' , + 'D' ,'A' ,'T' ,'A' ,'B' ,'A' ,'S' ,'E' }; + register_header_check(0, atd_header,sizeof(atd_header), &header_check_atd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_au.c b/subprojects/lib/src/file_au.c new file mode 100644 index 0000000..3d5f270 --- /dev/null +++ b/subprojects/lib/src/file_au.c @@ -0,0 +1,100 @@ +/* + + File: file_au.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_au) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_au(file_stat_t *file_stat); + +const file_hint_t file_hint_au= { + .extension="au", + .description="Sun/NeXT audio data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_au +}; + +/* http://en.wikipedia.org/wiki/Au_file_format */ +struct header_au_s +{ + uint32_t magic; + uint32_t offset; + uint32_t size; + uint32_t encoding; + uint32_t sample_rate; + uint32_t channels; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size > sizeof(struct header_au_s); + @ requires separation: \separated(&file_hint_au, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_au(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct header_au_s *au=(const struct header_au_s *)buffer; + const unsigned int offset=be32(au->offset); + const unsigned int size=be32(au->size); + if(offset >= sizeof(struct header_au_s) && + be32(au->encoding)>0 && be32(au->encoding)<=27 && + be32(au->channels)>0 && be32(au->channels)<=256) + { + if(size!=0xffffffff) + { + const uint64_t cfs=(uint64_t)offset + size; + if(cfs < 111) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=111; + file_recovery_new->extension=file_hint_au.extension; + file_recovery_new->calculated_file_size=cfs; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=111; + file_recovery_new->extension=file_hint_au.extension; + return 1; + } + return 0; +} + +static void register_header_check_au(file_stat_t *file_stat) +{ + static const unsigned char au_header[4]= {'.','s','n','d'}; + register_header_check(0, au_header,sizeof(au_header), &header_check_au, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_axp.c b/subprojects/lib/src/file_axp.c new file mode 100644 index 0000000..0cb0a15 --- /dev/null +++ b/subprojects/lib/src/file_axp.c @@ -0,0 +1,131 @@ +/* + + File: file_axp.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_axp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_axp(file_stat_t *file_stat); + +const file_hint_t file_hint_axp= { + .extension="axp", + .description="Pinnacle Studio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_axp +}; + +const unsigned char axp_footer[34]= { + '<', 0, '/', 0, 'V', 0, 'F', 0, + 'N', 0, 'G', 0, 'D', 0, 'o', 0, + 'c', 0, 'u', 0, 'm', 0, 'e', 0, + 'n', 0, 't', 0, '>', 0, 0x0d, 0, + 0x0a, 0 +}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_axp(file_recovery_t *file_recovery) +{ + file_search_footer(file_recovery, axp_footer, sizeof(axp_footer), 1); +} + +/*@ + @ requires file_recovery->data_check==&data_check_axp; + @ requires buffer_size >= 2*sizeof(axp_footer); + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_axp(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + unsigned int j; + /*@ + @ loop assigns j, file_recovery->calculated_file_size; + @*/ + for(j=buffer_size/2-sizeof(axp_footer); + j+sizeof(axp_footer) <= buffer_size; + j++) + { + if(buffer[j]=='<' && memcmp((const char *)&buffer[j], axp_footer, sizeof(axp_footer))==0) + { + file_recovery->calculated_file_size+=j+sizeof(axp_footer)-buffer_size/2; + return DC_STOP; + } + } + file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2); + return DC_CONTINUE; +} + +/*@ + @ requires separation: \separated(&file_hint_axp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_axp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_axp.extension; + file_recovery_new->min_filesize=0x70+34; + file_recovery_new->file_check=&file_check_axp; + if(file_recovery_new->blocksize >= 0x34) + { + file_recovery_new->data_check=&data_check_axp; + } + return 1; +} + +static void register_header_check_axp(file_stat_t *file_stat) +{ + static const unsigned char axp_header[0x70]= { + 0xff, 0xfe, 0x3c, 0x00, 0x3f, 0x00, 'x' , 0x00, + 'm' , 0x00, 'l' , 0x00, ' ' , 0x00, 'v' , 0x00, + 'e' , 0x00, 'r' , 0x00, 's' , 0x00, 'i' , 0x00, + 'o' , 0x00, 'n' , 0x00, 0x3d, 0x00, 0x22, 0x00, + '1' , 0x00, '.' , 0x00, '0' , 0x00, 0x22, 0x00, + ' ' , 0x00, 'e' , 0x00, 'n' , 0x00, 'c' , 0x00, + 'o' , 0x00, 'd' , 0x00, 'i' , 0x00, 'n' , 0x00, + 'g' , 0x00, 0x3d, 0x00, 0x22, 0x00, 'U' , 0x00, + 'T' , 0x00, 'F' , 0x00, 0x2d, 0x00, '1' , 0x00, + '6' , 0x00, 0x22, 0x00, 0x3f, 0x00, 0x3e, 0x00, + 0x0d, 0x00, 0x0a, 0x00, 0x3c, 0x00, 'V' , 0x00, + 'F' , 0x00, 'N' , 0x00, 'G' , 0x00, 'D' , 0x00, + 'o' , 0x00, 'c' , 0x00, 'u' , 0x00, 'm' , 0x00, + 'e' , 0x00, 'n' , 0x00, 't' , 0x00, 0x3e, 0x00, + }; + register_header_check(0, axp_header, sizeof(axp_header), &header_check_axp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_axx.c b/subprojects/lib/src/file_axx.c new file mode 100644 index 0000000..c625fd3 --- /dev/null +++ b/subprojects/lib/src/file_axx.c @@ -0,0 +1,141 @@ +/* + + File: file_axx.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_axx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_axx(file_stat_t *file_stat); + +const file_hint_t file_hint_axx= { + .extension="axx", + .description="AxCrypt", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_axx +}; + +struct SHeader +{ + uint32_t aoLength; + uint8_t oType; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires fr->file_check == &file_check_axx; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, fr->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_axx(file_recovery_t *fr) +{ + uint64_t offset=0x10; + /*@ + @ loop assigns *fr->handle, errno, fr->file_size; + @ loop assigns offset, Frama_C_entropy_source; + @ */ + while(offset < 0x8000000000000000) + { + char buffer[sizeof(struct SHeader)]; + const struct SHeader *header=(const struct SHeader *)&buffer; + unsigned int len; + if(my_fseek(fr->handle, offset, SEEK_SET) < 0) + return ; + if (fread(&buffer, sizeof(buffer), 1, fr->handle)!=1) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + len=le32(header->aoLength); +#ifdef DEBUG_AAX + log_info("axx 0x%llx 0x%x 0x%x/%d\n", (long long int)offset, len, header->oType, header->oType); +#endif + if(len<5) + return ; + offset+=len; + if(offset >= 0x8000000000000000) + break; + if(header->oType==63) // eData + { + char buf[sizeof(uint64_t)]; + const uint64_t *fsize_ptr=(const uint64_t *)&buf; + uint64_t fsize; + if(len!=13) + return ; + if (fread(&buf, sizeof(buf), 1, fr->handle)!=1) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buf, sizeof(buf)); +#endif + fsize=le64(*fsize_ptr); + if(fsize >= 0x8000000000000000) + break; + offset+=fsize; + fr->file_size=(fr->file_size < offset ? 0 : offset); + return ; + } + } + fr->file_size=0; +} + +/*@ + @ requires buffer_size > 0x25+sizeof(struct SHeader); + @ requires separation: \separated(&file_hint_axx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_axx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct SHeader *header=(const struct SHeader *)&buffer[0x10+0x15]; + if(le32(header->aoLength) < 5) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_axx.extension; + file_recovery_new->file_check=&file_check_axx; + file_recovery_new->min_filesize=(uint64_t)0x25+le32(header->aoLength); + return 1; +} + +static void register_header_check_axx(file_stat_t *file_stat) +{ + // guidAxCryptFileIdInverse (32 bytes) + length (4) + ePreamble=2 + static const unsigned char axx_header[0x15]= { + 0xc0, 0xb9, 0x07, 0x2e, 0x4f, 0x93, 0xf1, 0x46, + 0xa0, 0x15, 0x79, 0x2c, 0xa1, 0xd9, 0xe8, 0x21, + 0x15, 0x00, 0x00, 0x00, 0x02 + }; + register_header_check(0, axx_header, sizeof(axx_header), &header_check_axx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bac.c b/subprojects/lib/src/file_bac.c new file mode 100644 index 0000000..211d60c --- /dev/null +++ b/subprojects/lib/src/file_bac.c @@ -0,0 +1,138 @@ +/* + + File: file_bac.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bac) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_bac(file_stat_t *file_stat); + +const file_hint_t file_hint_bac= { + .extension="bac", + .description="Bacula backup", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bac +}; + +struct block_header +{ + uint32_t CheckSum; /* Block check sum */ + uint32_t BlockSize; /* Block byte size including the header */ + uint32_t BlockNumber; /* Block number */ + char ID[4]; /* Identification and block level */ + uint32_t VolSessionId; /* Session Id for Job */ + uint32_t VolSessionTime; /* Session Time for Job */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= 2*0x18; + @ requires file_recovery->data_check==&data_check_bac; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_bac(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ assert buffer_size >= 2*0x18; */ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x18 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x18 ; */ + const struct block_header *hdr=(const struct block_header *)&buffer[i]; + const unsigned int block_size=be32(hdr->BlockSize); +#ifdef DEBUG_BACULA + const unsigned int block_nbr=be32(hdr->BlockNumber); + log_trace("file_bac.c: block %u size %u, calculated_file_size %llu\n", + block_nbr, block_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(memcmp(hdr->ID, "BB02", 4)!=0 || block_size<0x18) + { +#ifndef __FRAMAC__ + log_error("file_bac.c: invalid block at %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)block_size; + } +#ifdef DEBUG_BACULA + log_trace("file_bac.c: new calculated_file_size %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct block_header); + @ requires separation: \separated(&file_hint_bac, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null || file_recovery_new->data_check == &data_check_bac); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == \null || file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bac.extension); + @ assigns *file_recovery_new; + @*/ +static int header_check_bac(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct block_header *hdr=(const struct block_header *)buffer; + if(be32(hdr->BlockSize) < 0x18) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bac.extension; + file_recovery_new->min_filesize=be32(hdr->BlockSize); + file_recovery_new->calculated_file_size=0; + if(file_recovery_new->blocksize >= 0x18) + { + file_recovery_new->data_check=&data_check_bac; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_bac(file_stat_t *file_stat) +{ + static const unsigned char bac_header[8]={ 0, 0, 0, 0, 'B', 'B', '0', '2' }; + register_header_check(8, bac_header, sizeof(bac_header), &header_check_bac, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bdm.c b/subprojects/lib/src/file_bdm.c new file mode 100644 index 0000000..daf3e01 --- /dev/null +++ b/subprojects/lib/src/file_bdm.c @@ -0,0 +1,66 @@ +/* + + File: file_bdm.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bdm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bdm(file_stat_t *file_stat); + +const file_hint_t file_hint_bdm= { + .extension="bdm", + .description="AVHCD index", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bdm +}; + +/*@ + @ requires separation: \separated(&file_hint_bdm, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bdm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bdm.extension; + return 1; +} + +static void register_header_check_bdm(file_stat_t *file_stat) +{ + register_header_check(0, "INDX0100", 8, &header_check_bdm, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, "MOBJ0100", 8, &header_check_bdm, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_berkeley.c b/subprojects/lib/src/file_berkeley.c new file mode 100644 index 0000000..9bb5ae4 --- /dev/null +++ b/subprojects/lib/src/file_berkeley.c @@ -0,0 +1,85 @@ +/* + + File: file_db.c + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_berkeley) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_berkeley_le(file_stat_t *file_stat); + +const file_hint_t file_hint_berkeley= { + .extension="db", + .description="Berkeley DB (Little Endian)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_berkeley_le +}; + +/*@ + @ requires separation: \separated(&file_hint_berkeley, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_berkeley_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_berkeley.extension; + file_recovery_new->min_filesize=0xC+8; + return 1; +} + +static void register_header_check_berkeley_le(file_stat_t *file_stat) +{ +#if 0 + static unsigned char berkeley_db_hash_4[8]={0x61, 0x15, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_hash_5[8]={0x61, 0x15, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_hash_6[8]={0x61, 0x15, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_hash_7[8]={0x61, 0x15, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00}; +#endif + static unsigned char berkeley_db_hash_8[8]={0x61, 0x15, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_hash_9[8]={0x61, 0x15, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00}; +#if 0 + static unsigned char berkeley_db_btree_4[8]={0x62, 0x31, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_btree_5[8]={0x62, 0x31, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_btree_6[8]={0x62, 0x31, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_btree_7[8]={0x62, 0x31, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00}; +#endif + static unsigned char berkeley_db_btree_8[8]={0x62, 0x31, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00}; + static unsigned char berkeley_db_btree_9[8]={0x62, 0x31, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00}; + register_header_check(0xC, berkeley_db_hash_8, 8, &header_check_berkeley_le, file_stat); +#ifndef __FRAMAC__ + register_header_check(0xC, berkeley_db_hash_9, 8, &header_check_berkeley_le, file_stat); + register_header_check(0xC, berkeley_db_btree_8, 8, &header_check_berkeley_le, file_stat); + register_header_check(0xC, berkeley_db_btree_9, 8, &header_check_berkeley_le, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_bfa.c b/subprojects/lib/src/file_bfa.c new file mode 100644 index 0000000..180b2fe --- /dev/null +++ b/subprojects/lib/src/file_bfa.c @@ -0,0 +1,86 @@ +/* + + File: file_bfa.c + + Copyright (C) 2019 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bfa) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bfa(file_stat_t *file_stat); + +const file_hint_t file_hint_bfa= { + .extension="bfa", + .description="Blowfish Advanced CS", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bfa +}; + +struct bfa_header +{ + uint32_t lMagic; + uint16_t wSizeOfHeader; + uint16_t wVersion; + uint64_t lLength; + uint16_t wCipherInitDataSize; + uint16_t wCipherBlockSize; + uint8_t salt[11]; + uint32_t lKeyHash; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct bfa_header); + @ requires separation: \separated(&file_hint_bfa, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bfa(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct bfa_header *header=(const struct bfa_header*)buffer; + uint64_t size=le64(header->lLength); + if(size > PHOTOREC_MAX_FILE_SIZE) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bfa.extension; + file_recovery_new->calculated_file_size=size + le16(header->wSizeOfHeader); + file_recovery_new->file_check=&file_check_size_min; + return 1; +} + +static void register_header_check_bfa(file_stat_t *file_stat) +{ + static const unsigned char bfa_header[8]= { + 0x24, 0x08, 0x19, 0x92, 0x23, 0x00, 0x15, 0x01 + }; + register_header_check(0, bfa_header, sizeof(bfa_header), &header_check_bfa, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bim.c b/subprojects/lib/src/file_bim.c new file mode 100644 index 0000000..6dc45b3 --- /dev/null +++ b/subprojects/lib/src/file_bim.c @@ -0,0 +1,69 @@ +/* + + File: file_bim.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bim) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bim(file_stat_t *file_stat); + +const file_hint_t file_hint_bim= { + .extension="bim", + .description="Broadcast Interface Module", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bim +}; + +/*@ + @ requires separation: \separated(&file_hint_bim, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bim(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bim.extension; + return 1; +} + +static void register_header_check_bim(file_stat_t *file_stat) +{ + static const unsigned char bim_header[0x20]= { + 0x00, 0x1f, 0x01, '4' , 'u' , 'r' , 'n' , ':', + 's' , 'c' , 'h' , 'e' , 'm' , 'a' , 's' , '-', + 'p' , 'r' , 'o' , 'f' , 'e' , 's' , 's' , 'i' , + 'o' , 'n' , 'a' , 'l' , 'D' , 'i' , 's' , 'c' + }; + register_header_check(0, bim_header, sizeof(bim_header), &header_check_bim, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bin.c b/subprojects/lib/src/file_bin.c new file mode 100644 index 0000000..f9ecce8 --- /dev/null +++ b/subprojects/lib/src/file_bin.c @@ -0,0 +1,85 @@ +/* + + File: file_bin.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bin) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bin(file_stat_t *file_stat); + +const file_hint_t file_hint_bin= { + .extension="bin", + .description="DINO", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bin +}; + +struct ticket_header +{ + uint16_t magic; // 01 04 + uint32_t size; + uint32_t unk; // 00 07 00 07 + char data_len; // 9 + char data[9]; // TaTickets +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct ticket_header); + @ requires separation: \separated(&file_hint_bin, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bin(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ticket_header *hdr=(const struct ticket_header *)buffer; + const unsigned int size=le32(hdr->size); + if(size < 65) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="Ticket.bin"; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->min_filesize=65; + return 1; +} + +static void register_header_check_bin(file_stat_t *file_stat) +{ + static const unsigned char bin_header[13]= { + 0x07, 0x00, 0x07, 0x09, 'T' , 'a' , 'T' , + 'i' , 'c' , 'k' , 'e' , 't' , 's' }; + register_header_check(6, bin_header, sizeof(bin_header), &header_check_bin, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_binvox.c b/subprojects/lib/src/file_binvox.c new file mode 100644 index 0000000..71c75d9 --- /dev/null +++ b/subprojects/lib/src/file_binvox.c @@ -0,0 +1,63 @@ +/* + + File: file_binvox.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_binvox) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_binvox(file_stat_t *file_stat); + +const file_hint_t file_hint_binvox= { + .extension="binvox", + .description="Binvox Voxel File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_binvox +}; + +/*@ + @ requires separation: \separated(&file_hint_binvox, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_binvox(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_binvox.extension; + return 1; +} + +static void register_header_check_binvox(file_stat_t *file_stat) +{ + register_header_check(0, "#binvox 1\ndim ", 14, &header_check_binvox, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bkf.c b/subprojects/lib/src/file_bkf.c new file mode 100644 index 0000000..a6b16c6 --- /dev/null +++ b/subprojects/lib/src/file_bkf.c @@ -0,0 +1,121 @@ +/* + + File: file_bkf.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bkf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_bkf(file_stat_t *file_stat); + +const file_hint_t file_hint_bkf= { + .extension="bkf", + .description="MS Backup file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bkf +}; + +struct mtf_db_hdr +{ + uint32_t type; /* DBLK type */ + uint32_t attr; /* block attributes */ + uint16_t off; /* offset to first event */ + uint8_t osId; /* OS ID */ + uint8_t osVer; /* OS version */ + uint64_t size; /* displayable size */ + uint64_t fla; /* format logical address */ + uint16_t mbc; /* reserved for MBC */ + uint8_t rsv1[6]; /* reserved for future use */ + uint32_t cbId; /* control block ID */ + uint8_t rsv2[4]; /* reserved for future use */ + uint32_t osData; /* OS-specific data */ + uint8_t strType; /* string type */ + uint8_t rsv3; /* reserved for future use */ + uint16_t check; /* header checksum */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_bkf; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_bkf(file_recovery_t *file_recovery) +{ + const unsigned char bkf_footer[4]= { 'S', 'F', 'M', 'B'}; + file_search_footer(file_recovery, bkf_footer, sizeof(bkf_footer), 0x400-4); +} + +/*@ + @ requires buffer_size >= sizeof(struct mtf_db_hdr); + @ requires separation: \separated(&file_hint_bkf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 52); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bkf.extension); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_bkf); + @ assigns *file_recovery_new; + @*/ +static int header_check_bkf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct mtf_db_hdr *hdr=(const struct mtf_db_hdr *)buffer; + /* Microsoft Tape Format + * The DBLK Type field is set to ‘TAPE’. + * The Format Logical Address field is set to zero. + * The Control Block ID field is set to zero. + */ + if(le64(hdr->fla)!=0 || le32(hdr->cbId)!=0 || hdr->strType>2 || + le16(hdr->off)off)); +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=52; + file_recovery_new->extension=file_hint_bkf.extension; + file_recovery_new->file_check=&file_check_bkf; + return 1; +} + +static void register_header_check_bkf(file_stat_t *file_stat) +{ + static const unsigned char bkf_header[4]= { 'T','A','P','E'}; + register_header_check(0, bkf_header,sizeof(bkf_header), &header_check_bkf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bld.c b/subprojects/lib/src/file_bld.c new file mode 100644 index 0000000..dd7cb06 --- /dev/null +++ b/subprojects/lib/src/file_bld.c @@ -0,0 +1,256 @@ +/* + + File: file_bld.c + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_blend) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_blend(file_stat_t *file_stat); + +const file_hint_t file_hint_blend= { + .extension="blend", + .description="blender", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_blend +}; + +static const unsigned char blend_header_footer[4] = { 'E', 'N', 'D', 'B'}; + +struct blend4_block +{ + char code[4]; + uint32_t size; + uint32_t old_address; + uint32_t SDNA_index; + uint32_t count; +} __attribute__ ((gcc_struct, __packed__)); + +struct blend8_block +{ + char code[4]; + uint32_t size; + uint64_t old_address; + uint32_t SDNA_index; + uint32_t count; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_blend4le; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_blend4le(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x14 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x14; */ + const struct blend4_block *blk=(const struct blend4_block *)&buffer[i]; + const unsigned int len=le32(blk->size); +#ifdef DEBUG_BLEND + log_debug("file_mov.c: atom %c%c%c%c (0x%02x%02x%02x%02x) size %u, calculated_file_size %llu\n", + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + len, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(memcmp(&buffer[i],blend_header_footer,sizeof(blend_header_footer))==0) + { + file_recovery->calculated_file_size+=0x14; + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)0x14+len; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&data_check_blend8le; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_blend8le(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x18 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x18; */ + const struct blend8_block *blk=(const struct blend8_block *)&buffer[i]; + const unsigned int len=le32(blk->size); +#ifdef DEBUG_BLEND + log_debug("file_mov.c: atom %c%c%c%c (0x%02x%02x%02x%02x) size %u, calculated_file_size %llu\n", + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + len, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(memcmp(&buffer[i],blend_header_footer,sizeof(blend_header_footer))==0) + { + file_recovery->calculated_file_size+=0x18; + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)0x18+len; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&data_check_blend4be; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_blend4be(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x14 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x14; */ + const struct blend4_block *blk=(const struct blend4_block *)&buffer[i]; + const unsigned int len=be32(blk->size); + /*@ assert len <= 0xffffffff; */ +#ifdef DEBUG_BLEND + log_debug("file_mov.c: atom %c%c%c%c (0x%02x%02x%02x%02x) size %u, calculated_file_size %llu\n", + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + len, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(memcmp(&buffer[i],blend_header_footer,sizeof(blend_header_footer))==0) + { + file_recovery->calculated_file_size+=0x14; + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)0x14+len; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&data_check_blend8be; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_blend8be(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @ */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x18 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x18; */ + const struct blend8_block *blk=(const struct blend8_block *)&buffer[i]; + const unsigned int len=be32(blk->size); + /*@ assert len <= 0xffffffff; */ +#ifdef DEBUG_BLEND + log_debug("file_mov.c: atom %c%c%c%c (0x%02x%02x%02x%02x) size %u, calculated_file_size %llu\n", + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i+0],buffer[i+1],buffer[i+2],buffer[i+3], + len, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(memcmp(&buffer[i],blend_header_footer,sizeof(blend_header_footer))==0) + { + file_recovery->calculated_file_size+=0x18; + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)0x18+len; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_blend, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 12); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_blend.extension); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_blend4be || + file_recovery_new->data_check == &data_check_blend4le || + file_recovery_new->data_check == &data_check_blend8be || + file_recovery_new->data_check == &data_check_blend8le + ); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ assigns *file_recovery_new; + @*/ +static int header_check_blend(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[7]!='_' && buffer[7]!='-') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_blend.extension; + if(file_recovery_new->blocksize < 0x14) + return 1; + file_recovery_new->calculated_file_size=12; + if(buffer[8]=='v') + { /* Little endian */ + if(buffer[7]=='_') + file_recovery_new->data_check=&data_check_blend4le; + else + file_recovery_new->data_check=&data_check_blend8le; + } + else + { /* Big endian */ + if(buffer[7]=='_') + file_recovery_new->data_check=&data_check_blend4be; + else + file_recovery_new->data_check=&data_check_blend8be; + } + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_blend(file_stat_t *file_stat) +{ + static const unsigned char blend_header[7] = { 'B', 'L', 'E', 'N', 'D', 'E', 'R'}; + register_header_check(0, blend_header,sizeof(blend_header), &header_check_blend, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bmp.c b/subprojects/lib/src/file_bmp.c new file mode 100644 index 0000000..9d8b1df --- /dev/null +++ b/subprojects/lib/src/file_bmp.c @@ -0,0 +1,229 @@ +/* + + File: file_bmp.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bmp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_bmp(file_stat_t *file_stat); + +const file_hint_t file_hint_bmp= { + .extension="bmp", + .description="BMP bitmap image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bmp +}; + +static const unsigned char bmp_header[2]= {'B','M'}; + +struct bmp_header +{ + uint16_t magic; + uint32_t size; + uint32_t reserved; + uint32_t offset; + uint32_t hdr_size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= 18; + @ requires separation: \separated(&file_hint_bmp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null); + @ ensures (\result == 1) ==> (file_recovery_new->handle == \null); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bmp.extension); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 65); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 65); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ assigns file_recovery_new->filename[0]; + @ assigns file_recovery_new->time; + @ assigns file_recovery_new->file_stat; + @ assigns file_recovery_new->handle; + @ assigns file_recovery_new->file_size; + @ assigns file_recovery_new->location.list.prev; + @ assigns file_recovery_new->location.list.next; + @ assigns file_recovery_new->location.end; + @ assigns file_recovery_new->location.data; + @ assigns file_recovery_new->extension; + @ assigns file_recovery_new->min_filesize; + @ assigns file_recovery_new->calculated_file_size; + @ assigns file_recovery_new->data_check; + @ assigns file_recovery_new->file_check; + @ assigns file_recovery_new->file_rename; + @ assigns file_recovery_new->offset_error; + @ assigns file_recovery_new->offset_ok; + @ assigns file_recovery_new->checkpoint_status; + @ assigns file_recovery_new->checkpoint_offset; + @ assigns file_recovery_new->flags; + @ assigns file_recovery_new->extra; + @ assigns file_recovery_new->data_check_tmp; + @*/ +// ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension); +static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct bmp_header *bm=(const struct bmp_header *)buffer; + if(buffer[0]!='B' || buffer[1]!='M') + return 0; + if(bm->reserved!=0) + return 0; + if( + (buffer[14]==12 || buffer[14]==64 || buffer[14]==40 || buffer[14]==52 || + buffer[14]==56 || buffer[14]==108 || buffer[14]==124) && + buffer[15]==0 && buffer[16]==0 && buffer[17]==0 && + le32(bm->offset) < le32(bm->size) && + le32(bm->size) >= 65 && + le32(bm->hdr_size) < le32(bm->size)) + { + /* See http://en.wikipedia.org/wiki/BMP_file_format */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bmp.extension; + file_recovery_new->min_filesize=65; + file_recovery_new->calculated_file_size=(uint64_t)le32(bm->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + /*@ assert file_recovery_new->extension == file_hint_bmp.extension; */ + /*@ assert file_recovery_new->calculated_file_size >= 65; */ + /*@ assert file_recovery_new->file_size == 0; */ + /*@ assert file_recovery_new->min_filesize == 65; */ + /*@ assert file_recovery_new->data_check == &data_check_size; */ + /*@ assert file_recovery_new->file_check == &file_check_size; */ + /*@ assert valid_read_string(file_recovery_new->extension); */ + /*@ assert \initialized(&file_recovery_new->time); */ + return 1; + } + return 0; +} + +static void register_header_check_bmp(file_stat_t *file_stat) +{ + register_header_check(0, bmp_header,sizeof(bmp_header), &header_check_bmp, file_stat); +} +#endif + +#if defined(MAIN_bmp) +#define BLOCKSIZE 65536u +int main(void) +{ + const char fn[] = "recup_dir.1/f0000000.bmp"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + /*@ assert file_recovery.file_stat == \null; */ + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_bmp; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_bmp(&file_stats); + if(header_check_bmp(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.extension == file_hint_bmp.extension; */ + /*@ assert file_recovery_new.calculated_file_size >= 65; */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.min_filesize == 65; */ + /*@ assert file_recovery_new.file_check == &file_check_size; */ + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */ + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_size == 0; */; + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + { + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + header_check_bmp(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_recovery_new.handle=fopen(fn, "rb"); + /*@ assert file_recovery_new.file_check == &file_check_size; */ + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_bpg.c b/subprojects/lib/src/file_bpg.c new file mode 100644 index 0000000..7fc307a --- /dev/null +++ b/subprojects/lib/src/file_bpg.c @@ -0,0 +1,124 @@ +/* + + File: file_bpg.c + + Copyright (C) 1998-2007 Christophe GRENIER + Copyright (C) 2016 Dmitry Brant + + BPG specification can be found at: + https://bellard.org/bpg/bpg_spec.txt + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bpg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +#define MAX_BPG_SIZE 0x800000 + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bpg(file_stat_t *file_stat); + +const file_hint_t file_hint_bpg= { + .extension="bpg", + .description="Better Portable Graphics image", + .max_filesize=MAX_BPG_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bpg +}; + +/*@ + @ requires buffer_size > 0; + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ requires \valid(buf_ptr); + @ requires \separated(buffer+(..), buf_ptr); + @ assigns *buf_ptr; + @*/ +static unsigned int getue32(const unsigned char *buffer, const unsigned int buffer_size, unsigned int *buf_ptr) +{ + uint64_t value = 0; + int bitsRead = 0; + /*@ + @ loop invariant bitsRead <= 35; + @ loop invariant value < (bitsRead == 0 ? 1: (0x80 << (bitsRead-7))); + @ loop assigns value, bitsRead, *buf_ptr; + @ loop variant 35 - bitsRead; + @ */ + while (*buf_ptr < buffer_size) + { + const unsigned int b = buffer[*buf_ptr]; + *buf_ptr = *buf_ptr + 1; + value <<= 7; + value |= (b & 0x7F); + if ((b & 0x80) == 0) + break; + bitsRead += 7; + if (bitsRead >= 32) + break; + } + return value&0xffffffff; +} + +/*@ + @ requires buffer_size >= 6+3*5; + @ requires separation: \separated(&file_hint_bpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bpg.extension); + @ ensures (\result == 1) ==> (file_recovery_new->data_check== &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ assigns *file_recovery_new; + @*/ +static int header_check_bpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int buf_ptr = 6; + // get image width + const unsigned int picture_width = getue32(buffer, buffer_size, &buf_ptr); + // get image height + const unsigned int picture_height = getue32(buffer, buffer_size, &buf_ptr); + uint64_t size = getue32(buffer, buffer_size, &buf_ptr); + if(picture_width==0 || picture_height==0) + return 0; + if (size == 0) { + size = MAX_BPG_SIZE; + } else { + size += buf_ptr; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->extension=file_hint_bpg.extension; + return 1; +} + +static void register_header_check_bpg(file_stat_t *file_stat) +{ + static const unsigned char bpg_header[4]= {'B','P','G',0xFB}; + register_header_check(0, bpg_header,sizeof(bpg_header), &header_check_bpg, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bvr.c b/subprojects/lib/src/file_bvr.c new file mode 100644 index 0000000..715d786 --- /dev/null +++ b/subprojects/lib/src/file_bvr.c @@ -0,0 +1,100 @@ +/* + + File: file_bvr.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bvr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bvr(file_stat_t *file_stat); + +const file_hint_t file_hint_bvr= { + .extension="bvr", + .description="Blue Iris DVR", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bvr +}; + +/*@ + @ requires file_recovery->data_check==&data_check_bvr; + @ requires \separated(buffer, file_recovery); + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_bvr(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 16; */ + const uint32_t *valp=(const uint32_t *)&buffer[i+12]; + if(memcmp(&buffer[i], "BLUE", 4) != 0) + return DC_STOP; + file_recovery->calculated_file_size+=(uint64_t)0x20 + *valp; + if(*valp == 0) + return DC_STOP; + } + return DC_CONTINUE; +} + +/*@ + @ requires separation: \separated(&file_hint_bvr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_bvr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_bvr) + { + /*@ assert \valid_function(file_recovery->file_check); */ + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bvr.extension; + file_recovery_new->data_check=&data_check_bvr; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_bvr(file_stat_t *file_stat) +{ + static const unsigned char bvrheader[8]= { 'B', 'L', 'U', 'E', 0x20, 0x00, 0x10, 0x00}; + register_header_check(0, bvrheader, sizeof(bvrheader), &header_check_bvr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_bz2.c b/subprojects/lib/src/file_bz2.c new file mode 100644 index 0000000..7d08d75 --- /dev/null +++ b/subprojects/lib/src/file_bz2.c @@ -0,0 +1,69 @@ +/* + + File: file_bz2.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bz2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_bz2(file_stat_t *file_stat); + +const file_hint_t file_hint_bz2= { + .extension="bz2", + .description="bzip2 compressed data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_bz2 +}; + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_bz2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bz2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]=='B' && buffer[1]=='Z' && buffer[2]=='h' && buffer[3]>='0' && buffer[3]<='9' && buffer[4]=='1' && buffer[5]=='A' && buffer[6]=='Y' && buffer[7]=='&' && buffer[8]=='S' && buffer[9]=='Y') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_bz2.extension; + return 1; + } + return 0; +} + +static void register_header_check_bz2(file_stat_t *file_stat) +{ + static const unsigned char bz2_header[3]= {'B','Z','h'}; + register_header_check(0, bz2_header,sizeof(bz2_header), &header_check_bz2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_c4d.c b/subprojects/lib/src/file_c4d.c new file mode 100644 index 0000000..0f08ef7 --- /dev/null +++ b/subprojects/lib/src/file_c4d.c @@ -0,0 +1,63 @@ +/* + + File: file_c4d.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_c4d) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_c4d(file_stat_t *file_stat); + +const file_hint_t file_hint_c4d= { + .extension="c4d", + .description="Cinema 4d", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_c4d +}; + +/*@ + @ requires separation: \separated(&file_hint_c4d, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_c4d(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_c4d.extension; + return 1; +} + +static void register_header_check_c4d(file_stat_t *file_stat) +{ + register_header_check(0, "QC4DC4D6", 8, &header_check_c4d, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cab.c b/subprojects/lib/src/file_cab.c new file mode 100644 index 0000000..0d7642b --- /dev/null +++ b/subprojects/lib/src/file_cab.c @@ -0,0 +1,90 @@ +/* + + File: file_cab.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cab) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cab(file_stat_t *file_stat); + +const file_hint_t file_hint_cab= { + .extension="cab", + .description="Microsoft Cabinet archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cab +}; + +struct cab_header { + uint32_t magic; + uint32_t hdr_checksum; + uint32_t filesize; + uint32_t fld_checksum; + uint32_t off_file; + uint32_t files_checksum; + uint16_t cab_version; + uint16_t nb_folder; + uint16_t nb_files; + uint16_t flags; + uint16_t setid; + uint16_t number; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct cab_header) ; + @ requires separation: \separated(&file_hint_cab, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cab(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct cab_header *cab_hdr=(const struct cab_header*)buffer; + const unsigned int filesize=le32(cab_hdr->filesize); + if(le16(cab_hdr->cab_version)==0x0103 && filesize >= sizeof(struct cab_header)) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cab.extension; + file_recovery_new->calculated_file_size=filesize; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_cab(file_stat_t *file_stat) +{ + static const unsigned char cab_header[4] = { 'M','S','C','F'}; + register_header_check(0, cab_header,sizeof(cab_header), &header_check_cab, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_caf.c b/subprojects/lib/src/file_caf.c new file mode 100644 index 0000000..07b98aa --- /dev/null +++ b/subprojects/lib/src/file_caf.c @@ -0,0 +1,144 @@ +/* + + File: file_caf.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_caf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +//#define DEBUG_CAF +#ifdef DEBUG_CAF +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_caf(file_stat_t *file_stat); + +const file_hint_t file_hint_caf= { + .extension="caf", + .description="Core Audio Format", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_caf +}; + +/* https://developer.apple.com/library/archive/documentation/MusicAudio/Reference/CAFSpec/CAF_spec/CAF_spec.html */ + +struct chunk_struct +{ + uint32_t type; + /* The correct type is int64_t but */ + uint64_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_caf; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size,file_recovery->data_check,file_recovery->file_check; + @*/ +static data_check_t data_check_caf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 12 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 12; */ + const struct chunk_struct *chunk=(const struct chunk_struct*)&buffer[i]; + const uint64_t chunk_size=be64(chunk->size); +#ifdef DEBUG_CAF + log_trace("file_caf.c: %s chunk %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu (0x%llx)\n", + file_recovery->filename, + buffer[i],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i],buffer[i+1],buffer[i+2],buffer[i+3], + (long long unsigned)chunk_size, + (long long unsigned)file_recovery->calculated_file_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(buffer[i]==0) + { + /* Always true */ + if(file_recovery->calculated_file_size > 0) + file_recovery->calculated_file_size--; + return DC_STOP; + } + /* The correct type is int64_t, 0x7ffffffffffffff >= PHOTOREC_MAX_FILE_SIZE */ + if(chunk_size>PHOTOREC_MAX_FILE_SIZE) + { + file_recovery->data_check=NULL; + file_recovery->file_check=NULL; + return DC_STOP; + } + file_recovery->calculated_file_size+=(uint64_t)12+chunk_size; + } +#ifdef DEBUG_CAF + log_trace("file_caf.c: new calculated_file_size %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_CONTINUE; +} + +/*@ + @ requires separation: \separated(&file_hint_caf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures \result!=0 && file_recovery_new->data_check==&data_check_caf ==> file_recovery_new->calculated_file_size == 8; + @ assigns *file_recovery_new; + @*/ +static int header_check_caf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct chunk_struct *chunk=(const struct chunk_struct*)&buffer[8]; + const uint64_t chunk_size=be64(chunk->size); + if(chunk_size >= PHOTOREC_MAX_FILE_SIZE) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_caf.extension; + file_recovery_new->min_filesize=8+12; + if(file_recovery_new->blocksize >= 12) + { + file_recovery_new->data_check=&data_check_caf; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=8; + } + /*@ assert file_recovery_new->data_check==&data_check_caf ==> file_recovery_new->calculated_file_size == 8; */ + return 1; +} + +static void register_header_check_caf(file_stat_t *file_stat) +{ + static const unsigned char caf_header[12]= { + 'c' , 'a' , 'f' , 'f' , 0x00, 0x01, 0x00, 0x00, + 'd' , 'e' , 's' , 'c' + }; + register_header_check(0, caf_header, sizeof(caf_header), &header_check_caf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cam.c b/subprojects/lib/src/file_cam.c new file mode 100644 index 0000000..9a71173 --- /dev/null +++ b/subprojects/lib/src/file_cam.c @@ -0,0 +1,64 @@ +/* + + File: file_cam.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cam) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cam(file_stat_t *file_stat); + +const file_hint_t file_hint_cam= { + .extension="cam", + .description="Casio QV Digital Camera Image", + .max_filesize=10*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cam +}; + +/*@ + @ requires separation: \separated(&file_hint_cam, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cam(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cam.extension; + return 1; +} + +static void register_header_check_cam(file_stat_t *file_stat) +{ + static const unsigned char cam_header[4]= {0x07, 0x20, 'M', 'M'}; + register_header_check(0, cam_header,sizeof(cam_header), &header_check_cam, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_catdrawing.c b/subprojects/lib/src/file_catdrawing.c new file mode 100644 index 0000000..6f577e1 --- /dev/null +++ b/subprojects/lib/src/file_catdrawing.c @@ -0,0 +1,67 @@ +/* + + File: file_catdrawing.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_catdrawing) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_catdrawing(file_stat_t *file_stat); + +const file_hint_t file_hint_catdrawing= { + .extension="catdrawing", + .description="CATIA", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_catdrawing +}; + +/*@ + @ requires separation: \separated(&file_hint_catdrawing, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_catdrawing(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_catdrawing.extension; + return 1; +} + +static void register_header_check_catdrawing(file_stat_t *file_stat) +{ + static const unsigned char catdrawing_header[9]= { + 'V' , '5' , '_' , 'C' , 'F' , 'V' , '2' , 0x00, + 0x00 + }; + register_header_check(0, catdrawing_header, sizeof(catdrawing_header), &header_check_catdrawing, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cdt.c b/subprojects/lib/src/file_cdt.c new file mode 100644 index 0000000..297bef5 --- /dev/null +++ b/subprojects/lib/src/file_cdt.c @@ -0,0 +1,73 @@ +/* + + File: file_cdt.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cdt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cdt(file_stat_t *file_stat); + +const file_hint_t file_hint_cdt= { + .extension="cdt", + .description="cdl/cdt/cdd Concept Draw", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cdt +}; + +/*@ + @ requires separation: \separated(&file_hint_cdt, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cdt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + if(buffer[0]==0xee) + file_recovery_new->extension="cdl"; /* ConceptDraw PRO Library File */ + else if(buffer[0]==0xef) + file_recovery_new->extension="cdd"; /* ConceptDraw PRO Document */ + else if(buffer[0]==0xf0) + file_recovery_new->extension="cdt"; /* ConceptDraw PRO Template */ + else + file_recovery_new->extension=file_hint_cdt.extension; + return 1; +} + +static void register_header_check_cdt(file_stat_t *file_stat) +{ + static const unsigned char cdt_header[7]= { + 'C' , 'O' , 'N' , 'C' , 'E' , 'P' , 'T' + }; + register_header_check(12, cdt_header, sizeof(cdt_header), &header_check_cdt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_che.c b/subprojects/lib/src/file_che.c new file mode 100644 index 0000000..682ccc7 --- /dev/null +++ b/subprojects/lib/src/file_che.c @@ -0,0 +1,120 @@ +/* + + File: file_che.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_che) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_che(file_stat_t *file_stat); + +const file_hint_t file_hint_che= { + .extension="che", + .description="Compucon EOS Design File", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_che +}; + +struct che_block +{ + char name[0x10]; + uint32_t size; + uint32_t unk1; + uint32_t unk2; +} __attribute__ ((gcc_struct, __packed__)); + + +/*@ + @ requires file_recovery->file_check == &file_check_che; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @ + @*/ +static void file_check_che(file_recovery_t *file_recovery) +{ + struct che_block block; + uint64_t offset; + uint64_t new_offset=0x19; + const uint64_t file_size_org=file_recovery->file_size; + file_recovery->file_size=0; + /*@ + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source; + @*/ + do + { + offset=new_offset; +#ifdef DEBUG_CHE + log_info("offset=0x%llx\n", (long long unsigned)offset); +#endif + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 || + fread(&block, sizeof(struct che_block), 1, file_recovery->handle) != 1) + { + file_recovery->file_size=offset; + return ; + } +#ifdef DEBUG_CHE + log_info(" sizeof=0x%x, size=%x, name=%s\n", sizeof(struct che_block),le32(block.size), block.name); +#endif + new_offset=offset+sizeof(struct che_block)+le32(block.size); + if(memcmp(block.name,"ConnectionInfo",14)==0) + { + file_recovery->file_size=new_offset; + return ; + } + } while(new_offset <= file_size_org && le32(block.size)!=0); + file_recovery->file_size=offset; +} + +/*@ + @ requires separation: \separated(&file_hint_che, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_che(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_che.extension; + file_recovery_new->min_filesize=0x19; + file_recovery_new->file_check=&file_check_che; + return 1; +} + +static void register_header_check_che(file_stat_t *file_stat) +{ + register_header_check(0, "Compucon EOS Design File", 24, &header_check_che, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_chm.c b/subprojects/lib/src/file_chm.c new file mode 100644 index 0000000..67ed5bf --- /dev/null +++ b/subprojects/lib/src/file_chm.c @@ -0,0 +1,72 @@ +/* + + File: file_chm.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_chm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_chm(file_stat_t *file_stat); + +const file_hint_t file_hint_chm= { + .extension="chm", + .description="MS Windows HtmlHelp Data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_chm +}; + +/*@ + @ requires buffer_size >= 108; + @ requires separation: \separated(&file_hint_chm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_chm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=(buffer[104]<<0)+(buffer[105]<<8)+(buffer[106]<<16)+((uint64_t)buffer[107]<<24); + if(size < 108) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->extension=file_hint_chm.extension; + return 1; +} + +static void register_header_check_chm(file_stat_t *file_stat) +{ + static const unsigned char chm_header[16]={ 'I', 'T', 'S', 'F', 0x03, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; + register_header_check(0, chm_header,sizeof(chm_header), &header_check_chm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_class.c b/subprojects/lib/src/file_class.c new file mode 100644 index 0000000..7d0f67f --- /dev/null +++ b/subprojects/lib/src/file_class.c @@ -0,0 +1,81 @@ +/* + + File: file_class.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_class) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_class(file_stat_t *file_stat); + +const file_hint_t file_hint_class= { + .extension="class", + .description="Java Class", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_class +}; + +struct class_header { + uint32_t magic_number; + uint16_t minor_version; + uint16_t major_version; + uint16_t constant_pool_count; +}; + +/*@ + @ requires buffer_size >= sizeof(struct class_header); + @ requires separation: \separated(&file_hint_class, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_class(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct class_header *cafe=(const struct class_header *)buffer; + if(be32(cafe->magic_number)==0xCafeBabe && + be16(cafe->major_version) >= 45 && be16(cafe->major_version) <= 100 && + be16(cafe->constant_pool_count) > 0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_class.extension; + return 1; + } + return 0; +} + +static void register_header_check_class(file_stat_t *file_stat) +{ + /* https://en.wikipedia.org/wiki/Class_(file_format) */ + static const unsigned char class_magic[4]= { 0xCA, 0xFE, 0xBA, 0xBE }; + register_header_check(0, class_magic, sizeof(class_magic), &header_check_class, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_clip.c b/subprojects/lib/src/file_clip.c new file mode 100644 index 0000000..0694806 --- /dev/null +++ b/subprojects/lib/src/file_clip.c @@ -0,0 +1,113 @@ +/* + + File: file_clip.c + + Copyright (C) 2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_clip) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_clip(file_stat_t *file_stat); + +const file_hint_t file_hint_clip= { + .extension="clip", + .description="Clip Studio Paint", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_clip +}; + +struct clip_header +{ + char header[8]; + uint64_t size; +} __attribute__ ((gcc_struct, __packed__)); + +struct clip_chunk +{ + char chunk[4]; /* CHNK */ + char type[4]; + uint64_t length; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_clip; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_clip(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 16 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 16; */ + const struct clip_chunk *chunk=(const struct clip_chunk *)&buffer[i]; + const uint64_t length=be64(chunk->length); + if(length >= 0x100000000 || + memcmp(&buffer[i], "CHNK", 4)!=0) + return DC_ERROR; + file_recovery->calculated_file_size+=(uint64_t)0x10 + length; + if(length==0) + return DC_STOP; + } + return DC_CONTINUE; +} + + +/*@ + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_clip(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct clip_header *hdr=(const struct clip_header *)buffer; + const uint64_t size=be64(hdr->size); + if(size <= 0x18 || size > 0x100000000) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_clip.extension; + file_recovery_new->data_check=&data_check_clip; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=0x18; + file_recovery_new->min_filesize=size; + return 1; +} + +static void register_header_check_clip(file_stat_t *file_stat) +{ + register_header_check(0, "CSFCHUNK", 8, &header_check_clip, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cm.c b/subprojects/lib/src/file_cm.c new file mode 100644 index 0000000..ff1875b --- /dev/null +++ b/subprojects/lib/src/file_cm.c @@ -0,0 +1,64 @@ +/* + + File: file_cm.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cm(file_stat_t *file_stat); + +const file_hint_t file_hint_cm= { + .extension="comicdoc", + .description="Comic Life", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cm +}; + +/*@ + @ requires separation: \separated(&file_hint_cm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cm.extension; + return 1; +} + +static void register_header_check_cm(file_stat_t *file_stat) +{ + static const unsigned char cm_header[8] = { 'f','L','m','C','0','0','0','1'}; + register_header_check(0x0, cm_header,sizeof(cm_header), &header_check_cm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_compress.c b/subprojects/lib/src/file_compress.c new file mode 100644 index 0000000..1c4d3c5 --- /dev/null +++ b/subprojects/lib/src/file_compress.c @@ -0,0 +1,64 @@ +/* + + File: file_compress.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_compress) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_compress(file_stat_t *file_stat); + +const file_hint_t file_hint_compress= { + .extension="cp_", + .description="MS compress file (SZDD)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_compress +}; + +/*@ + @ requires separation: \separated(&file_hint_compress, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_compress(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_compress.extension; + return 1; +} + +static void register_header_check_compress(file_stat_t *file_stat) +{ + static const unsigned char compress_header[9] = {'S', 'Z', 'D', 'D', 0x88, 0xf0, 0x27, 0x33, 'A'}; + register_header_check(0, compress_header, sizeof(compress_header), &header_check_compress, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cow.c b/subprojects/lib/src/file_cow.c new file mode 100644 index 0000000..80479ba --- /dev/null +++ b/subprojects/lib/src/file_cow.c @@ -0,0 +1,146 @@ +/* + + File: file_cow.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cow) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cow(file_stat_t *file_stat); + +const file_hint_t file_hint_cow= { + .extension="cow", + .description="Qemu Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cow +}; + +/* QEMU, open source processor emulator, can be downloaded from http://www.qemu.org/ */ + +typedef struct { + uint32_t magic; + uint32_t version; + uint64_t backing_file_offset; + uint32_t backing_file_size; + uint32_t mtime; + uint64_t size; /* in bytes */ + uint8_t cluster_bits; + uint8_t l2_bits; + uint32_t crypt_method; + uint64_t l1_table_offset; +} __attribute__ ((gcc_struct, __packed__)) QCowHeader_t; + +typedef struct QCowHeader { + uint32_t magic; + uint32_t version; + uint64_t backing_file_offset; + uint32_t backing_file_size; + uint32_t cluster_bits; + uint64_t size; /* in bytes */ + uint32_t crypt_method; + uint32_t l1_size; /* XXX: save number of clusters instead ? */ + uint64_t l1_table_offset; + uint64_t refcount_table_offset; + uint32_t refcount_table_clusters; + uint32_t nb_snapshots; + uint64_t snapshots_offset; +} QCowHeader2_t; + +/*@ + @ requires buffer_size >= sizeof(QCowHeader_t); + @ requires separation: \separated(&file_hint_cow, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qcow1(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const QCowHeader_t *header=(const QCowHeader_t*)buffer; + uint64_t min_size=be64(header->backing_file_offset); + if(min_size < be64(header->l1_table_offset)) + min_size=be64(header->l1_table_offset); + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cow.extension; + file_recovery_new->time=be32(header->mtime); + file_recovery_new->min_filesize=min_size; + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(QCowHeader2_t); + @ requires separation: \separated(&file_hint_cow, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qcow2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const QCowHeader2_t *header=(const QCowHeader2_t*)buffer; + uint64_t min_size=be64(header->backing_file_offset); + if(min_size < be64(header->l1_table_offset)) + min_size=be64(header->l1_table_offset); + else if(min_size < be64(header->refcount_table_offset)) + min_size=be64(header->refcount_table_offset); + else if(min_size < be64(header->snapshots_offset)) + min_size=be64(header->snapshots_offset); + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cow.extension; + file_recovery_new->min_filesize=min_size; +#ifdef DEBUG_COW + log_info("magic %lu\n", be32(header->magic)); + log_info("version %lu\n", be32(header->version)); + log_info("backing_file_offset %llu\n", be64(header->backing_file_offset)); + log_info("backing_file_size %lu\n", be32(header->backing_file_size)); + log_info("cluster_bits %lu\n", be32(header->cluster_bits)); + log_info("size %llu\n", be64(header->size)); /* in bytes */ + log_info("crypt_method %lu\n", be32(header->crypt_method)); + log_info("l1_size %lu\n", be32(header->l1_size)); /* XXX: save number of clusters instead ? */ + log_info("l1_table_offset %llu\n", be64(header->l1_table_offset)); + log_info("refcount_table_offset %llu\n", be64(header->refcount_table_offset)); + log_info("refcount_table_clusters %lu\n", be32(header->refcount_table_clusters)); + log_info("nb_snapshots %lu\n", be32(header->nb_snapshots)); + log_info("snapshots_offset %llu\n", be64(header->snapshots_offset)); +#endif + return 1; +} + +static void register_header_check_cow(file_stat_t *file_stat) +{ + static const unsigned char cow_header[8]= {'Q', 'F', 'I', 0xfb, 0x0, 0x0, 0x0, 0x1}; + static const unsigned char cow_header2[8]= {'Q', 'F', 'I', 0xfb, 0x0, 0x0, 0x0, 0x2}; + static const unsigned char cow_header3[8]= {'Q', 'F', 'I', 0xfb, 0x0, 0x0, 0x0, 0x3}; + register_header_check(0, cow_header,sizeof(cow_header), &header_check_qcow1, file_stat); + register_header_check(0, cow_header2,sizeof(cow_header2), &header_check_qcow2, file_stat); + register_header_check(0, cow_header3,sizeof(cow_header3), &header_check_qcow2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cpi.c b/subprojects/lib/src/file_cpi.c new file mode 100644 index 0000000..c53b865 --- /dev/null +++ b/subprojects/lib/src/file_cpi.c @@ -0,0 +1,63 @@ +/* + + File: file_cpi.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cpi) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cpi(file_stat_t *file_stat); + +const file_hint_t file_hint_cpi= { + .extension="cpi", + .description="AVCHD Clip Information", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cpi +}; + +/*@ + @ requires separation: \separated(&file_hint_cpi, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cpi(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cpi.extension; + return 1; +} + +static void register_header_check_cpi(file_stat_t *file_stat) +{ + register_header_check(0, "HDMV0100", 8, &header_check_cpi, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_crw.c b/subprojects/lib/src/file_crw.c new file mode 100644 index 0000000..20d337e --- /dev/null +++ b/subprojects/lib/src/file_crw.c @@ -0,0 +1,88 @@ +/* + + File: file_crw.c + + Copyright (C) 1998-2005,2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_crw) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_crw(file_stat_t *file_stat); + +const file_hint_t file_hint_crw= { + .extension="crw", + .description="Canon Raw picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_crw +}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_crw(file_recovery_t *file_recovery) +{ + const unsigned char crw_footer[2]= { 0x0A, 0x30}; + file_search_footer(file_recovery, crw_footer, sizeof(crw_footer), 12); +} + +/*@ + @ requires buffer_size >= 6+8; + @ requires separation: \separated(&file_hint_crw, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_crw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(((buffer[0]==0x49 && buffer[1]==0x49)||(buffer[0]==0x4D && buffer[1]==0x4D)) + && memcmp(buffer+6,"HEAPCCDR",8)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_crw.extension; + file_recovery_new->file_check=&file_check_crw; + return 1; + } + return 0; +} + +static void register_header_check_crw(file_stat_t *file_stat) +{ + static const unsigned char crw_header_be[2]= {'I','I'}; + static const unsigned char crw_header_le[2]= {'M','M'}; + register_header_check(0, crw_header_be, sizeof(crw_header_be), &header_check_crw, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, crw_header_le, sizeof(crw_header_le), &header_check_crw, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_csh.c b/subprojects/lib/src/file_csh.c new file mode 100644 index 0000000..e520655 --- /dev/null +++ b/subprojects/lib/src/file_csh.c @@ -0,0 +1,67 @@ +/* + + File: file_csh.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_csh) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_csh(file_stat_t *file_stat); + +const file_hint_t file_hint_csh= { + .extension="csh", + .description="Adobe Custom shapes", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_csh +}; + +/*@ + @ requires separation: \separated(&file_hint_csh, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_csh(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_csh.extension; + return 1; +} + +static void register_header_check_csh(file_stat_t *file_stat) +{ + static const unsigned char csh_header[10]= { + 'c' , 'u' , 's' , 'h' , 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00 + }; + register_header_check(0, csh_header, sizeof(csh_header), &header_check_csh, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ctg.c b/subprojects/lib/src/file_ctg.c new file mode 100644 index 0000000..f8c9eec --- /dev/null +++ b/subprojects/lib/src/file_ctg.c @@ -0,0 +1,64 @@ +/* + + File: file_ctg.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ctg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ctg(file_stat_t *file_stat); + +const file_hint_t file_hint_ctg= { + .extension="ctg", + .description="Canon catalog", + .max_filesize=4634, + .recover=0, + .enable_by_default=1, + .register_header_check=®ister_header_check_ctg +}; + +/*@ + @ requires separation: \separated(&file_hint_ctg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ctg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ctg.extension; + return 1; +} + +static void register_header_check_ctg(file_stat_t *file_stat) +{ + static const unsigned char ctg_header[7]= {':','\\','D','C','I','M','\\'}; + register_header_check(1, ctg_header,sizeof(ctg_header), &header_check_ctg, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_cwk.c b/subprojects/lib/src/file_cwk.c new file mode 100644 index 0000000..6b24c1c --- /dev/null +++ b/subprojects/lib/src/file_cwk.c @@ -0,0 +1,104 @@ +/* + + File: file_cwk.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cwk) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_cwk(file_stat_t *file_stat); + +const file_hint_t file_hint_cwk= { + .extension="cwk", + .description="AppleWorks", + .max_filesize=200*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_cwk +}; + +/* http://wiki.wirelust.com/x/index.php/AppleWorks_/_ClarisWorks */ +struct cwk_header +{ + unsigned char major_version; + unsigned char minor_version[3]; + uint32_t creator_type; /* BOBO */ + unsigned char old_major_version; + unsigned char old_minor_version[3]; + uint64_t reserved0; + uint16_t reserved1; + uint16_t marker; + uint16_t unk1; + uint32_t unk2; + uint16_t height; + uint16_t width; + uint16_t margins[6]; + uint16_t inner_height; + uint16_t inner_width; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_cwk; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @ + @*/ +static void file_check_cwk(file_recovery_t *file_recovery) +{ + const unsigned char cwk_footer[4]= {0xf0, 0xf1, 0xf2, 0xf3}; + file_search_footer(file_recovery, cwk_footer, sizeof(cwk_footer), 4); +} + +/*@ + @ requires buffer_size >= sizeof(struct cwk_header); + @ requires separation: \separated(&file_hint_cwk, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_cwk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct cwk_header *cwk=(const struct cwk_header *)buffer; + if(be64(cwk->reserved0)!=0 || be16(cwk->reserved1)!=1) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_cwk.extension; + file_recovery_new->file_check=&file_check_cwk; + return 1; +} + +static void register_header_check_cwk(file_stat_t *file_stat) +{ + static const unsigned char cwk_header[4]= {'B','O','B','O'}; + register_header_check(4, cwk_header,sizeof(cwk_header), &header_check_cwk, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_d2s.c b/subprojects/lib/src/file_d2s.c new file mode 100644 index 0000000..7832007 --- /dev/null +++ b/subprojects/lib/src/file_d2s.c @@ -0,0 +1,99 @@ +/* + + File: file_d2s.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_d2s) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_d2s(file_stat_t *file_stat); + +const file_hint_t file_hint_d2s= { + .extension="d2s", + .description="Diablo II", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_d2s +}; + +struct d2s_header { + char magic[8]; + uint32_t size; + uint32_t unk1; + uint32_t unk2; +// char name[0]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename==&file_rename_d2s; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_d2s(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + int buffer_size; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + file_rename(file_recovery, buffer, buffer_size, 0x14, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct d2s_header); + @ requires separation: \separated(&file_hint_d2s, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_d2s(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct d2s_header *d2s=(const struct d2s_header*)buffer; + if(le32(d2s->size) < sizeof(struct d2s_header)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_d2s.extension; + file_recovery_new->calculated_file_size=le32(d2s->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_d2s; + return 1; +} + +static void register_header_check_d2s(file_stat_t *file_stat) +{ + static const unsigned char d2s_header[8]= { + 0x55, 0xaa, 0x55, 0xaa, 0x60, 0x00, 0x00, 0x00 + }; + register_header_check(0, d2s_header,sizeof(d2s_header), &header_check_d2s, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dad.c b/subprojects/lib/src/file_dad.c new file mode 100644 index 0000000..d9d06a7 --- /dev/null +++ b/subprojects/lib/src/file_dad.c @@ -0,0 +1,123 @@ +/* + + File: file_dad.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dad) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dad(file_stat_t *file_stat); + +const file_hint_t file_hint_dad= { + .extension="dad", + .description="Micae DVR", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dad +}; + +struct dad_header +{ + uint32_t magic; + uint32_t unk1; + uint32_t unk2; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_dad; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_dad(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 16; */ + const struct dad_header *dad=(const struct dad_header *)&buffer[i]; + /*@ assert \valid_read(dad); */ + const unsigned int size=le32(dad->size); +#ifdef DEBUG_DAD + log_info("%llu magic %08x => %llu\n", + (long long unsigned)file_recovery->calculated_file_size, le32(dad->magic), + (long long unsigned)file_recovery->calculated_file_size + size); +#endif + if(dad->magic!=le32(0x56414844) || size<16) + return DC_STOP; + file_recovery->calculated_file_size+=size; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_dad, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_dad(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct dad_header *dad=(const struct dad_header *)buffer; + const unsigned int size=le32(dad->size); + if(size<16) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_dad && + file_recovery->calculated_file_size==file_recovery->file_size) + { + /*@ assert \valid_function(file_recovery->file_check); */ + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dad.extension; + file_recovery_new->min_filesize=size; + if(file_recovery_new->blocksize >= 16) + { + file_recovery_new->data_check=&data_check_dad; + file_recovery_new->file_check=&file_check_size_max; + } + return 1; +} + +static void register_header_check_dad(file_stat_t *file_stat) +{ + register_header_check(0, "DHAV", 4, &header_check_dad, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dar.c b/subprojects/lib/src/file_dar.c new file mode 100644 index 0000000..243bfab --- /dev/null +++ b/subprojects/lib/src/file_dar.c @@ -0,0 +1,73 @@ +/* + + File: file_dar.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dar) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dar(file_stat_t *file_stat); + +const file_hint_t file_hint_dar= { + .extension="dar", + .description="dar archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dar +}; + +/*@ + @ requires buffer_size >= 0x10; + @ requires separation: \separated(&file_hint_dar, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dar(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* http://darbinding.sourceforge.net/specs/dar3.html */ + if((buffer[0xe]=='N' || buffer[0xe]=='T') && + (buffer[0xf]=='N' || buffer[0xf]=='S')) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dar.extension; + return 1; + } + return 0; +} + +static void register_header_check_dar(file_stat_t *file_stat) +{ + static const unsigned char dar_header[4]= { + 0, 0, 0, 0x7b + }; + register_header_check(0, dar_header, sizeof(dar_header), &header_check_dar, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dat.c b/subprojects/lib/src/file_dat.c new file mode 100644 index 0000000..01cbcb3 --- /dev/null +++ b/subprojects/lib/src/file_dat.c @@ -0,0 +1,125 @@ +/* + + File: file_dat.c + + Copyright (C) 2007,2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dat) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dat(file_stat_t *file_stat); + +const file_hint_t file_hint_dat= { + .extension="dat", + .description="IE History, Glavna Knjiga account data", + .max_filesize=2*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dat +}; + +/*@ + @ requires separation: \separated(&file_hint_dat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dat.extension; + file_recovery_new->min_filesize=8; + return 1; +} + +/*@ + @ requires buffer_size >= 0x20; + @ requires separation: \separated(&file_hint_dat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_datIE(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=(uint64_t)buffer[0x1C]+(((uint64_t)buffer[0x1D])<<8)+(((uint64_t)buffer[0x1E])<<16)+(((uint64_t)buffer[0x1F])<<24); + if(size < 0x20) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dat.extension; + file_recovery_new->min_filesize=0x20; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires buffer_size >= 0x30+12; + @ requires separation: \separated(&file_hint_dat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dat_history4(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x30], "BrowserVisit", 12)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dat.extension; + file_recovery_new->min_filesize=60; + return 1; +} + +/*@ + @ requires buffer_size >= 0x36+12; + @ requires separation: \separated(&file_hint_dat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dat_history10(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x36], "BrowserVisit", 12)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dat.extension; + file_recovery_new->min_filesize=66; + return 1; +} + +static void register_header_check_dat(file_stat_t *file_stat) +{ + static const unsigned char dat_header[8]= {0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + /* Found on Sony Ericson phone */ + static const unsigned char dat_history[8]={ 'N', 'F', 'P', 'K', 'D', 'D', 'A', 'T'}; + register_header_check(0, dat_header,sizeof(dat_header), &header_check_dat, file_stat); + register_header_check(0, "Client UrlCache MMF Ver 5.2", 0x1c, &header_check_datIE, file_stat); + register_header_check(4, dat_history, sizeof(dat_history), &header_check_dat_history4, file_stat); + register_header_check(10, dat_history, sizeof(dat_history), &header_check_dat_history10, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dbf.c b/subprojects/lib/src/file_dbf.c new file mode 100644 index 0000000..3ae3022 --- /dev/null +++ b/subprojects/lib/src/file_dbf.c @@ -0,0 +1,76 @@ +/* + + File: file_dbf.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dbf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dbf(file_stat_t *file_stat); + +const file_hint_t file_hint_dbf= { + .extension="dbf", + .description="DBase 3, prone to false positive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_dbf +}; + +/*@ + @ requires buffer_size >= 32; + @ requires separation: \separated(&file_hint_dbf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dbf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* 0x03 YY MM DD reserved=0 */ + if(buffer[0]==0x3 && ((buffer[1]>80 && buffer[1]<120) || buffer[1]<20) && + (buffer[2]>=1 && buffer[2]<=12) && (buffer[3]>=1 && buffer[3]<=31) && + buffer[12]==0 && buffer[13]==0 && buffer[14]==0 && buffer[15]==0 && + buffer[16]==0 && buffer[17]==0 && buffer[18]==0 && buffer[19]==0 && + buffer[20]==0 && buffer[21]==0 && buffer[22]==0 && buffer[23]==0 && + buffer[24]==0 && buffer[25]==0 && buffer[26]==0 && buffer[27]==0 && + buffer[30]==0 && buffer[31]==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dbf.extension; + return 1; + } + return 0; +} + +static void register_header_check_dbf(file_stat_t *file_stat) +{ + static const unsigned char dbf_header[1]= {0x3}; + register_header_check(0, dbf_header,sizeof(dbf_header), &header_check_dbf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dbn.c b/subprojects/lib/src/file_dbn.c new file mode 100644 index 0000000..c3898a4 --- /dev/null +++ b/subprojects/lib/src/file_dbn.c @@ -0,0 +1,71 @@ +/* + + File: file_dbn.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dbn) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "memmem.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dbn(file_stat_t *file_stat); + +const file_hint_t file_hint_dbn= { + .extension="dbn", + .description="DriftBox", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dbn +}; + +/*@ + @ requires buffer_size >= 512; + @ requires separation: \separated(&file_hint_dbn, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dbn(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(td_memmem(buffer, 512, "[HEADER]", 8)==NULL) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dbn.extension; + return 1; +} + +static void register_header_check_dbn(file_stat_t *file_stat) +{ + static const unsigned char dbn_header[16]= { + 'F' , 'i' , 'l' , 'e' , ' ' , 'c' , 'r' , 'e' , + 'a' , 't' , 'e' , 'd' , ' ' , 'o' , 'n' , ' ' + }; + register_header_check(0, dbn_header, sizeof(dbn_header), &header_check_dbn, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dcm.c b/subprojects/lib/src/file_dcm.c new file mode 100644 index 0000000..832f009 --- /dev/null +++ b/subprojects/lib/src/file_dcm.c @@ -0,0 +1,66 @@ +/* + + File: file_dcm.c + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dcm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dcm(file_stat_t *file_stat); + +const file_hint_t file_hint_dcm= { + .extension="dcm", + .description="Digital Imaging and Communications in Medicine (DICOM)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dcm +}; + +/*@ + @ requires separation: \separated(&file_hint_dcm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dcm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dcm.extension; + return 1; +} + +static void register_header_check_dcm(file_stat_t *file_stat) +{ + static const unsigned char dcm_header[10]= { + 'D' , 'I' , 'C' , 'M' , 0x02, 0x00, 0x00, 0x00, + 'U' , 'L' }; + register_header_check(0x80, dcm_header, sizeof(dcm_header), &header_check_dcm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ddf.c b/subprojects/lib/src/file_ddf.c new file mode 100644 index 0000000..7ec5d89 --- /dev/null +++ b/subprojects/lib/src/file_ddf.c @@ -0,0 +1,172 @@ +/* + + File: file_ddf.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ddf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_TIME_H +#include +#endif +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ddf(file_stat_t *file_stat); + +const file_hint_t file_hint_ddf= { + .extension="ddf", + .description="Didson Data File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ddf +}; + +struct MasterHeader +{ + uint32_t m_nVersion; // VERSION_DDF_03 = 0x03464444 + uint32_t m_nFrameTotal; + uint32_t m_nFrameRate; // requested frame rate...actual rate may differ + uint32_t m_bHighResolution; + uint32_t m_nNumRawBeams; // Std HF = 96, Std LF and LR HF/LF = 48, may be 64 or 128 if v5 + float m_fSampleRate; // dependent on Window Length + uint32_t m_nSamplesPerChannel; // always 512 + uint32_t m_nReceiverGain; // relative value, 0-40 dB + uint32_t m_nWindowStart; // code: value in master header is initial value + uint32_t m_nWindowLength; // code: value in master header is initial value + uint32_t m_bReverse; // TRUE if lens down orientation + uint32_t m_nSN; // serial number of sonar + char m_cDate[32]; // date string + char m_cHeaderID[256]; // annotation string + int32_t m_iUserID1; // Four user ID values displayed in header pane + int32_t m_iUserID2; // These values are inserted by user external via + int32_t m_iUserID3; // the Edit->Header ID command + int32_t m_iUserID4; + uint32_t m_nStartFrame; // for snippet or truncated file, from source file + uint32_t m_nEndFrame; // for snippet or truncated file, from source file + uint32_t m_bTimeLapse; // flag for time lapse data recording + uint32_t m_nRecordInterval; // interval between saved frames (N seconds) + int32_t m_iRadioSeconds; // 0 = N frames interval, 1 = N seconds interval + uint32_t m_nFrameInterval; // interval between saved frames (N frames) + uint32_t m_nFlags; // save displayed processing flags (see Table 1) + uint32_t m_nAuxFlags; // types of aux information present (see Table 2) + uint32_t m_nSspd; // sound velocity in water from DidsonV6.ini + uint32_t m_n3DFlags; // reserved...currently unused + /* Fields for v4 are added here*/ + char m_cRsvdData[120]; // (120) pad to 512 bytes +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(buffer+(0..sizeof(struct MasterHeader)-1)); + @ requires \valid(file_recovery_new); + @ requires separation: \separated(&file_hint_ddf, buffer+(..), file_recovery_new); + @ ensures \result == 1; + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_aux(const unsigned char *buffer, file_recovery_t *file_recovery_new) +{ + const char *date_asc=(const char *)&buffer[0x3f]; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ddf.extension; + if(date_asc[4]=='-' && date_asc[7]=='-' && date_asc[10]=='_') + { + file_recovery_new->time=get_time_from_YYYY_MM_DD_HHMMSS(date_asc); + } + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(struct MasterHeader); + @ requires separation: \separated(&file_hint_ddf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ddf3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct MasterHeader *h=(const struct MasterHeader *)buffer; + if(le32(h->m_nNumRawBeams)!=96 && le32(h->m_nNumRawBeams)!=48) + return 0; + if(le32(h->m_nSamplesPerChannel)!=512) + return 0; + return header_check_aux(buffer, file_recovery_new); +} + +/*@ + @ requires buffer_size >= sizeof(struct MasterHeader); + @ requires separation: \separated(&file_hint_ddf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ddf4(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct MasterHeader *h=(const struct MasterHeader *)buffer; + if(le32(h->m_nNumRawBeams)!=96 && le32(h->m_nNumRawBeams)!=48) + return 0; + if(le32(h->m_nSamplesPerChannel)!=512) + return 0; + return header_check_aux(buffer, file_recovery_new); +} + +/*@ + @ requires buffer_size >= sizeof(struct MasterHeader); + @ requires separation: \separated(&file_hint_ddf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ddf5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct MasterHeader *h=(const struct MasterHeader *)buffer; + switch(le32(h->m_nNumRawBeams)) + { + case 48: + case 96: + case 64: + case 128: + break; + default: + return 0; + } + if(le32(h->m_nSamplesPerChannel)<512 || le32(h->m_nSamplesPerChannel)>4096) + return 0; + return header_check_aux(buffer, file_recovery_new); +} + +static void register_header_check_ddf(file_stat_t *file_stat) +{ + static const unsigned char ddf3_header[4]= { 'D' , 'D' , 'F' , 0x03 }; + static const unsigned char ddf4_header[4]= { 'D' , 'D' , 'F' , 0x04 }; + static const unsigned char ddf5_header[4]= { 'D' , 'D' , 'F' , 0x05 }; + register_header_check(0, ddf3_header, sizeof(ddf3_header), &header_check_ddf3, file_stat); + register_header_check(0, ddf4_header, sizeof(ddf4_header), &header_check_ddf4, file_stat); + register_header_check(0, ddf5_header, sizeof(ddf5_header), &header_check_ddf5, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dex.c b/subprojects/lib/src/file_dex.c new file mode 100644 index 0000000..c0f3942 --- /dev/null +++ b/subprojects/lib/src/file_dex.c @@ -0,0 +1,105 @@ +/* + + File: file_dex.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dex) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dex(file_stat_t *file_stat); + +const file_hint_t file_hint_dex= { + .extension="dex", + .description="Dalvik", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dex +}; + +/* More information can be found at https://source.android.com/devices/tech/dalvik/dex-format.html */ +struct dex_header +{ + unsigned char magic[8]; + uint32_t checksum; + unsigned char signature[20]; + uint32_t file_size; + uint32_t header_size; + uint32_t endian_tag; + uint32_t link_size; + uint32_t link_off; + uint32_t map_off; + uint32_t strings_ids_size; + uint32_t strings_ids_off; + uint32_t type_ids_size; + uint32_t type_ids_off; + uint32_t proto_ids_size; + uint32_t proto_ids_off; + uint32_t field_ids_size; + uint32_t field_ids_off; + uint32_t method_ids_size; + uint32_t method_ids_off; + uint32_t class_def_size; + uint32_t class_def_off; + uint32_t data_size; + uint32_t data_off; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct dex_header); + @ requires separation: \separated(&file_hint_dex, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dex(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct dex_header *dex=(const struct dex_header*)buffer; + if(!isdigit(buffer[4]) || !isdigit(buffer[5]) || !isdigit(buffer[6]) || buffer[7]!=0x00) + return 0; + if(le32(dex->header_size) < 0x28) + return 0; + if(le32(dex->header_size) >= le32(dex->file_size)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dex.extension; + file_recovery_new->calculated_file_size=le32(dex->file_size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_dex(file_stat_t *file_stat) +{ + static const unsigned char dex_header[4]= {'d','e','x','\n'}; + register_header_check(0, dex_header,sizeof(dex_header), &header_check_dex, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dim.c b/subprojects/lib/src/file_dim.c new file mode 100644 index 0000000..c175ee6 --- /dev/null +++ b/subprojects/lib/src/file_dim.c @@ -0,0 +1,63 @@ +/* + + File: file_dim.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dim) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dim(file_stat_t *file_stat); + +const file_hint_t file_hint_dim= { + .extension="diskimage", + .description="SunPCI Disk Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dim +}; + +/*@ + @ requires separation: \separated(&file_hint_dim, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dim(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dim.extension; + return 1; +} + +static void register_header_check_dim(file_stat_t *file_stat) +{ + static const unsigned char dim_header[4]= { 'S', 'P','C','I'}; + register_header_check(0x0c, dim_header,sizeof(dim_header), &header_check_dim, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dir.c b/subprojects/lib/src/file_dir.c new file mode 100644 index 0000000..fb6ac6d --- /dev/null +++ b/subprojects/lib/src/file_dir.c @@ -0,0 +1,119 @@ +/* + + File: file_dir.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dir) || defined(MAIN_photorec) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "fat_common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dir(file_stat_t *file_stat); + +const file_hint_t file_hint_dir= { + .extension="fat", + .description="FAT subdirectory", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=0, + .enable_by_default=1, + .register_header_check=®ister_header_check_dir +}; + +/*@ + @ requires file_recovery->file_rename==&file_rename_fatdir; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_fatdir(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + char buffer_cluster[32]; + FILE *file; + int buffer_size; + unsigned int cluster; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size<32) + return; + /*@ assert buffer_size >= 32; */ + cluster=fat_get_cluster_from_entry((const struct msdos_dir_entry *)&buffer[0]); + sprintf(buffer_cluster, "cluster_%u", cluster); +#if defined(__FRAMAC__) + buffer_cluster[sizeof(buffer_cluster)-1]='\0'; +#endif + file_rename(file_recovery, buffer_cluster, strlen(buffer_cluster), 0, NULL, 1); +} + +/*@ + @ requires file_recovery->data_check == &data_check_fatdir; + @ requires buffer_size >= 2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures \result == DC_STOP; + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_fatdir(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /* Save only one cluster */ + file_recovery->calculated_file_size=buffer_size/2; + return DC_STOP; +} + +/*@ + @ requires buffer_size >= sizeof(struct msdos_dir_entry); + @ requires separation: \separated(&file_hint_dir, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dir(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct msdos_dir_entry *de=(const struct msdos_dir_entry*)buffer; + if(!is_fat_directory(buffer)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dir.extension; + file_recovery_new->data_check=&data_check_fatdir; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_fatdir; + file_recovery_new->time=date_dos2unix(le16(de->time),le16(de->date)); + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +static void register_header_check_dir(file_stat_t *file_stat) +{ + register_header_check(0, ". ", 8+3, &header_check_dir, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_djv.c b/subprojects/lib/src/file_djv.c new file mode 100644 index 0000000..046b595 --- /dev/null +++ b/subprojects/lib/src/file_djv.c @@ -0,0 +1,80 @@ +/* + + File: file_djv.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_djv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_djv(file_stat_t *file_stat); + +const file_hint_t file_hint_djv= { + .extension="djv", + .description="DjVu", + .max_filesize=200*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_djv +}; + +struct djv_header +{ + uint32_t magic; + uint32_t type; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct djv_header); + @ requires separation: \separated(&file_hint_djv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_djv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct djv_header *hdr=(const struct djv_header *)buffer; + const uint64_t size=be32(hdr->size); + if(size==0 || size +12 > file_hint_djv.max_filesize) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_djv.extension; + file_recovery_new->calculated_file_size=size+12; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_djv(file_stat_t *file_stat) +{ + static const unsigned char djv_header[8]= { 'A','T','&','T','F','O','R','M'}; + register_header_check(0, djv_header,sizeof(djv_header), &header_check_djv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dmp.c b/subprojects/lib/src/file_dmp.c new file mode 100644 index 0000000..706d605 --- /dev/null +++ b/subprojects/lib/src/file_dmp.c @@ -0,0 +1,70 @@ +/* + + File: file_dmp.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dmp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dmp(file_stat_t *file_stat); + +const file_hint_t file_hint_dmp= { + .extension="dmp", + .description="Oracle Dump (export)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dmp +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_dmp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[11] < '0' || buffer[11] > '9') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dmp.extension; + return 1; +} + +static void register_header_check_dmp(file_stat_t *file_stat) +{ + static const unsigned char dmp_header[11]= { + 0x03, 0x00, 0x01, 'E', 'X', 'P', 'O', 'R', + 'T', ':', 'V' + }; + register_header_check(0, dmp_header, sizeof(dmp_header), &header_check_dmp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_doc.c b/subprojects/lib/src/file_doc.c new file mode 100644 index 0000000..616de46 --- /dev/null +++ b/subprojects/lib/src/file_doc.c @@ -0,0 +1,1918 @@ +/* + + File: file_doc.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_doc) || defined(SINGLE_FORMAT_snag) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "ole.h" +#include "log.h" +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_doc) +#include "memmem.h" +#endif +#include "setdate.h" +#include "file_doc.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +static const char *extension_albm="albm"; +static const char *extension_amb="amb"; +static const char *extension_apr="apr"; +static const char *extension_camrec="camrec"; +static const char *extension_db="db"; +static const char *extension_dgn="dgn"; +static const char *extension_doc="doc"; +static const char *extension_emb="emb"; +static const char *extension_et="et"; +static const char *extension_fla="fla"; +static const char *extension_ipt="ipt"; +static const char *extension_jnb="jnb"; +static const char *extension_max="max"; +static const char *extension_mdb="mdb"; +static const char *extension_mws="mws"; +static const char *extension_msg="msg"; +static const char *extension_p65="p65"; +static const char *extension_ppt="ppt"; +static const char *extension_psmodel="psmodel"; +static const char *extension_pub="pub"; +static const char *extension_qbb="qbb"; +static const char *extension_qdf_backup="qdf-backup"; +static const char *extension_qpw="qpw"; +static const char *extension_rvt="rvt"; +static const char *extension_sda="sda"; +static const char *extension_sdc="sdc"; +static const char *extension_sdd="sdd"; +static const char *extension_sdw="sdw"; +#ifdef DJGPP +static const char *extension_sldprt="sld"; +#else +static const char *extension_sldprt="sldprt"; +#endif +static const char *extension_snt="snt"; +static const char *extension_tcw="tcw"; +static const char *extension_vsd="vsd"; +static const char *extension_wps="wps"; +static const char *extension_xlr="xlr"; +static const char *extension_xls="xls"; +static const char *extension_wdb="wdb"; + +/*@ + @ requires \valid(IN); + @ requires (9 == uSectorShift) || (12 == uSectorShift); + @ requires \valid( buf + (0 .. (1< \initialized(buf + (0 .. (1<num_FAT_blocks) > 0; + @ requires 0 <= le32(header->num_extra_FAT_blocks)<= 50; + @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift); + @ requires le32(header->num_FAT_blocks) <= 109+le32(header->num_extra_FAT_blocks)*((1<uSectorShift))/4-1); + @ requires \separated(IN, header); + @ ensures \result==\null || \valid_read((const char *)\result + ( 0 .. (le32(header->num_FAT_blocks)<uSectorShift))-1)); + @*/ +static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset) +{ + char *data; + uint32_t *fat; + const uint32_t *dif; + const unsigned int uSectorShift=le16(header->uSectorShift); + const unsigned int num_FAT_blocks=le32(header->num_FAT_blocks); + const unsigned int num_extra_FAT_blocks=le32(header->num_extra_FAT_blocks); + /*@ assert uSectorShift == le16(header->uSectorShift); */ + /*@ assert num_FAT_blocks==le32(header->num_FAT_blocks); */ + /*@ assert num_FAT_blocks <= 109+le32(header->num_extra_FAT_blocks)*((1< 0) + { /* Load DIF*/ + unsigned long int i; + for(i=0; iFAT_next_block): le32(dif[109+i*(((1<= num_FAT_blocks<file_size; + unsigned int uSectorShift; + unsigned int num_FAT_blocks; + file_recovery->file_size=offset; + /*reads first sector including OLE header */ + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 || + fread(&buffer_header, sizeof(buffer_header), 1, file_recovery->handle) != 1) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer_header, sizeof(buffer_header)); +#endif + uSectorShift=le16(header->uSectorShift); + num_FAT_blocks=le32(header->num_FAT_blocks); + /* Sanity check */ + if( uSectorShift != 9 && uSectorShift != 12) + return ; + /*@ assert 9 == uSectorShift || 12 == uSectorShift; */ +#ifdef DEBUG_OLE + log_info("file_check_doc %s\n", file_recovery->filename); + log_trace("sector size %u\n",1<num_extra_FAT_blocks)); +#endif + if(num_FAT_blocks==0 || + le32(header->num_extra_FAT_blocks)>50) + return ; + /*@ assert num_FAT_blocks > 0; */ + /*@ assert 0 <= le32(header->num_extra_FAT_blocks) <= 50; */ + if(num_FAT_blocks > 109+le32(header->num_extra_FAT_blocks)*((1<num_extra_FAT_blocks)*((1<handle, header, offset))==NULL) + { +#ifdef DEBUG_OLE + log_info("OLE_load_FAT failed\n"); +#endif + return ; + } + /* Search how many entries are not used at the end of the FAT */ + { + const unsigned int val_max=(num_FAT_blocks< doc_file_size_org) + { +#ifdef DEBUG_OLE + log_info("doc_file_size=%llu + (1+(%u<<%u)/4-%u)<<%u\n", + (unsigned long long)offset, + num_FAT_blocks, uSectorShift, + freesect_count, uSectorShift); + log_info("doc_file_size %llu > doc_file_size_org %llu\n", + (unsigned long long)doc_file_size, (unsigned long long)doc_file_size_org); +#endif + free(fat); + return ; + } +#ifdef DEBUG_OLE + log_trace("==> size : %llu\n", (long long unsigned)doc_file_size); +#endif + { + unsigned int block; + const unsigned int fat_entries=(num_FAT_blocks==0 ? + 109: + (num_FAT_blocks<root_start_block), fat_entries); +#endif + /* FFFFFFFE = ENDOFCHAIN + * Use a loop count i to avoid endless loop */ + for(block=le32(header->root_start_block), i=0; + block!=0xFFFFFFFE && ihandle, (char *)dir_entries, uSectorShift, block, offset)<0) + { +#ifdef DEBUG_OLE + log_info("OLE_read_block failed\n"); +#endif + free(dir_entries); + free(fat); + return ; + } + { + unsigned int sid; + for(sid=0; + sid<(1<type==NO_ENTRY) + break; + if(offset + + le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 && + ((le32(dir_entry->size) >= le32(header->miniSectorCutoff) + && le32(dir_entry->start_block) > fat_entries) || + le32(dir_entry->size) > doc_file_size)) + { +#ifdef DEBUG_OLE + log_info("error at sid %u\n", sid); +#endif + free(dir_entries); + free(fat); + return ; + } + } + } + free(dir_entries); + } + } + free(fat); + file_recovery->file_size=doc_file_size; +} +#endif + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_doc) +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_doc(file_stat_t *file_stat); + +const file_hint_t file_hint_doc= { + .extension="doc", + .description="Microsoft Office Document (doc/xls/ppt/vsd/...), 3ds Max, MetaStock, Wilcom ES", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_doc +}; + +const char WilcomDesignInformationDDD[56]= +{ + 0x05, '\0', 'W', '\0', 'i', '\0', 'l', '\0', + 'c', '\0', 'o', '\0', 'm', '\0', 'D', '\0', + 'e', '\0', 's', '\0', 'i', '\0', 'g', '\0', + 'n', '\0', 'I', '\0', 'n', '\0', 'f', '\0', + 'o', '\0', 'r', '\0', 'm', '\0', 'a', '\0', + 't', '\0', 'i', '\0', 'o', '\0', 'n', '\0', + 'D', '\0', 'D', '\0', 'D', '\0', '\0', '\0' +}; + +/*@ + @ requires file_recovery->file_check == &file_check_doc; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +static void file_check_doc(file_recovery_t *file_recovery) +{ + file_check_doc_aux(file_recovery, 0); +} + +/*@ + @ requires \valid_read(dir_entry); + @ requires \initialized(dir_entry); + @ assigns \nothing; + @ ensures \result == \null || valid_read_string(\result); + @*/ +static const char *entry2ext(const struct OLE_DIR *dir_entry) +{ + switch(le16(dir_entry->namsiz)) + { + case 10: + if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0) + return extension_qdf_backup; + break; + case 12: + /* 3ds max */ + if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0) + return extension_max; + /* Licom AlphaCAM */ + else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0) + return extension_amb; + break; + case 18: + /* Microsoft Works .wps */ + if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0) + return extension_wps; + break; + case 20: + /* Page Maker */ + if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0) + return extension_p65; + break; + case 22: + /* SigmaPlot .jnb */ + if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0\0", 22)==0) + return extension_jnb; + /* Autodesk Inventor part ipt or iam file */ + if(memcmp(dir_entry->name, "R\0S\0e\0S\0t\0o\0r\0a\0g\0e\0\0\0", 22)==0) + return extension_ipt; + break; + case 24: + /* HP Photosmart Photo Printing Album */ + if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0) + return extension_albm; + /* Lotus Approch */ + if(memcmp(dir_entry->name,"A\0p\0p\0r\0o\0a\0c\0h\0D\0o\0c\0\0\0",24)==0) + return extension_apr; + break; + case 28: + /* Microsoft Works Spreadsheet or Chart */ + if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0) + return extension_xlr; + /* Visio */ + else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0) + return extension_vsd; + /* SolidWorks */ + else if(memcmp(&dir_entry->name,"s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0",28)==0) + return extension_sldprt; + break; + case 32: + if(memcmp(dir_entry->name, "m\0a\0n\0i\0f\0e\0s\0t\0.\0c\0a\0m\0x\0m\0l\0\0\0",32)==0) + return extension_camrec; + /* Revit */ + if(memcmp(dir_entry->name, "R\0e\0v\0i\0t\0P\0r\0e\0v\0i\0e\0w\0004\0.\0000\0\0", 32)==0) + return extension_rvt; + break; + case 34: + if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0) + return extension_sdc; + break; + case 36: + if(memcmp(dir_entry->name, "f\0i\0l\0e\0_\0C\0O\0M\0P\0A\0N\0Y\0_\0F\0I\0L\0E\0\0\0", 36)==0) + return extension_qbb; + break; + case 38: + /* Quattro Pro spreadsheet */ + if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0) + return extension_qpw; + else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0) + return extension_sdw; + break; + case 40: + if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0) + return extension_ppt; + /* Outlook */ + else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0) + return extension_msg; + break; + case 46: + if(memcmp(dir_entry->name, + "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0) + { + return extension_sldprt; + } + break; + case 56: + /* Wilcom ES Software */ + if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0) + return extension_emb; + break; + } + return NULL; +} + +/*@ + @ requires buffer_size >= sizeof(struct OLE_HDR); + @ requires \valid_read((char *)header + (0 .. buffer_size-1)); + @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift); + @ requires le32(header->num_FAT_blocks)>0; + @ requires 0 <= le32(header->num_extra_FAT_blocks) <= 50; + @ ensures \result == \null || valid_read_string(\result); + @ assigns \nothing; + @*/ +static const char *ole_get_file_extension(const struct OLE_HDR *header, const unsigned int buffer_size) +{ + const unsigned char *buffer=(const unsigned char *)header; + unsigned int fat_entries; + unsigned int block; + unsigned int i; + const unsigned int uSectorShift=le16(header->uSectorShift); + unsigned int fat_size; + if(buffer_size<512) + return NULL; + /*@ assert buffer_size >= 512; */ + fat_size=(le32(header->num_FAT_blocks) << uSectorShift); + fat_entries=fat_size/4; + /* FFFFFFFE = ENDOFCHAIN + * Use a loop count i to avoid endless loop */ +#ifdef DEBUG_OLE + log_info("ole_get_file_extension root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries); +#endif + /*@ + @ loop assigns block, i; + @*/ + for(block=le32(header->root_start_block), i=0; + blockbuffer_size-512) + return NULL; + /*@ assert offset_root_dir + 512 <= buffer_size; */ + { + unsigned int sid; + const struct OLE_DIR *dir_entries=(const struct OLE_DIR *)&buffer[offset_root_dir]; + /*@ assert \valid_read((char *)dir_entries + (0 .. 512-1)); */ + /*@ assert \valid_read(dir_entries + (0 .. 512/sizeof(struct OLE_DIR)-1)); */ + const char *ext=NULL; + int is_db=0; + /*@ + @ loop invariant ext == \null || ext == extension_xls || ext == extension_psmodel || ext == extension_snt; + @ loop assigns ext, is_db, sid; + @*/ + for(sid=0; + sid<512/sizeof(struct OLE_DIR); + sid++) + { + const struct OLE_DIR *dir_entry=&dir_entries[sid]; + if(dir_entry->type==NO_ENTRY) + break; +#ifdef DEBUG_OLE + { + unsigned int j; + for(j=0;j<64 && jnamsiz) && dir_entry->name[j]!='\0';j+=2) + { + log_info("%c",dir_entry->name[j]); + } + for(;j<64;j+=2) + log_info(" "); + log_info(" namsiz=%u type %u", le16(dir_entry->namsiz), dir_entry->type); + log_info(" Flags=%s", (dir_entry->bflags==0?"Red ":"Black")); + log_info(" sector %u (%u bytes)\n", + (unsigned int)le32(dir_entry->start_block), + (unsigned int)le32(dir_entry->size)); + } +#endif + { + const char *tmp=entry2ext(dir_entry); + /*@ assert tmp == \null || valid_read_string(tmp); */ + if(tmp!=NULL) + return tmp; + } + switch(le16(dir_entry->namsiz)) + { + case 4: + if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0) + is_db=1; + else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "2\0\0\0", 4)==0) + is_db=2; + break; + case 16: + if(sid==1 && memcmp(dir_entry->name, "d\0o\0c\0.\0d\0e\0t\0\0\0", 16)==0) + ext=extension_psmodel; + /* Windows Sticky Notes */ + else if(sid==1 && memcmp(dir_entry->name, "V\0e\0r\0s\0i\0o\0n\0\0\0", 16)==0) + ext=extension_snt; + else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0\0\0", 16)==0) + is_db=2; + break; + case 18: + /* MS Excel + * Note: Microsoft Works Spreadsheet contains the same signature */ + if(memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0) + ext=extension_xls; + break; + case 36: + /* sda=StarDraw, sdd=StarImpress */ + if(memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0) + return extension_sda; + break; + } + if(sid==1 && memcmp(&dir_entry->name, "D\0g\0n", 6)==0) + return extension_dgn; + } + if(ext!=NULL) + { + /*@ assert ext == extension_xls || ext == extension_psmodel || ext == extension_snt; */ + return ext; + } + /* Thumbs.db */ + if(is_db==2) + return extension_db; + } + { + const uint32_t *fati=(const uint32_t *)(header+1); + const uint64_t fat_offset=((uint64_t)1+le32(fati[0])) << uSectorShift; + unsigned int fat_test_size; + const uint32_t *val32_ptr; + if(fat_offset >= buffer_size) + return NULL; + /*@ assert 0 < fat_offset < buffer_size; */ + fat_test_size=fat_offset+block*4; + if(fat_test_size + 4 > buffer_size) + return NULL; + /*@ assert fat_test_size + 4 <= buffer_size; */ + val32_ptr=(const uint32_t *)&buffer[fat_test_size]; + block=le32(*val32_ptr); + } + } +#ifdef DEBUG_OLE + log_info("Root Directory end\n"); +#endif + return NULL; +} + + +/*@ + @ requires \valid(IN); + @ requires \valid_read(fat + (0 .. fat_entries-1)); + @ requires 9 == uSectorShift || 12 == uSectorShift; + @ requires 0 < len <= 1024*1024; + @ requires \separated(IN, fat + (..), &errno, &Frama_C_entropy_source); + @ ensures \result!=\null ==> \valid((char *)\result + (0 .. len - 1)); + @*/ +static void *OLE_read_stream(FILE *IN, + const uint32_t *fat, const unsigned int fat_entries, const unsigned int uSectorShift, + const unsigned int block_start, const unsigned int len, const uint64_t offset) +{ + //@ split uSectorShift; + char *dataPt; + unsigned int block; + unsigned int i; + const unsigned int i_max=((len+(1<> uSectorShift); +#ifdef __FRAMAC__ + dataPt=(char *)MALLOC(((1024*1024+(1<> uSectorShift) << uSectorShift); +#else + dataPt=(char *)MALLOC(i_max << uSectorShift); +#endif + /*@ assert \valid(dataPt + ( 0 .. len-1)); */ + /*@ + @ loop invariant 0 <= i <= i_max; + @ loop invariant i > 0 ==> \initialized(dataPt + ((i-1)<uSectorShift) || 12 == le16(header->uSectorShift); + @ requires 0 < le32(header->csectMiniFat) <= 2048; + @ ensures \result!=\null ==> \valid((char *)\result + (0 .. (le32(header->csectMiniFat) << le16(header->uSectorShift)) - 1)); + @*/ +static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries, const uint64_t offset) +{ + char *minifat; + unsigned int block; + unsigned int i; + const unsigned int uSectorShift=le16(header->uSectorShift); + /*@ assert uSectorShift==9 || uSectorShift==12; */ + const unsigned int csectMiniFat=le32(header->csectMiniFat); + const unsigned int minifat_length=csectMiniFat << uSectorShift; + if(csectMiniFat==0) + return NULL; + /*@ assert 0 < csectMiniFat; */ + /*@ assert 0 < csectMiniFat <= 2048; */ +#ifdef __FRAMAC__ + minifat=(char *)MALLOC(2048 << 12); +#else + minifat=(char *)MALLOC(minifat_length); +#endif + block=le32(header->MiniFat_block); + /*@ + @ loop invariant 0 <= i <= csectMiniFat; + @ loop variant csectMiniFat-i; + @*/ + for(i=0; i < csectMiniFat; i++) + { + if(block >= fat_entries) + { + free(minifat); + return NULL; + } + if(OLE_read_block(IN, minifat + (i << uSectorShift), uSectorShift, block, offset)<0) + { + free(minifat); + return NULL; + } + block=le32(fat[block]); + } + return (uint32_t *)minifat; +} + +/*@ + @ requires \valid_read((char *)buffer + (offset .. offset + 4 - 1)); + @ requires \initialized((char *)buffer + (offset .. offset + 4 - 1)); + @ assigns \nothing; + @*/ +static uint32_t get32u(const void *buffer, const unsigned int offset) +{ + /*@ assert \valid_read((char *)buffer + offset + (0 .. 4-1)); */ + /*@ assert \initialized((char *)buffer + offset + (0 .. 4-1)); */ + const char *ptr=(const char *)buffer+offset; + /*@ assert \valid_read(ptr + (0 .. 4-1)); */ + /*@ assert \initialized(ptr + (0 .. 4-1)); */ + const uint32_t *val=(const uint32_t *)ptr; + return le32(*val); +} + +/*@ + @ requires \valid_read((char *)buffer + (offset .. offset + 8 - 1)); + @ requires \initialized((char *)buffer + (offset .. offset + 8 - 1)); + @ assigns \nothing; + @*/ +static uint64_t get64u(const void *buffer, const unsigned int offset) +{ + /*@ assert \valid_read((char *)(buffer + offset) + (0 .. 7)); */ + const char *ptr=(const char *)buffer + offset; + /*@ assert \valid_read(ptr + (0 .. 7)); */ + const uint64_t *val=(const uint64_t *)ptr; + return le64(*val); +} + +/*@ + @ requires \valid(ext); + @ requires *ext == \null || valid_read_string(*ext); + @ requires count > 0; + @ requires \valid_read(software + (0 .. count-1)); + @ requires \initialized(software + (0 .. count-1)); + @ requires \initialized(software + (0 .. count-1)); + @ ensures *ext == \null || valid_read_string(*ext); + @ assigns *ext; + @*/ +static void software2ext(const char **ext, const char *software, const unsigned int count) +{ + /*@ assert *ext == \null || valid_read_string(*ext); */ + if(count>=12) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "MicroStation", 12)==0) + { + *ext=extension_dgn; + /*@ assert valid_read_string(*ext); */ + return; + } + } + if(count>=14) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "Microsoft Word", 14)==0) + { + *ext=extension_doc; + /*@ assert valid_read_string(*ext); */ + return; + } + } + if(count>=15) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "Microsoft Excel", 15)==0) + { + if(*ext==NULL || strcmp(*ext,"sldprt")!=0) + { + *ext=extension_xls; + /*@ assert valid_read_string(*ext); */ + } + return; + } + } + if(count>=20) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "Microsoft PowerPoint", 20)==0) + { + *ext=extension_ppt; + /*@ assert valid_read_string(*ext); */ + return; + } + } + if(count>=21) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "Microsoft Office Word", 21)==0) + { + *ext=extension_doc; + /*@ assert valid_read_string(*ext); */ + return; + } + } + if(count==21) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "TurboCAD for Windows", 21)==0) + { + *ext=extension_tcw; + /*@ assert valid_read_string(*ext); */ + return; + } + } + if(count==22) + { + /*@ assert \valid_read(software + (0 .. count-1)); */ + if(memcmp(software, "TurboCAD pour Windows", 22)==0) + { + *ext=extension_tcw; + /*@ assert valid_read_string(*ext); */ + return; + } + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; +} + +/*@ + @ requires count > 0; + @ requires \valid_read(software + (0 .. 2*count-1)); + @ ensures \result == \null || \result == extension_et || \result == extension_psmodel; + @ ensures \result == \null || valid_read_string(\result); + @ assigns \nothing; + @*/ +static const char *software_uni2ext(const char *software, const unsigned int count) +{ + if(count>=15) + { + /*@ assert \valid_read(software + (0 .. 2*count-1)); */ + if(memcmp(software, "M\0i\0c\0r\0o\0s\0o\0f\0t\0 \0E\0x\0c\0e\0l\0", 30)==0) + { + /*@ assert valid_read_string(extension_et); */ + return extension_et; + } + } + if(count>=17) + { + /*@ assert \valid_read(software + (0 .. 2*count-1)); */ + if(memcmp(software, "D\0e\0l\0c\0a\0m\0 \0P\0o\0w\0e\0r\0S\0H\0A\0P\0E\0", 34)==0) + { + /*@ assert valid_read_string(extension_psmodel); */ + return extension_psmodel; + } + } + return NULL; +} + +struct summary_entry +{ + uint32_t tag; + uint32_t offset; +}; + +/*@ + @ requires 8 <= size <= 1024*1024; + @ requires \valid_read(buffer+ (0 .. size-1)); + @ requires \initialized(buffer+ (0 .. size-1)); + @ requires \valid(ext); + @ requires *ext == \null || valid_read_string(*ext); + @ ensures *ext == \null || valid_read_string(*ext); + @ assigns *ext; + @*/ +static void OLE_parse_software_entry(const char *buffer, const unsigned int size, const unsigned int offset, const char **ext) +{ + if(offset >= size - 8) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert offset < size - 8; */ + { + const unsigned int count=get32u(buffer, offset + 4); + const unsigned int offset_soft=offset + 8; + /*@ assert offset_soft == offset + 8; */ + if(count == 0 || count > size) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert 0 < count <= size; */ + if(offset_soft + count > size) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert offset_soft + count <= size; */ + /*@ assert \valid_read(buffer + (0 .. size-1)); */ + /*@ assert \forall int j; (0 <= j < size ) ==> \valid_read(buffer + j + (0 .. size-1-j)); */ + /*@ assert 0 <= offset_soft < size; */ + /*@ assert \valid_read(buffer + offset_soft + (0 .. size - offset_soft -1)); */ + /*@ assert 0 < count <= size - offset_soft; */ + /*@ assert \valid_read(buffer + offset_soft + (0 .. count -1)); */ + + /*@ assert offset_soft + count <= size; */ + /*@ assert count <= size - offset_soft; */ + /*@ assert \valid_read(buffer + (0 .. size-1)); */ + /*@ assert \valid_read(buffer + (0 .. offset_soft + count -1)); */ +#ifdef DEBUG_OLE + { + unsigned int j; + log_info("Software "); + for(j=0; j= size - 8) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert offset < size - 8; */ + { + const unsigned int offset_soft=offset + 8; + /*@ assert offset_soft < size; */ + const unsigned int count=get32u(buffer, offset + 4); + unsigned int count2; + if(count == 0 || count > size/2) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert 0 < count <= size/2; */ + count2=2*count; + /*@ assert 0 < count2 <= size; */ + if(count2 > size - offset_soft) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + return ; + } + /*@ assert count2 <= size - offset_soft; */ + /*@ assert offset_soft + count2 <= size; */ + /*@ assert \valid_read(buffer + (0 .. size - 1)) && \initialized(buffer + (0 .. size - 1)); */ + /*@ assert \valid_read(buffer + (0 .. offset_soft + count2 - 1)); */ +#ifdef DEBUG_OLE + { + unsigned int j; + log_info("Software "); + for(j=0; j < count2; j+=2) + { + /*@ assert 0 <= j < count2; */ + /*@ assert offset_soft + count2 <= size; */ + const unsigned int tmp=offset_soft + j; + /*@ assert tmp < size; */ + log_info("%c", buffer[tmp]); + } + log_info("\n"); + } +#endif + *ext=software_uni2ext(&buffer[offset_soft], count); + } + /*@ assert *ext == \null || valid_read_string(*ext); */ +} + +/*@ + @ requires 8 <= size <= 1024*1024; + @ requires \valid_read(buffer+ (0 .. size-1)); + @ requires \valid(title + (0 .. 1024-1)); + @ requires valid_string(title); + @ requires \initialized(buffer+ (0 .. size-1)); + @ ensures valid_string(title); + @ assigns *(title + (0 .. 1023)); + @*/ +static void OLE_parse_title_entry(const char *buffer, const unsigned int size, const unsigned int offset, char *title) +{ + if(offset + 8 > size) + { + return; + } + /*@ assert offset + 8 <= size; */ + { + /*@ assert \valid_read(buffer + (0 .. size - 1)); */ + const unsigned int count=get32u(buffer, offset + 4); + const unsigned int offset_tmp=offset + 8; + const char *src=(const char *)buffer; + if(count <= 1 || count > size) + { + return; + } + /*@ assert 1 < count <= size; */ + /*@ assert 1 < count <= 1024*1024; */ + if(offset_tmp + count > size) + { + return; + } + /*@ assert offset_tmp + count <= size; */ + /*@ assert \valid_read(src + (0 .. size - 1)); */ + /*@ assert offset_tmp + count <= size; */ + /*@ assert \valid_read(src + (0 .. offset_tmp + count - 1)); */ + /*@ assert \valid_read((src + offset_tmp) + (0 .. count - 1)); */ + /*@ assert \valid_read((src + offset_tmp) + (1 .. count - 1)); */ + /*@ assert \valid_read((char*)src + (0 .. offset_tmp + count - 1)); */ + /*@ assert \valid_read(((char*)(src+offset_tmp))+(0..count-1)); */ + /*@ assert \valid_read(((char*)(src+offset_tmp))+(1..count-1)); */ + /*@ assert \valid_read((char*)(src + offset_tmp)); */ + /*@ assert \valid_read((char*)(src + offset_tmp)) && \valid_read(((char*)(src+offset_tmp))+(1..count-1)); */ + /*@ assert valid_read_or_empty((void const *)(src + offset_tmp), count); */ + /*@ assert valid_read_or_empty((void const *)(src + offset_tmp), count); */ +#ifndef __FRAMAC__ + if(count < 1024) + { + memcpy(title, &src[offset_tmp], count); + title[count]='\0'; + /*@ assert valid_string(title); */ + } + else + { + memcpy(title, &src[offset_tmp], 1023); + title[1023]='\0'; + /*@ assert valid_string(title); */ + } +#endif +#ifdef DEBUG_OLE + log_info("Title %s\n", title); +#endif + } + /*@ assert valid_string(title); */ +} + +/*@ + @ requires 8 <= size <= 1024*1024; + @ requires \valid_read(buffer+ (0 .. size-1)); + @ requires \initialized(buffer+ (0 .. size-1)); + @ requires \valid(file_time); + @ assigns *file_time; + @*/ +static void OLE_parse_filetime_entry(const char *buffer, const unsigned int size, const unsigned int offset, time_t *file_time) +{ + uint64_t tmp; + if(offset + 12 > size) + { + return ; + } + /*@ assert offset + 12 <= size; */ + tmp=get64u(buffer, offset + 4); + tmp/=10000000; + if(tmp > (uint64_t)134774 * 24 * 3600) + { + tmp -= (uint64_t)134774 * 24 * 3600; + *file_time=tmp; + } +} + +/*@ + @ requires 8 <= size <= 1024*1024; + @ requires \valid_read(buffer+ (0 .. size-1)); + @ requires \initialized(buffer+ (0 .. size-1)); + @ requires \valid(ext); + @ requires \valid(title + (0 .. 1024-1)); + @ requires \valid(file_time); + @ requires \valid_read(entry); + @ requires \initialized(entry); + @ requires *ext == \null || valid_read_string(*ext); + @ requires valid_string(title); + @ requires separation: \separated(buffer+(..), ext, title + ( 0 .. 1023), file_time); + @ ensures *ext == \null || valid_read_string(*ext); + @ ensures valid_string(title); + @ assigns *ext, *(title + (0..1023)), *file_time; + @*/ +static void OLE_parse_PropertySet_entry(const char *buffer, const unsigned int size, const struct summary_entry *entry, const char **ext, char *title, time_t *file_time) +{ + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_read_string(title); */ + const unsigned int tag=le32(entry->tag); + const unsigned int offset=le32(entry->offset); + unsigned int type; + if(offset >= size - 4) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return; + } + /*@ assert offset < size - 4; */ + /*@ assert \valid_read(buffer + (0 .. offset + 4 - 1)); */ + type=get32u(buffer, offset); +#ifdef DEBUG_OLE + log_info("entry: tag 0x%x, offset 0x%x, offset + 4 0x%x, type 0x%x\n", + tag, offset, offset + 4, type); +#endif + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + /* tag: Software, type: VT_LPSTR */ + if(tag==0x12 && type==30) + { + /*@ assert valid_string(title); */ + OLE_parse_software_entry(buffer, size, offset, ext); + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return; + } + /* tag: Software, type: VT_LPWSTR */ + if(tag==0x12 && type==31) + { + /*@ assert valid_string(title); */ + OLE_parse_uni_software_entry(buffer, size, offset, ext); + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return; + } + /* tag: title, type: VT_LPSTR */ + if(tag==0x02 && type==30 && title[0]=='\0') + { + OLE_parse_title_entry(buffer, size, offset, title); + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + /* ModifyDate, type=VT_FILETIME */ + if(tag==0x0d && type==64) + { + OLE_parse_filetime_entry(buffer, size, offset, file_time); + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return; + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return; +} + +/*@ + @ requires 8 <= size <= 1024*1024; + @ requires \valid_read(buffer+ (0 .. size-1)); + @ requires \initialized(buffer+ (0 .. size-1)); + @ requires \valid(ext); + @ requires \valid(title + (0 .. 1024-1)); + @ requires \valid(file_time); + @ requires valid_string(title); + @ requires *ext == \null || valid_read_string(*ext); + @ requires separation: \separated(buffer+(..), ext, title + (0 .. 1023), file_time); + @ ensures *ext == \null || valid_read_string(*ext); + @ ensures valid_string(title); + @ assigns *ext, *(title + (0..1023)), *file_time; + @*/ +static void OLE_parse_PropertySet(const char *buffer, const unsigned int size, const char **ext, char *title, time_t *file_time) +{ + const struct summary_entry *entries=(const struct summary_entry *)&buffer[8]; + const unsigned int numEntries=get32u(buffer, 4); + unsigned int i; +#ifdef DEBUG_OLE + log_info("Property Info %u entries - %u bytes\n", numEntries, size); +#endif + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + if(numEntries == 0 || numEntries > 1024*1024) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert 0 < numEntries <= 1024*1024; */ + if(8 + numEntries * 8 > size) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert 8 + numEntries * 8 <= size; */ + /*@ assert numEntries * 8 <= size - 8; */ + /*@ assert numEntries < size/8; */ + if((const char *)&entries[numEntries] > &buffer[size]) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + /*@ assert \valid_read(buffer + (0 .. size - 1)); */ + /*@ assert \valid_read((buffer+8) + (8 .. size - 8 - 1)); */ + /*@ + @ loop invariant *ext == \null || valid_read_string(*ext); + @ loop invariant valid_string(title); + @ loop invariant 0 <= i <= numEntries; + @ loop assigns i, *ext, *(title + (0..1023)), *file_time; + @ loop variant numEntries-i; + @*/ + for(i=0; i size) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert entry_offset + 8 <= size; */ + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + /*@ assert \valid_read(buffer+ (0 .. size-1)); */ + /*@ assert \valid_read(buffer+ (0 .. entry_offset + 8 - 1)); */ + /*@ assert \valid_read(buffer+ (entry_offset .. entry_offset + 8 - 1)); */ + /*@ assert \valid_read(buffer+ entry_offset + ( 0 .. 8 - 1)); */ + entry_ptr=&buffer[entry_offset]; + /*@ assert \valid_read(entry_ptr + ( 0 .. 8 - 1)); */ + /*@ assert \initialized(entry_ptr + ( 0 .. 8 - 1)); */ + entry=(const struct summary_entry *)entry_ptr; + /*@ assert \valid_read(entry); */ + /*@ assert \initialized(entry); */ + OLE_parse_PropertySet_entry(buffer, size, entry, ext, title, file_time); + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ +} + +/*@ + @ requires 48 <= dirLen <= 1024*1024; + @ requires \valid_read(dataPt + (0 .. dirLen-1)); + @ requires \initialized(dataPt + (0 .. dirLen-1)); + @ requires \valid(ext); + @ requires \valid(title + (0 .. 1024-1)); + @ requires \valid(file_time); + @ requires valid_string(title); + @ requires *ext == \null || valid_read_string(*ext); + @ requires separation: \separated(dataPt+(..), ext, title + (0 .. 1023), file_time); + @ ensures *ext == \null || valid_read_string(*ext); + @ ensures valid_string(title); + @ assigns *ext, *(title + (0..1023)), *file_time; + @*/ +static void OLE_parse_summary_aux(const char *dataPt, const unsigned int dirLen, const char **ext, char *title, time_t *file_time) +{ + unsigned int pos; + const unsigned char *udataPt=(const unsigned char *)dataPt; +#ifndef __FRAMAC__ + assert(dirLen >= 48 && dirLen<=1024*1024); +#endif + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ +#ifdef DEBUG_OLE + dump_log(dataPt, dirLen); +#endif + if(udataPt[0]!=0xfe || udataPt[1]!=0xff) + return ; + pos=get32u(dataPt, 44); + if(pos > dirLen - 8) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert 0 <= pos <= dirLen - 8; */ + { + /* PropertySet */ + const unsigned int size=get32u(dataPt, pos); + if(size <= 8 || size > dirLen || pos + size > dirLen) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert size > 8 && size <= dirLen && pos + size <= dirLen; */ + + /*@ assert 0 < dirLen <=1024*1024; */ + /*@ assert \valid_read(dataPt + (0 .. dirLen-1)); */ + /*@ assert pos + size <= dirLen; */ + /*@ assert \valid_read(dataPt + (0 .. pos+size-1)); */ + /*@ assert \valid_read(dataPt + pos + (0 .. size-1)); */ + + /*@ assert 0 < dirLen <=1024*1024; */ + /*@ assert \initialized(dataPt + (0 .. dirLen-1)); */ + /*@ assert pos + size <= dirLen; */ + /*@ ghost int small_dirLen = pos + size; */ + /*@ assert small_dirLen <= dirLen; */ + /*@ assert \initialized(dataPt + (0 .. small_dirLen-1)); */ + + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + OLE_parse_PropertySet(&dataPt[pos], size, ext, title, file_time); + } + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ +} + +/*@ + @ requires \valid_read(ministream + (0 .. ministream_size-1)); + @ requires \valid_read(minifat + (0 .. minifat_entries-1)); + @ requires uMiniSectorShift==6; + @ requires 48 <= len <= 1024*1024; + @ ensures \result!=\null ==> \valid((char *)\result + (0 .. len-1)); + @*/ +static void *OLE_read_ministream(const unsigned char *ministream, + const uint32_t *minifat, const unsigned int minifat_entries, const unsigned int uMiniSectorShift, + const unsigned int miniblock_start, const unsigned int len, const unsigned int ministream_size) +{ + unsigned char *dataPt; + unsigned int mblock=miniblock_start; + unsigned int size_read; +#ifdef __FRAMAC__ + const unsigned int len_aligned=(1024*1024+(1<= minifat_entries) + { + free(dataPt); + return NULL; + } + /* TODO assert mblock < minifat_entries; */ + if(mblock >= ministream_size>>uMiniSectorShift) + { + free(dataPt); + return NULL; + } + memcpy(&dataPt[size_read], &ministream[mblock<uSectorShift) || 12 == le16(header->uSectorShift); + @ requires 6 == le16(header->uMiniSectorShift); + @ requires \valid(ext); + @ requires \valid(title + (0 .. 1024-1)); + @ requires \valid(file_time); + @ requires *ext == \null || valid_read_string(*ext); + @ requires valid_string(title); + @ requires separation: \separated(file,fat+(..), header, ext, title + (0 .. 1023), file_time); + @ ensures *ext == \null || valid_read_string(*ext); + @ ensures valid_string(title); + @*/ +static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries, + const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size, + const unsigned int block, const unsigned int len, const char **ext, char *title, time_t *file_time, + const uint64_t offset) +{ + const unsigned int uSectorShift=le16(header->uSectorShift); + char *summary=NULL; + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + if(len < 48 || len>1024*1024) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert 48 <= len <= 1024*1024; */ + if(len < le32(header->miniSectorCutoff)) + { + if(le32(header->csectMiniFat)==0 || ministream_size == 0) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + if(ministream_size > 1024*1024 || le32(header->csectMiniFat) > 2048) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + /*@ assert 0 < le32(header->csectMiniFat) <= 2048; */ + { + const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << uSectorShift) / 4; + uint32_t *minifat; + unsigned char *ministream; + if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries, offset))==NULL) + { + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ + return ; + } + ministream=(unsigned char *)OLE_read_stream(file, + fat, fat_entries, uSectorShift, + ministream_block, ministream_size, offset); + if(ministream != NULL) + { + summary=(char*)OLE_read_ministream(ministream, + minifat, mini_fat_entries, le16(header->uMiniSectorShift), + block, len, ministream_size); + free(ministream); + } + free(minifat); + } + } + else + summary=(char *)OLE_read_stream(file, + fat, fat_entries, uSectorShift, + block, len, offset); +#if defined(__FRAMAC__) + { + free(summary); + /* OK: 48, 512, 4096, 1024*1024 */ + summary=MALLOC(512); + Frama_C_make_unknown(summary, 512); + /*@ assert \initialized((char *)summary + (0 .. 512 - 1)); */ + OLE_parse_summary_aux(summary, 512, ext, title, file_time); + free(summary); + } +#else + if(summary!=NULL) + { + /*@ assert \initialized(summary + (0 .. len)); */ + OLE_parse_summary_aux(summary, len, ext, title, file_time); + /*@ assert valid_string(title); */ + free(summary); + } +#endif + /*@ assert *ext == \null || valid_read_string(*ext); */ + /*@ assert valid_string(title); */ +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_doc; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_doc(file_recovery_t *file_recovery) +{ + const char *ext=NULL; + char title[1024]; + FILE *file; + unsigned char buffer_header[512]; + uint32_t *fat; + const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header; + time_t file_time=0; + unsigned int fat_entries; + unsigned int uSectorShift; + unsigned int num_FAT_blocks; + title[0]='\0'; + /*@ assert valid_string(&title[0]); */ + if(strstr(file_recovery->filename, ".sdd")!=NULL) + ext=extension_sdd; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; +#ifdef DEBUG_OLE + log_info("file_rename_doc(%s)\n", file_recovery->filename); +#endif + /*reads first sector including OLE header */ + if(my_fseek(file, 0, SEEK_SET) < 0 || + fread(&buffer_header, sizeof(buffer_header), 1, file) != 1) + { + fclose(file); + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer_header, sizeof(buffer_header)); +#endif + uSectorShift=le16(header->uSectorShift); + num_FAT_blocks=le32(header->num_FAT_blocks); + /* Sanity check */ + if( uSectorShift != 9 && uSectorShift != 12) + { + fclose(file); + return ; + } + /*@ assert 9 == uSectorShift || 12 == uSectorShift; */ + if(le16(header->uMiniSectorShift) != 6) + { + fclose(file); + return ; + } + /* Sanity check */ + if(num_FAT_blocks==0 || + le32(header->num_extra_FAT_blocks)>50) + { + fclose(file); + return ; + } + /*@ assert num_FAT_blocks > 0; */ + /*@ assert 0 <= le32(header->num_extra_FAT_blocks) <= 50; */ + if(num_FAT_blocks > 109+le32(header->num_extra_FAT_blocks)*((1<root_start_block), fat_entries); +#endif + for(block=le32(header->root_start_block), i=0; + blockstart_block); + ministream_size=le32(dir_entry->size); + } + /*@ assert valid_string(&title[0]); */ + for(sid=0; + sid<(1<type!=NO_ENTRY) + { + const char SummaryInformation[40]= + { + 0x05, '\0', 'S', '\0', 'u', '\0', 'm', '\0', + 'm', '\0', 'a', '\0', 'r', '\0', 'y', '\0', + 'I', '\0', 'n', '\0', 'f', '\0', 'o', '\0', + 'r', '\0', 'm', '\0', 'a', '\0', 't', '\0', + 'i', '\0', 'o', '\0', 'n', '\0', '\0', '\0' + }; + const unsigned int namsiz=le16(dir_entry->namsiz); +#ifdef DEBUG_OLE + unsigned int j; + for(j=0;j<64 && jname[j]!='\0';j+=2) + { + log_info("%c",dir_entry->name[j]); + } + log_info(" namsiz=%u type %u", namsiz, dir_entry->type); + log_info(" Flags=%s", (dir_entry->bflags==0?"Red":"Black")); + log_info(" sector %u (%u bytes)\n", + (unsigned int)le32(dir_entry->start_block), + (unsigned int)le32(dir_entry->size)); +#endif + { + const char *tmp=entry2ext(dir_entry); + /*@ assert tmp == \null || valid_read_string(tmp); */ + if(tmp!=NULL) + ext=tmp; + /*@ assert ext == \null || valid_read_string(ext); */ + } + /*@ assert valid_string(&title[0]); */ + switch(namsiz) + { + case 4: + if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0) + is_db=1; + else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "2\0\0\0", 4)==0) + is_db=2; + /*@ assert valid_string(&title[0]); */ + break; + case 16: + if(sid==1 && memcmp(dir_entry->name, "d\0o\0c\0.\0d\0e\0t\0\0\0", 16)==0) + ext=extension_psmodel; + /* Windows Sticky Notes */ + else if(sid==1 && memcmp(dir_entry->name, "V\0e\0r\0s\0i\0o\0n\0\0\0", 16)==0) + ext=extension_snt; + else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0\0\0", 16)==0) + is_db=2; + /*@ assert valid_string(&title[0]); */ + break; + case 18: + /* MS Excel + * Note: Microsoft Works Spreadsheet contains the same signature */ + if(ext==NULL && + memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0) + ext=extension_xls; + /*@ assert valid_string(&title[0]); */ + break; + case 36: + /* sda=StarDraw, sdd=StarImpress */ + if(ext!=extension_sdd && + memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0) + ext=extension_sda; + /*@ assert valid_string(&title[0]); */ + break; + case 40: + if(memcmp(dir_entry->name, SummaryInformation, 40)==0) + { + /*@ assert ext == \null || valid_read_string(ext); */ + /*@ assert valid_string(&title[0]); */ + OLE_parse_summary(file, fat, fat_entries, header, + ministream_block, ministream_size, + le32(dir_entry->start_block), le32(dir_entry->size), + &ext, &title[0], &file_time, 0); + /*@ assert valid_string(&title[0]); */ + /*@ assert ext == \null || valid_read_string(ext); */ + } + /*@ assert valid_string(&title[0]); */ + break; + case 42: + /* 256_ */ + if(sid==1 && memcmp(dir_entry->name, "2\0005\0006\000_\000", 8)==0) + ext=extension_db; + break; + default: + /*@ assert valid_string(&title[0]); */ + break; + } + /*@ assert valid_string(&title[0]); */ + if(sid==1 && namsiz >=6 && + memcmp(dir_entry->name, "D\0g\0n", 6)==0) + ext=extension_dgn; +#ifdef DEBUG_OLE + if(ext!=NULL) + log_info("Found %s %u\n", ext, namsiz); +#endif + /*@ assert valid_string(&title[0]); */ + } + /*@ assert valid_string(&title[0]); */ + } + if(ext==NULL && is_db==2) + ext=extension_db; + } + free(dir_entries); + /*@ assert valid_string(&title[0]); */ + } + } + free(fat); + fclose(file); + if(file_time!=0 && file_time!=(time_t)-1) + set_date(file_recovery->filename, file_time, file_time); + if(title[0]!='\0') + { + file_rename(file_recovery, &title, strlen((const char *)title), 0, ext, 1); + } + else + file_rename(file_recovery, NULL, 0, 0, ext, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct OLE_HDR); + @ requires separation: \separated(&file_hint_doc, buffer, file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_doc); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_doc); + @ assigns *file_recovery_new; + @*/ +static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /*@ assert file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename); */ + const struct OLE_HDR *header=(const struct OLE_HDR *)buffer; + /* Check for Little Endian */ + if(le16(header->uByteOrder)!=0xFFFE) + return 0; + if(le16(header->uDllVersion)!=3 && le16(header->uDllVersion)!=4) + return 0; + if(le16(header->reserved)!=0 || le32(header->reserved1)!=0) + return 0; + if(le16(header->uMiniSectorShift)!=6) + return 0; + if(le16(header->uDllVersion)==3 && le16(header->uSectorShift)!=9) + return 0; + /* max and qbb file have uSectorShift=12 */ + if(le16(header->uDllVersion)==4 && le16(header->uSectorShift)!=12) + return 0; + if(le16(header->uDllVersion)==3 && le32(header->csectDir)!=0) + return 0; + /* max file have csectDir=1 + * qbb file have csectDir=4 */ + if(le16(header->uDllVersion)==4 && le32(header->csectDir)==0) + return 0; + /* + num_FAT_blocks=109+num_extra_FAT_blocks*(512-1); + maximum file size is 512+(num_FAT_blocks*128)*512, about 1.6GB + */ + if(le32(header->num_FAT_blocks)==0 || + le32(header->num_extra_FAT_blocks)>50 || + le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<uSectorShift))/4-1)) + return 0; + /*@ assert file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename); */ + /*@ assert le32(header->num_FAT_blocks) <= 109+le32(header->num_extra_FAT_blocks)*((1<uSectorShift))/4-1); */ + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_doc; + file_recovery_new->file_rename=&file_rename_doc; + file_recovery_new->extension=ole_get_file_extension(header, buffer_size); + if(file_recovery_new->extension!=NULL) + { + /*@ assert valid_read_string(file_recovery_new->extension); */ + if(strcmp(file_recovery_new->extension,"sda")==0) + { + if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL) + file_recovery_new->extension=extension_sdd; + } + else if(strcmp(file_recovery_new->extension,"wps")==0) + { + /* Distinguish between MS Works .wps and MS Publisher .pub */ + if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL) + file_recovery_new->extension=extension_pub; + } + /*@ assert valid_read_string(file_recovery_new->extension); */ + return 1; + } + if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL) + { + file_recovery_new->extension=extension_doc; + } + else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL) + { + file_recovery_new->extension=extension_sda; + } + else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL) + { + file_recovery_new->extension=extension_sdc; + } + else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL) + { + file_recovery_new->extension=extension_sdd; + } + else if(td_memmem(buffer,buffer_size,"Worksheet",9)!=NULL || + td_memmem(buffer,buffer_size,"Book",4)!=NULL || + td_memmem(buffer,buffer_size,"Workbook",8)!=NULL || + td_memmem(buffer,buffer_size,"Calc",4)!=NULL) + { + file_recovery_new->extension=extension_xls; + } + else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL) + { + file_recovery_new->extension=extension_ppt; + } + else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL) + { + file_recovery_new->extension=extension_mdb; + } + else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL) + { + file_recovery_new->extension=extension_vsd; + } + else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL) + { + file_recovery_new->extension=extension_sdw; + } + else if(td_memmem(buffer,buffer_size,"CPicPage",8)!=NULL) + { /* Flash Project File */ + file_recovery_new->extension=extension_fla; + } + else if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL) + { /* Publisher */ + file_recovery_new->extension=extension_pub; + } + else if(td_memmem(buffer, buffer_size, "Microsoft Works Database", 24)!=NULL + || td_memmem( buffer, buffer_size, "MSWorksDBDoc", 12)!=NULL) + { /* Microsoft Works .wdb */ + file_recovery_new->extension=extension_wdb; + } + else if(td_memmem(buffer,buffer_size,"MetaStock",9)!=NULL) + { /* MetaStock */ + file_recovery_new->extension=extension_mws; + } + else + file_recovery_new->extension=extension_doc; + /*@ assert valid_read_string(file_recovery_new->extension); */ + return 1; +} + +static void register_header_check_doc(file_stat_t *file_stat) +{ + static const unsigned char doc_header[]= { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1}; + register_header_check(0, doc_header,sizeof(doc_header), &header_check_doc, file_stat); +} +#endif + +#if defined(MAIN_doc) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.doc"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_doc; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_doc(&file_stats); + if(header_check_doc(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.file_check == &file_check_doc; */ + /*@ assert file_recovery_new.file_rename == &file_rename_doc; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert \separated(&file_recovery_new, file_recovery_new.extension); */ +#ifdef __FRAMAC__ + file_recovery_new.file_size = 512*Frama_C_interval(1, 1000); +#endif + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*X TODO assert valid_read_string(file_recovery_new.extension); */ + file_recovery_new.file_stat=&file_stats; + if(file_recovery_new.file_stat!=NULL) + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_doc(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_doc(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_rename_doc(&file_recovery_new); + return 0; +} +#endif diff --git a/subprojects/lib/src/file_doc.h b/subprojects/lib/src/file_doc.h new file mode 100644 index 0000000..a58a910 --- /dev/null +++ b/subprojects/lib/src/file_doc.h @@ -0,0 +1,37 @@ +/* + + File: file_doc.h + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*/ +#ifndef _FILE_DOC_H +#define _FILE_DOC_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_dpx.c b/subprojects/lib/src/file_dpx.c new file mode 100644 index 0000000..b2b51a9 --- /dev/null +++ b/subprojects/lib/src/file_dpx.c @@ -0,0 +1,104 @@ +/* + + File: file_dpx.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dpx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dpx(file_stat_t *file_stat); + +const file_hint_t file_hint_dpx= { + .extension="dpx", + .description="Cineon image file/SMTPE DPX", + .max_filesize=10*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dpx +}; + +/* Header information from http://www.cineon.com/ff_draft.php */ +struct header_dpx +{ + uint32_t magic_num; /* magic number 0x53445058 (SDPX) or 0x58504453 (XPDS) */ + uint32_t offset; /* offset to image data in bytes */ + char vers[8]; /* which header format version is being used (v1.0)*/ + uint32_t file_size; /* file size in bytes */ + uint32_t ditto_key; /* read time short cut - 0 = same, 1 = new */ + uint32_t gen_hdr_size; /* generic header length in bytes */ + uint32_t ind_hdr_size; /* industry header length in bytes */ + uint32_t user_data_size; /* user-defined data length in bytes */ + char file_name[100]; /* image file name */ + char create_time[24]; /* file creation date "yyyy:mm:dd:hh:mm:ss:LTZ" */ + char creator[100]; /* file creator's name */ + char project[200]; /* project name */ + char copyright[200]; /* right to use or copyright info */ + uint32_t key; /* encryption ( FFFFFFFF = unencrypted ) */ + char Reserved[104]; /* reserved field TBD (need to pad) */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct header_dpx); + @ requires separation: \separated(&file_hint_dpx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dpx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char ver10[8]= {'V', '1', '.', '0', 0x00, 0x00, 0x00, 0x00}; + const struct header_dpx *dpx=(const struct header_dpx *)buffer; + const unsigned int file_size=be32(dpx->file_size); + if(memcmp(dpx->vers, ver10, sizeof(ver10))==0) + { + if(file_size < sizeof(struct header_dpx)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dpx.extension; + file_recovery_new->calculated_file_size=file_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->time=get_time_from_YYYY_MM_DD_HH_MM_SS(dpx->create_time); + return 1; + } + return 0; +} + +static void register_header_check_dpx(file_stat_t *file_stat) +{ + register_header_check(0, "SDPX", 4, &header_check_dpx, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, "XPDS", 4, &header_check_dpx, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_drw.c b/subprojects/lib/src/file_drw.c new file mode 100644 index 0000000..5f96a10 --- /dev/null +++ b/subprojects/lib/src/file_drw.c @@ -0,0 +1,86 @@ +/* + + File: file_drw.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_drw) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_drw(file_stat_t *file_stat); + +const file_hint_t file_hint_drw= { + .extension="drw", + .description="Pro/ENGINEER Drawing", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_drw +}; + +/*@ + @ requires file_recovery->file_check == &file_check_drw; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_drw(file_recovery_t *file_recovery) +{ + const unsigned char drw_footer[11]= { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C'}; + file_search_footer(file_recovery, drw_footer, sizeof(drw_footer), 1); +} + +/*@ + @ requires buffer_size >= 18; + @ requires separation: \separated(&file_hint_drw, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_drw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[14]) || !isprint(buffer[15]) || !isprint(buffer[16]) || !isprint(buffer[17])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_drw; + file_recovery_new->extension=file_hint_drw.extension; + return 1; +} + +static void register_header_check_drw(file_stat_t *file_stat) +{ + static const unsigned char drw_header[14]= { + '#', 'U', 'G', 'C', ':', '2', ' ', 'D', + 'R', 'A', 'W', 'I', 'N', 'G'}; + register_header_check(0, drw_header,sizeof(drw_header), &header_check_drw, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_drw2.c b/subprojects/lib/src/file_drw2.c new file mode 100644 index 0000000..31bbc69 --- /dev/null +++ b/subprojects/lib/src/file_drw2.c @@ -0,0 +1,67 @@ +/* + + File: file_drw2.c + + Copyright (C) YEAR Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_drw2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_drw2(file_stat_t *file_stat); + +const file_hint_t file_hint_drw2= { + .extension="drw", + .description="Designer DRW file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_drw2 +}; + +/*@ + @ requires \valid(file_recovery_new); + @ requires separation: \separated(&file_hint_drw2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_drw2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_drw2.extension; + return 1; +} + +static void register_header_check_drw2(file_stat_t *file_stat) +{ + static const unsigned char drw2_header[10]= { + 0x01, 0xff, 0x02, 0x04, 0x03, 0x02, 0x00, 0x02, 0x02, 0x02 + }; + register_header_check(0, drw2_header, sizeof(drw2_header), &header_check_drw2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ds2.c b/subprojects/lib/src/file_ds2.c new file mode 100644 index 0000000..a3820b0 --- /dev/null +++ b/subprojects/lib/src/file_ds2.c @@ -0,0 +1,89 @@ +/* + + File: file_ds2.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ds2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ds2(file_stat_t *file_stat); + +const file_hint_t file_hint_ds2= { + .extension="ds2", + .description="Digital Speech Standard v2", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ds2 +}; + +/* + Digital Speech Standard (.ds2) is a digital speech recording format + that is an evolution from dss standard which was jointly developed + and introduced by Olympus, Grundig and Phillips in 1994. + 0x00 char magic[4]; + 0x26 char create_date[12]; + 0x32 char complete_date[12]; + + Filesize is always a multiple of 512 +*/ + +/*@ + @ requires buffer_size >= 0x32; + @ requires separation: \separated(&file_hint_ds2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ds2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char *date_asc=&buffer[0x26]; + unsigned int i; + /*@ + @ loop assigns i; + @ */ + for(i=0; i<24; i++) + if(!isdigit(date_asc[i])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ds2.extension; + file_recovery_new->min_filesize=0x200; + file_recovery_new->time=get_time_from_YYMMDDHHMMSS(date_asc); + return 1; +} + +static void register_header_check_ds2(file_stat_t *file_stat) +{ + static const unsigned char ds2_header[4]= { 0x03, 'd','s','2'}; + register_header_check(0, ds2_header,sizeof(ds2_header), &header_check_ds2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ds_store.c b/subprojects/lib/src/file_ds_store.c new file mode 100644 index 0000000..017f529 --- /dev/null +++ b/subprojects/lib/src/file_ds_store.c @@ -0,0 +1,82 @@ +/* + + File: file_ds_store.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ds_store) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ds_store(file_stat_t *file_stat); + +const file_hint_t file_hint_ds_store= { + .extension="DS_Store", + .description="Apple Desktop Services Store", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ds_store +}; + +struct ds_store_header +{ + uint32_t magic1; + uint32_t magic; + uint32_t offset; + uint32_t size; + uint32_t offset2; + char unk2[16]; +}; + +/*@ + @ requires buffer_size >= sizeof(struct ds_store_header); + @ requires separation: \separated(&file_hint_ds_store, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ds_store(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ds_store_header *hdr=(const struct ds_store_header *)buffer; + if(hdr->offset!=hdr->offset2) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ds_store.extension; + file_recovery_new->min_filesize=(uint64_t)be32(hdr->offset)+be32(hdr->size); + return 1; +} + +static void register_header_check_ds_store(file_stat_t *file_stat) +{ + static const unsigned char ds_store_header[8]= { + 0x00, 0x00, 0x00, 0x01, 'B' , 'u' , 'd' , '1' + }; + register_header_check(0, ds_store_header, sizeof(ds_store_header), &header_check_ds_store, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dsc.c b/subprojects/lib/src/file_dsc.c new file mode 100644 index 0000000..d2b33ad --- /dev/null +++ b/subprojects/lib/src/file_dsc.c @@ -0,0 +1,66 @@ +/* + + File: file_dsc.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dsc) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dsc(file_stat_t *file_stat); + +const file_hint_t file_hint_dsc= { + .extension="dsc", + .description="Nikon dsc", + .max_filesize=1024*1024, + .recover=0, + .enable_by_default=0, + .register_header_check=®ister_header_check_dsc +}; + +/*@ + @ requires separation: \separated(&file_hint_dsc, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dsc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer_size<1024) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dsc.extension; + file_recovery_new->min_filesize=588+3; + return 1; +} + +static void register_header_check_dsc(file_stat_t *file_stat) +{ + static const unsigned char dsc_header[3]= { 'M','L','T'}; + register_header_check(588, dsc_header,sizeof(dsc_header), &header_check_dsc, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dss.c b/subprojects/lib/src/file_dss.c new file mode 100644 index 0000000..f5c37b3 --- /dev/null +++ b/subprojects/lib/src/file_dss.c @@ -0,0 +1,91 @@ +/* + + File: file_dss.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dss) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dss(file_stat_t *file_stat); + +const file_hint_t file_hint_dss = { + .extension = "dss", + .description = "Digital Speech Standard", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_dss +}; + +/* + Digital Speech Standard (.dss) is a digital speech recording standard + which was jointly developed and introduced by Olympus, Grundig and + Phillips in 1994. + 0x00 char magic[4]; + 0x26 char create_date[12]; + 0x32 char complete_date[12]; + 0x3e char length[6]; + 0x31e char comments[100]; + + Filesize is always a multiple of 512 +*/ + +/*@ + @ requires buffer_size >= 0x26+24; + @ requires separation: \separated(&file_hint_dss, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dss(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char *udate_asc = (const unsigned char *)&buffer[0x26]; + const char *date_asc = (const char *)&buffer[0x26]; + unsigned int i; + /*@ loop assigns i; */ + for(i = 0; i < 24; i++) + if(!isdigit(udate_asc[i])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_dss.extension; + /* File should be big enough to hold the comments */ + file_recovery_new->min_filesize = 1024; + file_recovery_new->time = get_time_from_YYMMDDHHMMSS(date_asc); + return 1; +} + +static void register_header_check_dss(file_stat_t *file_stat) +{ + static const unsigned char dss_header[4] = { 0x02, 'd', 's', 's' }; + register_header_check(0, dss_header, sizeof(dss_header), &header_check_dss, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dst.c b/subprojects/lib/src/file_dst.c new file mode 100644 index 0000000..a9bd14f --- /dev/null +++ b/subprojects/lib/src/file_dst.c @@ -0,0 +1,77 @@ +/* + + File: file_dst.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dst) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dst(file_stat_t *file_stat); + +const file_hint_t file_hint_dst= { + .extension="dst", + .description="Tajima", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dst +}; + +/*@ + @ requires buffer_size >= 512; + @ requires separation: \separated(&file_hint_dst, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dst(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int stitch_count=0; + char buf[8]; + memcpy(&buf, &buffer[23], 7); + buf[7]='\0'; + if(memcmp(buffer, "LA:",3)!=0 || memcmp(&buffer[30], "\rCO:", 4)!=0) + return 0; + if(sscanf(&buf, "%u", &stitch_count) < 0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dst.extension; + /* https://community.kde.org/Projects/Liberty/File_Formats/Tajima_Ternary */ + /* The header is 512 bytes */ + file_recovery_new->calculated_file_size=(uint64_t)512 + (uint64_t)3*stitch_count; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_dst(file_stat_t *file_stat) +{ + register_header_check(0x13, "\rST:", 4, &header_check_dst, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dta.c b/subprojects/lib/src/file_dta.c new file mode 100644 index 0000000..8f1c3e0 --- /dev/null +++ b/subprojects/lib/src/file_dta.c @@ -0,0 +1,78 @@ +/* + + File: file_dta.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dta) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dta(file_stat_t *file_stat); + +const file_hint_t file_hint_dta= { + .extension="dta", + .description="SPSS", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_dta +}; + +/*@ + @ requires separation: \separated(&file_hint_dta, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dta(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* + ds_format 1 byte 0x71 or 0x72 + byteorder 1 byte 0x01 -> HILO, 0x02 -> LOHI + filetype 1 byte 0x01 + unused 1 byte ? + nvar (number of vars) 2 int encoded per byteorder + nobs (number of obs) 4 int encoded per byteorder + data_label 81 char dataset label, \0 terminated + time_stamp 18 char date/time saved, \0 terminated + */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dta.extension; + return 1; +} + +static void register_header_check_dta(file_stat_t *file_stat) +{ + static const unsigned char dta_header_71le[3]= {0x71, 0x02, 0x01}; + static const unsigned char dta_header_72le[3]= {0x72, 0x02, 0x01}; + register_header_check(0, dta_header_71le,sizeof(dta_header_71le), &header_check_dta, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, dta_header_72le,sizeof(dta_header_72le), &header_check_dta, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_dump.c b/subprojects/lib/src/file_dump.c new file mode 100644 index 0000000..3669cef --- /dev/null +++ b/subprojects/lib/src/file_dump.c @@ -0,0 +1,159 @@ +/* + + File: file_dump.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the tedumps of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dump) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#define TS_TAPE 1 /* dump tape header */ + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dump(file_stat_t *file_stat); + +const file_hint_t file_hint_dump= { + .extension="dump", + .description="Dump/Restore archive", + .max_filesize=(((uint64_t)1<<33)-1), + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dump +}; + +/* + * TP_BSIZE is the size of file blocks on the dump tapes. + * Note that TP_BSIZE must be a multiple of DEV_BSIZE. + * + * NTREC is the number of TP_BSIZE blocks that are written + * in each tape record. HIGHDENSITYTREC is the number of + * TP_BSIZE blocks that are written in each tape record on + * 6250 BPI or higher density tapes. + * + * TP_NINDIR is the number of indirect pointers in a TS_INODE + * or TS_ADDR record. Note that it must be a power of two. + */ +#define TP_BSIZE 1024 +#define NTREC 10 +#define HIGHDENSITYTREC 32 +#define TP_NINDIR (TP_BSIZE/2) +#define LBLSIZE 16 +#define NAMELEN 64 + +struct dump_struct +{ + int32_t c_type; /* record type (see below) */ + int32_t c_old_date; /* date of this dump */ + int32_t c_old_ddate; /* date of previous dump */ + int32_t c_volume; /* dump volume number */ + int32_t c_old_tapea; /* logical block of this record */ + uint32_t c_inumber; /* number of inode */ + int32_t c_magic; /* magic number (see above) */ + int32_t c_checksum; /* record checksum */ + /* + * Start old dinode structure, expanded for binary + * compatibility with UFS1. + */ + uint16_t c_mode; /* file mode */ + int16_t c_spare1[3]; /* old nlink, ids */ + uint64_t c_size; /* file byte count */ + int32_t c_old_atime; /* old last access time, seconds */ + int32_t c_atimensec; /* last access time, nanoseconds */ + int32_t c_old_mtime; /* old last modified time, secs */ + int32_t c_mtimensec; /* last modified time, nanosecs */ + int32_t c_spare2[2]; /* old ctime */ + int32_t c_rdev; /* for devices, device number */ + int32_t c_birthtimensec; /* creation time, nanosecs */ + int64_t c_birthtime; /* creation time, seconds */ + int64_t c_atime; /* last access time, seconds */ + int64_t c_mtime; /* last modified time, seconds */ + int32_t c_spare4[7]; /* old block pointers */ + uint32_t c_file_flags; /* status flags (chflags) */ + int32_t c_spare5[2]; /* old blocks, generation number */ + uint32_t c_uid; /* file owner */ + uint32_t c_gid; /* file group */ + int32_t c_spare6[2]; /* previously unused spares */ + /* + * End old dinode structure. + */ + int32_t c_count; /* number of valid c_addr entries */ + char c_addr[TP_NINDIR]; /* 1 => data; 0 => hole in inode */ + char c_label[LBLSIZE]; /* dump label */ + int32_t c_level; /* level of this dump */ + char c_filesys[NAMELEN]; /* name of dumpped file system */ + char c_dev[NAMELEN]; /* name of dumpped device */ + char c_host[NAMELEN]; /* name of dumpped host */ + int32_t c_flags; /* additional information */ + int32_t c_old_firstrec; /* first record on volume */ + int64_t c_date; /* date of this dump */ + int64_t c_ddate; /* date of previous dump */ + int64_t c_tapea; /* logical block of this record */ + int64_t c_firstrec; /* first record on volume */ + int32_t c_spare[24]; /* reserved for future uses */ +}; +/* + * special record types + */ +#define TS_TAPE 1 /* dump tape header */ +#define TS_INODE 2 /* beginning of file record */ +#define TS_ADDR 4 /* continuation of file record */ +#define TS_BITS 3 /* map of inodes on tape */ +#define TS_CLRI 6 /* map of inodes deleted since last dump */ +#define TS_END 5 /* end of volume marker */ + +/*@ + @ requires buffer_size >= sizeof(struct dump_struct); + @ requires separation: \separated(&file_hint_dump, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dump(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct dump_struct *dump=(const struct dump_struct*)buffer; + if(le32(dump->c_type)!=TS_TAPE) + return 0; + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="dmp"; +#else + file_recovery_new->extension=file_hint_dump.extension; +#endif + file_recovery_new->time=le32(dump->c_old_date); + return 1; +} + +static void register_header_check_dump(file_stat_t *file_stat) +{ + static const unsigned char dump_header_le_old_fs[4] = { 0x6b, 0xea, 0x00, 0x00}; + static const unsigned char dump_header_le_new_fs[4] = { 0x6c, 0xea, 0x00, 0x00}; + register_header_check(0x18, dump_header_le_old_fs,sizeof(dump_header_le_old_fs), &header_check_dump, file_stat); +#ifndef __FRAMAC__ + register_header_check(0x18, dump_header_le_new_fs,sizeof(dump_header_le_new_fs), &header_check_dump, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_dv.c b/subprojects/lib/src/file_dv.c new file mode 100644 index 0000000..1a35671 --- /dev/null +++ b/subprojects/lib/src/file_dv.c @@ -0,0 +1,231 @@ +/* + + File: file_dv.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dv(file_stat_t *file_stat); + +const file_hint_t file_hint_dv= { + .extension="dv", + .description="DIF Digital Video", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dv +}; + +/*@ + @ requires file_recovery->data_check==&data_check_NTSC; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_NTSC(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + if(buffer[i]==0x1f && buffer[i+1]==0x07 && buffer[i+2]==0x00 && + buffer[i+5]==0x78 && buffer[i+6]==0x78 && buffer[i+7]==0x78) + file_recovery->calculated_file_size+=120000; + else + return DC_STOP; + } + return DC_CONTINUE; +} + +/*@ + @ requires fr->file_check == &file_check_dv_NTSC; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, Frama_C_entropy_source, fr->file_size; + @*/ +static void file_check_dv_NTSC(file_recovery_t *fr) +{ + char buffer_header[512]; + uint64_t fs=fr->file_size/120000*120000; + if(my_fseek(fr->handle, 0, SEEK_SET) < 0 || + fread(&buffer_header, sizeof(buffer_header), 1, fr->handle) != 1) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer_header, sizeof(buffer_header)); +#endif + if(fs > 0) + fs-=120000; + if(fs > 0) + fs-=120000; + /*@ loop assigns fs, *fr->handle, errno, Frama_C_entropy_source, fr->file_size; */ + while(fs < fr->file_size && + my_fseek(fr->handle, fs, SEEK_SET) >= 0) + { + char buffer[120000]; + unsigned int i; + if(fread(&buffer, sizeof(buffer), 1, fr->handle) != 1) + { + fr->file_size=fs; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + /*@ loop assigns i, fr->file_size; */ + for(i=1; ifile_size=fs; + return; + } + fs+=sizeof(buffer); + } + fr->file_size=fs; +} + +/*@ + @ requires file_recovery->data_check==&data_check_PAL; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_PAL(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + if(buffer[i]==0x1f && buffer[i+1]==0x07 && buffer[i+2]==0x00 && + buffer[i+5]==0x78 && buffer[i+6]==0x78 && buffer[i+7]==0x78) + file_recovery->calculated_file_size+=144000; + else + return DC_STOP; + } + return DC_CONTINUE; +} + +/*@ + @ requires fr->file_check == &file_check_dv_PAL; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, Frama_C_entropy_source, fr->file_size; + @*/ +static void file_check_dv_PAL(file_recovery_t *fr) +{ + char buffer_header[512]; + uint64_t fs=fr->file_size/144000*144000; + if(my_fseek(fr->handle, 0, SEEK_SET) < 0 || + fread(&buffer_header, sizeof(buffer_header), 1, fr->handle) != 1) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer_header, sizeof(buffer_header)); +#endif + if(fs > 0) + fs-=144000; + if(fs > 0) + fs-=144000; + /*@ loop assigns fs, *fr->handle, errno, Frama_C_entropy_source, fr->file_size; */ + while(fs < fr->file_size && + my_fseek(fr->handle, fs, SEEK_SET) >= 0) + { + unsigned int i; + char buffer[144000]; + if(fread(&buffer, sizeof(buffer), 1, fr->handle) != 1) + { + fr->file_size=fs; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + /*@ loop assigns i, fr->file_size; */ + for(i=1; ifile_size=fs; + return; + } + fs+=sizeof(buffer); + } + fr->file_size=fs; +} + + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_dv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_dv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]!=0x1f || buffer[1]!=0x07 || buffer[2]!=0x00 || buffer[5]!=0x78 || buffer[6]!=0x78 || buffer[7]!=0x78) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_dv) + { + /*@ assert \valid_function(file_recovery->file_check); */ + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dv.extension; + if((buffer[3]&0x80)==0) + file_recovery_new->file_check=&file_check_dv_NTSC; + else + file_recovery_new->file_check=&file_check_dv_PAL; + if(file_recovery_new->blocksize < 8) + return 1; + // Each frame contains exactly 120000 bytes in NTSC, 144000 in PAL. + if((buffer[3]&0x80)==0) + file_recovery_new->data_check=&data_check_NTSC; + else + file_recovery_new->data_check=&data_check_PAL; + return 1; +} + +static void register_header_check_dv(file_stat_t *file_stat) +{ + static const unsigned char dv_header[3]= {0x1f, 0x07, 0x00}; + register_header_check(0, dv_header,sizeof(dv_header), &header_check_dv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dvi.c b/subprojects/lib/src/file_dvi.c new file mode 100644 index 0000000..0747ebf --- /dev/null +++ b/subprojects/lib/src/file_dvi.c @@ -0,0 +1,77 @@ +/* + + File: file_dvi.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dvi) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dvi(file_stat_t *file_stat); + +const file_hint_t file_hint_dvi= { + .extension="dvi", + .description="TeX DVI", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dvi +}; + +/*@ + @ requires buffer_size >= 0x15; + @ requires separation: \separated(&file_hint_dvi, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dvi(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dvi.extension; + file_recovery_new->min_filesize=0x15+buffer[0x14]; + return 1; +} + +static void register_header_check_dvi(file_stat_t *file_stat) +{ + static const unsigned char dvi_header[12]= { + 0xf7, // pre + 0x02, // version 2 + // There are exactly 7227 TeX points in 254 centimeters, + // and TeX82 works with scaled points where there are 2^16 sp in a point, + // so TeX82 sets the following values + 0x01, 0x83, 0x92, 0xc0, // num=0x018392c0=25400000 + 0x1c, 0x3b, 0x00, 0x00, // den=0x1c3b0000=7227*2^16=473628672 + // mag + // comment size + // comment + }; + register_header_check(0, dvi_header, sizeof(dvi_header), &header_check_dvi, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dvr.c b/subprojects/lib/src/file_dvr.c new file mode 100644 index 0000000..0708396 --- /dev/null +++ b/subprojects/lib/src/file_dvr.c @@ -0,0 +1,72 @@ +/* + + File: file_dvr.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dvr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dvr(file_stat_t *file_stat); + +const file_hint_t file_hint_dvr= { + .extension="dvr", + .description="RT60", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dvr +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_dvr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dvr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[8], "XVID", 4)!=0) + return 0; + if(file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_dvr) + { + /* header_ignored(file_recovery_new); is useless as there is no file check */ + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dvr.extension; + file_recovery_new->min_filesize=0x10; + return 1; +} + +static void register_header_check_dvr(file_stat_t *file_stat) +{ + register_header_check(0, "RT60", 4, &header_check_dvr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_dwg.c b/subprojects/lib/src/file_dwg.c new file mode 100644 index 0000000..7db4234 --- /dev/null +++ b/subprojects/lib/src/file_dwg.c @@ -0,0 +1,82 @@ +/* + + File: file_dwg.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dwg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dwg(file_stat_t *file_stat); + +const file_hint_t file_hint_dwg= { + .extension="dwg", + .description="AutoCAD", + .max_filesize=20*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dwg +}; + +/*@ + @ requires separation: \separated(&file_hint_dwg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dwg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dwg.extension; + return 1; +} + +static void register_header_check_dwg(file_stat_t *file_stat) +{ + static const unsigned char dwg_header_12[11]= {'A', 'C', '1', '0', '1', '2', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_13[11]= {'A', 'C', '1', '0', '1', '3', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_14[11]= {'A', 'C', '1', '0', '1', '4', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_15[11]= {'A', 'C', '1', '0', '1', '5', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_18[11]= {'A', 'C', '1', '0', '1', '8', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_21[11]= {'A', 'C', '1', '0', '2', '1', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_23[11]= {'A', 'C', '1', '0', '2', '3', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_24[11]= {'A', 'C', '1', '0', '2', '4', 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char dwg_header_27[11]= {'A', 'C', '1', '0', '2', '7', 0x00, 0x00, 0x00, 0x00, 0x00}; + register_header_check(0, dwg_header_12,sizeof(dwg_header_12), &header_check_dwg, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, dwg_header_13,sizeof(dwg_header_13), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_14,sizeof(dwg_header_14), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_15,sizeof(dwg_header_15), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_18,sizeof(dwg_header_18), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_21,sizeof(dwg_header_21), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_23,sizeof(dwg_header_23), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_24,sizeof(dwg_header_24), &header_check_dwg, file_stat); + register_header_check(0, dwg_header_27,sizeof(dwg_header_27), &header_check_dwg, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_dxf.c b/subprojects/lib/src/file_dxf.c new file mode 100644 index 0000000..06afd87 --- /dev/null +++ b/subprojects/lib/src/file_dxf.c @@ -0,0 +1,121 @@ +/* + + File: file_dxf.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dxf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_dxf(file_stat_t *file_stat); + +const file_hint_t file_hint_dxf= { + .extension="dxf", + .description="Drawing Interchange File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_dxf +}; + +/*@ + @ requires buffer_size >= 6; + @ requires file_recovery->data_check==&data_check_dxf; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_dxf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + unsigned int i; + /*@ + @ loop assigns i, file_recovery->calculated_file_size; + @*/ + for(i=(buffer_size/2)-3;i+4calculated_file_size=file_recovery->file_size+i+4-(buffer_size/2); + return DC_STOP; + } + } + file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2); + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_check == &file_check_dxf; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, Frama_C_entropy_source, file_recovery->file_size; + @*/ +static void file_check_dxf(file_recovery_t *file_recovery) +{ + const unsigned char dxf_footer[4]= {'\n', 'E', 'O', 'F'}; + file_search_footer(file_recovery, dxf_footer, sizeof(dxf_footer), 0); + file_allow_nl(file_recovery, NL_BARENL|NL_CRLF); +} + +/*@ + @ requires separation: \separated(&file_hint_dxf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dxf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_dxf.extension; + file_recovery_new->file_check=&file_check_dxf; + if(file_recovery_new->blocksize >= 3) + { + file_recovery_new->data_check=&data_check_dxf; + } + return 1; +} + +static void register_header_check_dxf(file_stat_t *file_stat) +{ + static const unsigned char header_dxflib[10]= {'9', '9', '9', '\n', + 'd', 'x', 'f', 'l', 'i', 'b'}; + static const unsigned char header_dxflib_dos[11]= {'9', '9', '9', '\r', '\n', + 'd', 'x', 'f', 'l', 'i', 'b'}; + static const unsigned char header_dxf[11]= {' ', ' ', '0', '\n', + 'S', 'E', 'C', 'T', 'I', 'O', 'N'}; + static const unsigned char header_dxf_dos[12]= {' ', ' ', '0', '\r', '\n', + 'S', 'E', 'C', 'T', 'I', 'O', 'N'}; + + register_header_check(0, header_dxf, sizeof(header_dxf), &header_check_dxf, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, header_dxf_dos, sizeof(header_dxf_dos), &header_check_dxf, file_stat); + register_header_check(0, header_dxflib, sizeof(header_dxflib), &header_check_dxf, file_stat); + register_header_check(0, header_dxflib_dos, sizeof(header_dxflib_dos), &header_check_dxf, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_e01.c b/subprojects/lib/src/file_e01.c new file mode 100644 index 0000000..4fdb024 --- /dev/null +++ b/subprojects/lib/src/file_e01.c @@ -0,0 +1,142 @@ +/* + + File: file_e01.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_e01) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_e01(file_stat_t *file_stat); + +static char ext[10]; + +const file_hint_t file_hint_e01= { + .extension="e01", + .description="Encase", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_e01 +}; + +struct ewf_file_header +{ + /* The EWF file signature (magic header) + * consists of 8 bytes containing + * EVF 0x09 0x0d 0x0a 0xff 0x00 + */ + uint8_t signature[ 8 ]; + /* The fields start + * consists of 1 byte (8 bit) containing + * 0x01 + */ + uint8_t fields_start; + /* The fields segment number + * consists of 2 bytes (16 bits) containing + */ + uint16_t fields_segment; + /* The fields end + * consists of 2 bytes (16 bits) containing + * 0x00 0x00 + */ + uint16_t fields_end; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_e01; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_e01(file_recovery_t *file_recovery) +{ + const uint64_t tmp=file_recovery->file_size; + const unsigned char sig_done[16]={ + 'd', 'o', 'n', 'e', 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig_next[16]={ + 'n', 'e', 'x', 't', 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + file_search_footer(file_recovery, sig_next, sizeof(sig_next), 60); + if(file_recovery->file_size!=0) + return ; + file_recovery->file_size=tmp; + file_search_footer(file_recovery, sig_done, sizeof(sig_done), 60); +} + +/*@ + @ requires buffer_size >= sizeof(struct ewf_file_header); + @ requires separation: \separated(&file_hint_e01, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new, *(ext + (0 .. sizeof(ext)-1)); + @*/ +static int header_check_e01(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ewf_file_header *ewf=(const struct ewf_file_header *)buffer; + uint16_t fields_segment=le16(ewf->fields_segment); + reset_file_recovery(file_recovery_new); + if(fields_segment > ('Z'-'E') * 100 + 99) + { + ext[0]='E'; + ext[1]='0'; + ext[2]='1'; + ext[3]='_'; + ext[4]='0'+(fields_segment/10000)%10; + ext[5]='0'+(fields_segment/1000)%10; + ext[6]='0'+(fields_segment/100)%10; + ext[7]='0'+(fields_segment/10)%10; + ext[8]='0'+fields_segment%10; + ext[9]='\0'; + } + else + { + ext[0]='E'+fields_segment/100; + ext[1]='0'+(fields_segment/10)%10; + ext[2]='0'+(fields_segment%10); + ext[3]='\0'; + } + file_recovery_new->extension=(const char*)&ext; + file_recovery_new->file_check=&file_check_e01; + return 1; +} + +static void register_header_check_e01(file_stat_t *file_stat) +{ + static const unsigned char e01_header[9]= { + 'E' , 'V' , 'F' , 0x09, 0x0d, 0x0a, 0xff, 0x00, + 0x01 + }; + register_header_check(0, e01_header, sizeof(e01_header), &header_check_e01, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ecryptfs.c b/subprojects/lib/src/file_ecryptfs.c new file mode 100644 index 0000000..d82f0ae --- /dev/null +++ b/subprojects/lib/src/file_ecryptfs.c @@ -0,0 +1,105 @@ +/* + + File: file_ecryptfs.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ecryptfs) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ecryptfs(file_stat_t *file_stat); + +const file_hint_t file_hint_ecryptfs= { + .extension="eCryptfs", + .description="Encrypted file by eCryptfs", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ecryptfs +}; + +static const unsigned char ecryptfs_header[2]= {0, 0}; + +struct ecrypfs_header { + uint64_t unencrypted_file_size; + uint32_t marker1; + uint32_t marker2; + unsigned char version; + unsigned char reserved1; + unsigned char reserved2; + uint32_t flags; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_ecryptfs; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +static void file_check_ecryptfs(file_recovery_t *file_recovery) +{ + if(file_recovery->file_size < file_recovery->calculated_file_size) + file_recovery->file_size=0; + else if(file_recovery->file_size > file_recovery->calculated_file_size+1024*1024) + file_recovery->file_size=file_recovery->calculated_file_size+1024*1024; +} + +/*@ + @ requires buffer_size >= sizeof(struct ecrypfs_header); + @ requires separation: \separated(&file_hint_ecryptfs, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ecryptfs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ecrypfs_header *e=(const struct ecrypfs_header *)buffer; + const uint64_t unencrypted_file_size=be64(e->unencrypted_file_size); + if((be32(e->marker1) ^ be32(e->marker2)) != 0x3c81b7f5) + return 0; + if(unencrypted_file_size < sizeof(struct ecrypfs_header)) + return 0; + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="ecr"; +#else + file_recovery_new->extension=file_hint_ecryptfs.extension; +#endif + file_recovery_new->min_filesize=unencrypted_file_size; + file_recovery_new->calculated_file_size=unencrypted_file_size; + file_recovery_new->data_check=NULL; + file_recovery_new->file_check=&file_check_ecryptfs; + return 1; +} + +static void register_header_check_ecryptfs(file_stat_t *file_stat) +{ + register_header_check(0, ecryptfs_header, sizeof(ecryptfs_header), &header_check_ecryptfs, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_edb.c b/subprojects/lib/src/file_edb.c new file mode 100644 index 0000000..e80a207 --- /dev/null +++ b/subprojects/lib/src/file_edb.c @@ -0,0 +1,75 @@ +/* + + File: file_edb.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_edb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_edb(file_stat_t *file_stat); + +const file_hint_t file_hint_edb= { + .extension="edb", + .description="Exchange Database", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_edb +}; + +/*@ + @ requires separation: \separated(&file_hint_edb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_edb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* A backup of the header is stored in the second block */ + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_edb && + file_recovery->file_size==4096) + { + /* header_ignored(file_recovery_new); is useless as there is no file check */ + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_edb.extension; + return 1; +} + +static void register_header_check_edb(file_stat_t *file_stat) +{ + static const unsigned char edb_magic[8]= { + 0xef, 0xcd, 0xab, 0x89, 0x20, 0x06, 0x00, 0x00 + }; + register_header_check(4, edb_magic, sizeof(edb_magic), &header_check_edb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_elf.c b/subprojects/lib/src/file_elf.c new file mode 100644 index 0000000..472e281 --- /dev/null +++ b/subprojects/lib/src/file_elf.c @@ -0,0 +1,229 @@ +/* + + File: file_elf.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_elf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_elf(file_stat_t *file_stat); + +const file_hint_t file_hint_elf= { + .extension="elf", + .description="Executable and Linking Format", + .max_filesize=10*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_elf +}; + +#define EI_NIDENT 16 +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type of symbol indices. */ +typedef uint32_t Elf32_Symndx; +typedef uint64_t Elf64_Symndx; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shtrndx; +} Elf32_Ehdr; + +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shtrndx; +} Elf64_Ehdr; + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +/*@ + @ requires buffer_size >= sizeof(Elf32_Ehdr); + @ requires separation: \separated(&file_hint_elf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_elf32_lsb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const Elf32_Ehdr *hdr=(const Elf32_Ehdr *)buffer; + if(le32(hdr->e_version) != 1) + return 0; + /* http://en.wikipedia.org/wiki/Executable_and_Linkable_Format */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_elf.extension; + { + const uint32_t tmp=le32(hdr->e_shoff); + file_recovery_new->min_filesize=le32(hdr->e_phoff); + if(file_recovery_new->min_filesize < tmp) + file_recovery_new->min_filesize=tmp; + } + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(Elf32_Ehdr); + @ requires separation: \separated(&file_hint_elf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_elf32_msb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const Elf32_Ehdr *hdr=(const Elf32_Ehdr *)buffer; + if(be32(hdr->e_version) != 1) + return 0; + /* http://en.wikipedia.org/wiki/Executable_and_Linkable_Format */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_elf.extension; + { + const uint32_t tmp=be32(hdr->e_shoff); + file_recovery_new->min_filesize=be32(hdr->e_phoff); + if(file_recovery_new->min_filesize < tmp) + file_recovery_new->min_filesize=tmp; + } + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(Elf64_Ehdr); + @ requires separation: \separated(&file_hint_elf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_elf64_lsb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const Elf64_Ehdr *hdr=(const Elf64_Ehdr *)buffer; + if(le32(hdr->e_version) != 1) + return 0; + /* http://en.wikipedia.org/wiki/Executable_and_Linkable_Format */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_elf.extension; + { + const uint64_t tmp=le64(hdr->e_shoff); + file_recovery_new->min_filesize=le64(hdr->e_phoff); + if(file_recovery_new->min_filesize < tmp) + file_recovery_new->min_filesize=tmp; + } + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(Elf64_Ehdr); + @ requires separation: \separated(&file_hint_elf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_elf64_msb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const Elf64_Ehdr *hdr=(const Elf64_Ehdr *)buffer; + if(be32(hdr->e_version) != 1) + return 0; + /* http://en.wikipedia.org/wiki/Executable_and_Linkable_Format */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_elf.extension; + { + const uint64_t tmp=be64(hdr->e_shoff); + file_recovery_new->min_filesize=be64(hdr->e_phoff); + if(file_recovery_new->min_filesize < tmp) + file_recovery_new->min_filesize=tmp; + } + return 1; +} + +static void register_header_check_elf(file_stat_t *file_stat) +{ + static const unsigned char elf_header32_lsb[6] = { 0x7f, 'E','L','F',0x01, ELFDATA2LSB}; + static const unsigned char elf_header32_msb[6] = { 0x7f, 'E','L','F',0x01, ELFDATA2MSB}; + static const unsigned char elf_header64_lsb[6] = { 0x7f, 'E','L','F',0x02, ELFDATA2LSB}; + static const unsigned char elf_header64_msb[6] = { 0x7f, 'E','L','F',0x02, ELFDATA2MSB}; + register_header_check(0, elf_header32_lsb, sizeof(elf_header32_lsb), &header_check_elf32_lsb, file_stat); + register_header_check(0, elf_header32_msb, sizeof(elf_header32_msb), &header_check_elf32_msb, file_stat); + register_header_check(0, elf_header64_lsb, sizeof(elf_header64_lsb), &header_check_elf64_lsb, file_stat); + register_header_check(0, elf_header64_msb, sizeof(elf_header64_msb), &header_check_elf64_msb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_emf.c b/subprojects/lib/src/file_emf.c new file mode 100644 index 0000000..8b6dcf7 --- /dev/null +++ b/subprojects/lib/src/file_emf.c @@ -0,0 +1,498 @@ +/* + + File: file_emf.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_emf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" +#include "common.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_emf(file_stat_t *file_stat); + +const file_hint_t file_hint_emf= { + .extension="emf", + .description="Windows Enhanced MetaFile", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_emf +}; + +typedef struct { + uint32_t iType; + uint32_t nSize; +} U_EMR; + +typedef struct { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} U_RECTL; + +typedef struct { + int32_t cx; + int32_t cy; +} U_SIZEL; + +struct EMF_HDR +{ + U_EMR emr; + U_RECTL rclBounds; + U_RECTL rclFrame; + uint32_t dSignature; + uint32_t nVersion; + uint32_t nBytes; + uint32_t nRecords; + uint16_t nHandles; + uint16_t sReserved; + uint32_t nDescription; + uint32_t offDescription; + uint32_t nPalEntries; + U_SIZEL szlDevice; + U_SIZEL szlMillimeters; +} __attribute__ ((gcc_struct, __packed__)); + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 +#define EMR_DRAWESCAPE 105 +#define EMR_EXTESCAPE 106 +#define EMR_STARTDOC 107 +#define EMR_SMALLTEXTOUT 108 +#define EMR_FORCEUFIMAPPING 109 +#define EMR_NAMEDESCAPE 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_SETLAYOUT 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_RESERVED_117 117 +#define EMR_GRADIENTFILL 118 +#define EMR_SETLINKEDUFI 119 +#define EMR_SETTEXTJUSTIFICATION 120 +#define EMR_COLORMATCHTOTARGETW 121 +#define EMR_CREATECOLORSPACEW 122 + +/*@ + @ requires file_recovery->data_check==&data_check_emf; + @ requires buffer_size >= 2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_emf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8 ; */ + const U_EMR *hdr=(const U_EMR *)&buffer[i]; + const unsigned int itype=le32(hdr->iType); + const unsigned int atom_size=le32(hdr->nSize); +#ifdef DEBUG_EMF + log_trace("0x%llx ", (long long unsigned)file_recovery->calculated_file_size); + switch(itype) + { + case EMR_HEADER: log_trace("EMR_HEADER"); break; + case EMR_POLYBEZIER: log_trace("EMR_POLYBEZIER"); break; + case EMR_POLYGON: log_trace("EMR_POLYGON"); break; + case EMR_POLYLINE: log_trace("EMR_POLYLINE"); break; + case EMR_POLYBEZIERTO: log_trace("EMR_POLYBEZIERTO"); break; + case EMR_POLYLINETO: log_trace("EMR_POLYLINETO"); break; + case EMR_POLYPOLYLINE: log_trace("EMR_POLYPOLYLINE"); break; + case EMR_POLYPOLYGON: log_trace("EMR_POLYPOLYGON"); break; + case EMR_SETWINDOWEXTEX: log_trace("EMR_SETWINDOWEXTEX"); break; + case EMR_SETWINDOWORGEX: log_trace("EMR_SETWINDOWORGEX"); break; + case EMR_SETVIEWPORTEXTEX: log_trace("EMR_SETVIEWPORTEXTEX"); break; + case EMR_SETVIEWPORTORGEX: log_trace("EMR_SETVIEWPORTORGEX"); break; + case EMR_SETBRUSHORGEX: log_trace("EMR_SETBRUSHORGEX"); break; + case EMR_EOF: log_trace("EMR_EOF"); break; + case EMR_SETPIXELV: log_trace("EMR_SETPIXELV"); break; + case EMR_SETMAPPERFLAGS: log_trace("EMR_SETMAPPERFLAGS"); break; + case EMR_SETMAPMODE: log_trace("EMR_SETMAPMODE"); break; + case EMR_SETBKMODE: log_trace("EMR_SETBKMODE"); break; + case EMR_SETPOLYFILLMODE: log_trace("EMR_SETPOLYFILLMODE"); break; + case EMR_SETROP2: log_trace("EMR_SETROP2"); break; + case EMR_SETSTRETCHBLTMODE: log_trace("EMR_SETSTRETCHBLTMODE"); break; + case EMR_SETTEXTALIGN: log_trace("EMR_SETTEXTALIGN"); break; + case EMR_SETCOLORADJUSTMENT: log_trace("EMR_SETCOLORADJUSTMENT"); break; + case EMR_SETTEXTCOLOR: log_trace("EMR_SETTEXTCOLOR"); break; + case EMR_SETBKCOLOR: log_trace("EMR_SETBKCOLOR"); break; + case EMR_OFFSETCLIPRGN: log_trace("EMR_OFFSETCLIPRGN"); break; + case EMR_MOVETOEX: log_trace("EMR_MOVETOEX"); break; + case EMR_SETMETARGN: log_trace("EMR_SETMETARGN"); break; + case EMR_EXCLUDECLIPRECT: log_trace("EMR_EXCLUDECLIPRECT"); break; + case EMR_INTERSECTCLIPRECT: log_trace("EMR_INTERSECTCLIPRECT"); break; + case EMR_SCALEVIEWPORTEXTEX: log_trace("EMR_SCALEVIEWPORTEXTEX"); break; + case EMR_SCALEWINDOWEXTEX: log_trace("EMR_SCALEWINDOWEXTEX"); break; + case EMR_SAVEDC: log_trace("EMR_SAVEDC"); break; + case EMR_RESTOREDC: log_trace("EMR_RESTOREDC"); break; + case EMR_SETWORLDTRANSFORM: log_trace("EMR_SETWORLDTRANSFORM"); break; + case EMR_MODIFYWORLDTRANSFORM: log_trace("EMR_MODIFYWORLDTRANSFORM"); break; + case EMR_SELECTOBJECT: log_trace("EMR_SELECTOBJECT"); break; + case EMR_CREATEPEN: log_trace("EMR_CREATEPEN"); break; + case EMR_CREATEBRUSHINDIRECT: log_trace("EMR_CREATEBRUSHINDIRECT"); break; + case EMR_DELETEOBJECT: log_trace("EMR_DELETEOBJECT"); break; + case EMR_ANGLEARC: log_trace("EMR_ANGLEARC"); break; + case EMR_ELLIPSE: log_trace("EMR_ELLIPSE"); break; + case EMR_RECTANGLE: log_trace("EMR_RECTANGLE"); break; + case EMR_ROUNDRECT: log_trace("EMR_ROUNDRECT"); break; + case EMR_ARC: log_trace("EMR_ARC"); break; + case EMR_CHORD: log_trace("EMR_CHORD"); break; + case EMR_PIE: log_trace("EMR_PIE"); break; + case EMR_SELECTPALETTE: log_trace("EMR_SELECTPALETTE"); break; + case EMR_CREATEPALETTE: log_trace("EMR_CREATEPALETTE"); break; + case EMR_SETPALETTEENTRIES: log_trace("EMR_SETPALETTEENTRIES"); break; + case EMR_RESIZEPALETTE: log_trace("EMR_RESIZEPALETTE"); break; + case EMR_REALIZEPALETTE: log_trace("EMR_REALIZEPALETTE"); break; + case EMR_EXTFLOODFILL: log_trace("EMR_EXTFLOODFILL"); break; + case EMR_LINETO: log_trace("EMR_LINETO"); break; + case EMR_ARCTO: log_trace("EMR_ARCTO"); break; + case EMR_POLYDRAW: log_trace("EMR_POLYDRAW"); break; + case EMR_SETARCDIRECTION: log_trace("EMR_SETARCDIRECTION"); break; + case EMR_SETMITERLIMIT: log_trace("EMR_SETMITERLIMIT"); break; + case EMR_BEGINPATH: log_trace("EMR_BEGINPATH"); break; + case EMR_ENDPATH: log_trace("EMR_ENDPATH"); break; + case EMR_CLOSEFIGURE: log_trace("EMR_CLOSEFIGURE"); break; + case EMR_FILLPATH: log_trace("EMR_FILLPATH"); break; + case EMR_STROKEANDFILLPATH: log_trace("EMR_STROKEANDFILLPATH"); break; + case EMR_STROKEPATH: log_trace("EMR_STROKEPATH"); break; + case EMR_FLATTENPATH: log_trace("EMR_FLATTENPATH"); break; + case EMR_WIDENPATH: log_trace("EMR_WIDENPATH"); break; + case EMR_SELECTCLIPPATH: log_trace("EMR_SELECTCLIPPATH"); break; + case EMR_ABORTPATH: log_trace("EMR_ABORTPATH"); break; + case EMR_GDICOMMENT: log_trace("EMR_GDICOMMENT"); break; + case EMR_FILLRGN: log_trace("EMR_FILLRGN"); break; + case EMR_FRAMERGN: log_trace("EMR_FRAMERGN"); break; + case EMR_INVERTRGN: log_trace("EMR_INVERTRGN"); break; + case EMR_PAINTRGN: log_trace("EMR_PAINTRGN"); break; + case EMR_EXTSELECTCLIPRGN: log_trace("EMR_EXTSELECTCLIPRGN"); break; + case EMR_BITBLT: log_trace("EMR_BITBLT"); break; + case EMR_STRETCHBLT: log_trace("EMR_STRETCHBLT"); break; + case EMR_MASKBLT: log_trace("EMR_MASKBLT"); break; + case EMR_PLGBLT: log_trace("EMR_PLGBLT"); break; + case EMR_SETDIBITSTODEVICE: log_trace("EMR_SETDIBITSTODEVICE"); break; + case EMR_STRETCHDIBITS: log_trace("EMR_STRETCHDIBITS"); break; + case EMR_EXTCREATEFONTINDIRECTW: log_trace("EMR_EXTCREATEFONTINDIRECTW"); break; + case EMR_EXTTEXTOUTA: log_trace("EMR_EXTTEXTOUTA"); break; + case EMR_EXTTEXTOUTW: log_trace("EMR_EXTTEXTOUTW"); break; + case EMR_POLYBEZIER16: log_trace("EMR_POLYBEZIER16"); break; + case EMR_POLYGON16: log_trace("EMR_POLYGON16"); break; + case EMR_POLYLINE16: log_trace("EMR_POLYLINE16"); break; + case EMR_POLYBEZIERTO16: log_trace("EMR_POLYBEZIERTO16"); break; + case EMR_POLYLINETO16: log_trace("EMR_POLYLINETO16"); break; + case EMR_POLYPOLYLINE16: log_trace("EMR_POLYPOLYLINE16"); break; + case EMR_POLYPOLYGON16: log_trace("EMR_POLYPOLYGON16"); break; + case EMR_POLYDRAW16: log_trace("EMR_POLYDRAW16"); break; + case EMR_CREATEMONOBRUSH: log_trace("EMR_CREATEMONOBRUSH"); break; + case EMR_CREATEDIBPATTERNBRUSHPT: log_trace("EMR_CREATEDIBPATTERNBRUSHPT"); break; + case EMR_EXTCREATEPEN: log_trace("EMR_EXTCREATEPEN"); break; + case EMR_POLYTEXTOUTA: log_trace("EMR_POLYTEXTOUTA"); break; + case EMR_POLYTEXTOUTW: log_trace("EMR_POLYTEXTOUTW"); break; + case EMR_SETICMMODE: log_trace("EMR_SETICMMODE"); break; + case EMR_CREATECOLORSPACE: log_trace("EMR_CREATECOLORSPACE"); break; + case EMR_SETCOLORSPACE: log_trace("EMR_SETCOLORSPACE"); break; + case EMR_DELETECOLORSPACE: log_trace("EMR_DELETECOLORSPACE"); break; + case EMR_GLSRECORD: log_trace("EMR_GLSRECORD"); break; + case EMR_GLSBOUNDEDRECORD: log_trace("EMR_GLSBOUNDEDRECORD"); break; + case EMR_PIXELFORMAT: log_trace("EMR_PIXELFORMAT"); break; + case EMR_DRAWESCAPE : log_trace("EMR_DRAWESCAPE "); break; + case EMR_EXTESCAPE: log_trace("EMR_EXTESCAPE"); break; + case EMR_STARTDOC: log_trace("EMR_STARTDOC"); break; + case EMR_SMALLTEXTOUT: log_trace("EMR_SMALLTEXTOUT"); break; + case EMR_FORCEUFIMAPPING: log_trace("EMR_FORCEUFIMAPPING"); break; + case EMR_NAMEDESCAPE: log_trace("EMR_NAMEDESCAPE"); break; + case EMR_COLORCORRECTPALETTE: log_trace("EMR_COLORCORRECTPALETTE"); break; + case EMR_SETICMPROFILEA: log_trace("EMR_SETICMPROFILEA"); break; + case EMR_SETICMPROFILEW: log_trace("EMR_SETICMPROFILEW"); break; + case EMR_ALPHABLEND: log_trace("EMR_ALPHABLEND"); break; + case EMR_SETLAYOUT: log_trace("EMR_SETLAYOUT"); break; + case EMR_TRANSPARENTBLT: log_trace("EMR_TRANSPARENTBLT"); break; + case EMR_RESERVED_117: log_trace("EMR_RESERVED_117"); break; + case EMR_GRADIENTFILL: log_trace("EMR_GRADIENTFILL"); break; + case EMR_SETLINKEDUFI: log_trace("EMR_SETLINKEDUFI"); break; + case EMR_SETTEXTJUSTIFICATION: log_trace("EMR_SETTEXTJUSTIFICATION"); break; + case EMR_COLORMATCHTOTARGETW: log_trace("EMR_COLORMATCHTOTARGETW"); break; + case EMR_CREATECOLORSPACEW: log_trace("EMR_CREATECOLORSPACEW"); break; + } + log_trace(" (%08x) \t%08x\n", itype, atom_size); +#endif + if(atom_size<8 || atom_size%4!=0 || atom_size>1024*1024) + return DC_ERROR; + /*@ assert 8 <= atom_size <= 1024*1024; */ + file_recovery->calculated_file_size+=(uint64_t)atom_size; + if(itype==EMR_EOF) + return DC_STOP; + /*@ assert file_recovery->calculated_file_size < file_recovery->file_size + buffer_size/2 - 8 + 1024*1024; */ + } + return DC_CONTINUE; +} + +/*@ + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_emf.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 0x34); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_emf); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null); + @ assigns *file_recovery_new; + @*/ +static int header_check_emf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char emf_header[4]= { 0x01, 0x00, 0x00, 0x00}; + const struct EMF_HDR *hdr=(const struct EMF_HDR *)buffer; + const unsigned int atom_size=le32(hdr->emr.nSize); + if(buffer_size < sizeof(struct EMF_HDR)) + return 0; + if(memcmp(buffer,emf_header,sizeof(emf_header))==0 && + le32(hdr->nBytes) >= 88 && + le16(hdr->sReserved)==0 && + atom_size>=0x34 && atom_size%4==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_emf.extension; + if(file_recovery_new->blocksize >= 8) + { + file_recovery_new->data_check=&data_check_emf; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=atom_size; + } + return 1; + } + return 0; +} + +static void register_header_check_emf(file_stat_t *file_stat) +{ + static const unsigned char emf_sign[4]= { ' ','E', 'M','F'}; + register_header_check(0x28, emf_sign,sizeof(emf_sign), &header_check_emf, file_stat); +} +#endif + +#if defined(MAIN_emf) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.emf"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_emf; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_emf(&file_stats); + if(header_check_emf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.calculated_file_size > 0; */ + /*@ assert file_recovery_new.data_check == &data_check_emf; */ + /*@ assert file_recovery_new.file_check == &file_check_size; */ + /*@ assert file_recovery_new.file_rename == \null; */ + /*@ assert file_recovery_new.extension == file_hint_emf.extension; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert \separated(&file_recovery_new, file_recovery_new.extension); */ + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*X TODO assert valid_read_string(file_recovery_new.extension); */ + file_recovery_new.file_stat=&file_stats; + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_emf; */ + /*@ assert file_recovery_new.file_size == 0; */; + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_emf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_ess.c b/subprojects/lib/src/file_ess.c new file mode 100644 index 0000000..a837c39 --- /dev/null +++ b/subprojects/lib/src/file_ess.c @@ -0,0 +1,63 @@ +/* + + File: file_ess.c + + Copyright (C) 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ess) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ess(file_stat_t *file_stat); + +const file_hint_t file_hint_ess= { + .extension="ess", + .description="Skyrim Savegame", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ess +}; + +/*@ + @ requires separation: \separated(&file_hint_ess, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ess(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ess.extension; + return 1; +} + +static void register_header_check_ess(file_stat_t *file_stat) +{ + register_header_check(0, "TESV_SAVEGAME", 13, &header_check_ess, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_evt.c b/subprojects/lib/src/file_evt.c new file mode 100644 index 0000000..51fe37f --- /dev/null +++ b/subprojects/lib/src/file_evt.c @@ -0,0 +1,126 @@ +/* + + File: file_evt.c + + Copyright (C) 2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_evt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_evt(file_stat_t *file_stat); + +const file_hint_t file_hint_evt= { + .extension="evt", + .description="Windows Event Log", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_evt +}; + +struct evt_chunk { + uint32_t size; + uint32_t id; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_evt; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_evt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + const struct evt_chunk *chunk=(const struct evt_chunk *)&buffer[i]; + if((buffer[i+4]=='L' && buffer[i+5]=='f' && buffer[i+6]=='L' && buffer[i+7]=='e') || + (buffer[i+4]==0x11 && buffer[i+5]==0x11 && buffer[i+6]==0x11 && buffer[i+7]==0x11) || + (buffer[i+4]==0x22 && buffer[i+5]==0x22 && buffer[i+6]==0x22 && buffer[i+7]==0x22) || + (buffer[i+4]==0x33 && buffer[i+5]==0x33 && buffer[i+6]==0x33 && buffer[i+7]==0x33) || + (buffer[i+4]==0x44 && buffer[i+5]==0x44 && buffer[i+6]==0x44 && buffer[i+7]==0x44)) + { + const unsigned int length=le32(chunk->size); + if(length<8) + { + return DC_STOP; + } + file_recovery->calculated_file_size+=length; + } + else + { + return DC_STOP; + } + } + /* + log_trace("data_check_evt record_offset=0x%x\n\n",record_offset); + */ + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_evt, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_evt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct evt_chunk *chunk=(const struct evt_chunk *)buffer; + const struct evt_chunk *chunk2; + if(le32(chunk->size) != 0x30) + return 0; + chunk2=(const struct evt_chunk *)&buffer[le32(chunk->size)]; + if(le32(chunk2->size) < 8) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_evt.extension; + if(file_recovery_new->blocksize >= 8) + { + file_recovery_new->calculated_file_size=le32(chunk->size); + file_recovery_new->data_check=&data_check_evt; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_evt(file_stat_t *file_stat) +{ + static const unsigned char evt_header[8]= {0x30, 0x00, 0x00, 0x00, 'L', 'f', 'L', 'e'}; + register_header_check(0, evt_header,sizeof(evt_header), &header_check_evt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_evtx.c b/subprojects/lib/src/file_evtx.c new file mode 100644 index 0000000..6d93977 --- /dev/null +++ b/subprojects/lib/src/file_evtx.c @@ -0,0 +1,90 @@ +/* + + File: file_evtx.c + + Copyright (C) 2019 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_evtx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +struct evtx_header +{ + char magic[8]; + uint64_t OldestChunk; + uint64_t CurrentChunkNum; + uint64_t NextRecordNum; + uint32_t HeaderPart1Len; /* 0x80 */ + uint16_t MinorVersion; /* 1 */ + uint16_t MajorVersion; /* 3 */ + uint16_t HeaderSize; /* 0x1000 */ + uint16_t ChunkCount; + char unk[76]; /* 0 */ + uint32_t Flags; + uint32_t Checksum; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_evtx(file_stat_t *file_stat); + +const file_hint_t file_hint_evtx= { + .extension="evtx", + .description="Microsoft Event Log", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_evtx +}; + +/*@ + @ requires buffer_size >= sizeof(struct evtx_header); + @ requires separation: \separated(&file_hint_evtx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_evtx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct evtx_header *hdr=(const struct evtx_header *)buffer; + if(le32(hdr->HeaderPart1Len) != 0x80 || + le16(hdr->MinorVersion) != 1 || + le16(hdr->MajorVersion) != 3 || + le16(hdr->HeaderSize) != 0x1000) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_evtx.extension; + file_recovery_new->calculated_file_size=(uint64_t)le16(hdr->HeaderSize) + (uint64_t)le16(hdr->ChunkCount) * 64 * 1024; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_evtx(file_stat_t *file_stat) +{ + register_header_check(0, "ElfFile", 8, &header_check_evtx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_exe.c b/subprojects/lib/src/file_exe.c new file mode 100644 index 0000000..a460183 --- /dev/null +++ b/subprojects/lib/src/file_exe.c @@ -0,0 +1,1003 @@ +/* + + File: file_exe.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exe) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "pe.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_exe(file_stat_t *file_stat); + +const file_hint_t file_hint_exe= { + .extension="exe", + .description="MS Windows executable", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_exe +}; + +static const char *extension_dll="dll"; +static const unsigned char exe_header[2] = {'M','Z'}; + +struct rsrc_entries_s +{ + uint32_t Type; + uint32_t Pos; +} __attribute__ ((gcc_struct, __packed__)); + +struct rsrc_offlen +{ + uint32_t off; + uint32_t len; +} __attribute__ ((gcc_struct, __packed__)); + +struct PE_index +{ + uint16_t len; + uint16_t val_len; + uint16_t type; /* 0=binary data, 1=text*/ +} __attribute__ ((gcc_struct, __packed__)); + +static char vs_version_info[32]={ + 'V', 0x0, 'S', 0x0, '_', 0x0, 'V', 0x0, 'E', 0x0, 'R', 0x0, 'S', 0x0, 'I', 0x0, + 'O', 0x0, 'N', 0x0, '_', 0x0, 'I', 0x0, 'N', 0x0, 'F', 0x0, 'O', 0x0, 0x0, 0x0 +}; + +static char StringFileInfo[30]={ + 'S', 0x0, 't', 0x0, 'r', 0x0, 'i', 0x0, 'n', 0x0, 'g', 0x0, 'F', 0x0, 'i', 0x0, + 'l', 0x0, 'e', 0x0, 'I', 0x0, 'n', 0x0, 'f', 0x0, 'o', 0x0, 0x0, 0x0 +}; + +static char OriginalFilename[34]={ + 'O', 0x0, 'r', 0x0, 'i', 0x0, 'g', 0x0, 'i', 0x0, 'n', 0x0, 'a', 0x0, 'l', 0x0, + 'F', 0x0, 'i', 0x0, 'l', 0x0, 'e', 0x0, 'n', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0, + 0x0, 0x0 +}; + +static char InternalName[24]={ + 'I', 0x0, 'n', 0x0, 't', 0x0, 'e', 0x0, 'r', 0x0, 'n', 0x0, 'a', 0x0, 'l', 0x0, + 'N', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0 +}; + +/*@ + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires needle_len > 0; + @ requires \valid_read(buffer+(0..end-1)); + @ requires \valid_read(needle+(0..needle_len-1)); + @ requires \separated(file_recovery, buffer+(..), needle+(..)); + @*/ +static int parse_String(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext) +{ + const struct PE_index *PE_index; + unsigned int len; + unsigned int val_len; + unsigned int type; + if(6 > end) + { + return -1; + } + PE_index=(const struct PE_index*)buffer; + len=le16(PE_index->len); + val_len=le16(PE_index->val_len); + type=le16(PE_index->type); +#ifdef DEBUG_EXE + log_info("parse_String len=%u val_len=%u type=%u\n", len, val_len, type); +#endif + if(len > end) + return -1; + if(6 + 2 * val_len > len) + return -1; +#ifdef DEBUG_EXE + dump_log(buffer, len); +#endif +// type=1 => text + if(6+needle_len < end && type==1 && memcmp(&buffer[6], needle, needle_len)==0) + { + if(6 + needle_len + 2 * val_len > len) + return -1; + file_rename_unicode(file_recovery, buffer, end, 6+needle_len, NULL, force_ext); + } + return len; +} + +/*@ + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires needle_len > 0; + @ requires \valid_read(buffer+(0..end-1)); + @ requires \valid_read(needle+(0..needle_len-1)); + @ requires \separated(file_recovery, buffer+(..), needle+(..)); + @*/ +static int parse_StringArray(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext) +{ + unsigned int pos=0; +#ifdef DEBUG_EXE + log_info("parse_StringArray end=%u\n", end); +#endif + /*@ + @ loop variant end - pos; + @*/ + while(pos 0; */ + pos+=res; + /* Padding */ + if((pos & 0x03)!=0) + pos+=2; + } + return 0; +} + +/*@ + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires needle_len > 0; + @ requires \valid_read(buffer+(0..end-1)); + @ requires \valid_read(needle+(0..needle_len-1)); + @ requires \separated(file_recovery, buffer+(..), needle+(..)); + @*/ +static int parse_StringTable(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext) +{ + const struct PE_index *PE_index; + unsigned int pos; + unsigned int len; + unsigned int val_len; + if(6 > end) + { + return -1; + } + PE_index=(const struct PE_index*)buffer; + /*@ assert \valid_read(PE_index); */ + len=le16(PE_index->len); + val_len=le16(PE_index->val_len); +#ifdef DEBUG_EXE + log_info("parse_StringTable len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type)); +#endif + if(len > end) + return -1; + /* szKey: language identifier + code page */ + pos = 6 + 2*8 + 2; + /* Padding */ + if((pos & 0x03)!=0) + pos+=2; + if(pos > len) + return -1; + /* An array of one or more String structures */ + return parse_StringArray(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext); +} + +/*@ + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires needle_len > 0; + @ requires \valid_read(buffer+(0..end-1)); + @ requires \valid_read(needle+(0..needle_len-1)); + @ requires \separated(file_recovery, buffer+(..), needle+(..)); + @*/ +static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext) +{ + /* https://docs.microsoft.com/en-us/windows/win32/menurc/stringfileinfo */ + const struct PE_index *PE_index; + unsigned int pos; + unsigned int len; + unsigned int val_len; + if(6 > end) + { + return -1; + } + PE_index=(const struct PE_index*)buffer; + /*@ assert \valid_read(PE_index); */ + len=le16(PE_index->len); + val_len=le16(PE_index->val_len); +#ifdef DEBUG_EXE + log_info("parse_StringFileInfo len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type)); +#endif + if(len > end) + return -1; + if(6 + sizeof(StringFileInfo) > end) + return 0; + /* szKey == StringFileInfo ? */ + if(memcmp(&buffer[6], StringFileInfo, sizeof(StringFileInfo))!=0) + return 0; + if(val_len!=0) + return -1; + pos=6 + sizeof(StringFileInfo); + /* Padding */ + if((pos & 0x03)!=0) + pos+=2; + if(pos > len) + return -1; + return parse_StringTable(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext); +} + +/*@ + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires end > 0; + @ requires needle_len > 0; + @ requires \valid_read(buffer+(0..end-1)); + @ requires \valid_read(needle+(0..needle_len-1)); + @ requires \separated(vs_version_info+(..), file_recovery, buffer+(..), needle+(..)); + @ behavior types: requires \separated(vs_version_info+(..), \union(file_recovery, buffer+(..), needle+(..))); + @*/ +static int parse_VS_VERSIONINFO(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext) +{ + /* https://docs.microsoft.com/en-us/windows/win32/menurc/vs-versioninfo */ + unsigned int pos=0; + const struct PE_index *PE_index; + const char *stringName; + unsigned int len; + unsigned int val_len; + if(6 > end) + { + return -1; + } + PE_index=(const struct PE_index*)buffer; + /*@ assert \valid_read(PE_index); */ + len=le16(PE_index->len); + val_len=le16(PE_index->val_len); +#ifdef DEBUG_EXE + log_info("parse_VS_VERSIONINFO len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type)); +#endif + if(len==0 && val_len==0) + { + return -1; + } + if(val_len > len) + return -1; + if(len > end) + return -1; + /*@ assert len <= end; */ + pos+=6; + if(pos + sizeof(vs_version_info) >= len) + return -1; + stringName=&buffer[pos]; + /* szKey */ + if(memcmp(stringName, vs_version_info, sizeof(vs_version_info))!=0) + return -1; + pos+=sizeof(vs_version_info); + /* Padding1 */ + if((pos & 0x03)!=0) + pos+=2; + /* VS_FIXEDFILEINFO */ + pos+=val_len; + /* Padding2 */ + if((pos & 0x03)!=0) + pos+=2; + if(pos > len) + return -1; + /* Children */ + /* An array of zero or one StringFileInfo structures, and zero or one + * VarFileInfo structures that are children of the current VS_VERSIONINFO structure. */ + if(parse_StringFileInfo(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext) < 0) + return -1; + return 0; +} + +/*@ + @ requires \valid(file); + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @*/ +static void PEVersion(FILE *file, const unsigned int offset, const unsigned int length, file_recovery_t *file_recovery) +{ + char buffer[1024*1024]; +#ifdef DEBUG_EXE + log_info("PEVersion(file, %u, %u, file_recovery)\n", offset, length); +#endif + if(length==0 || length > 1024*1024) + return; + if(fseek(file, offset, SEEK_SET)<0) + return ; + if(fread(&buffer, length, 1, file) != 1) + { + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + if(parse_VS_VERSIONINFO(file_recovery, (const char *)&buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0) + { + return; + } + parse_VS_VERSIONINFO(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1); +} + +/*@ + @ requires \valid(file); + @ requires base <= 0x7fffffff; + @ requires \valid_read(pe_sections); + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @ requires \valid_read(rsrc_entry); + @*/ +static int pe_resource_language_aux(FILE *file, const unsigned int base, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery, const struct rsrc_entries_s *rsrc_entry) +{ + struct rsrc_offlen buffer; + uint32_t off; + unsigned int len; + unsigned int j; +#ifdef DEBUG_EXE + log_info("resource lang=%u, %x, offset %u\n", + le32(rsrc_entry->Type), + le32(rsrc_entry->Pos), + base + (le32(rsrc_entry->Pos) & 0x7fffffff)); +#endif + if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0) + { + return -1; + } + if(fread(&buffer, 1, sizeof(buffer), file) != sizeof(buffer)) + { + return -1; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + off=le32(buffer.off); + len=le32(buffer.len); + /*TODO: loop invariant 0 <= j <= nbr_sections; */ + for(j=0; jVirtualAddress); + const uint64_t virt_addr_end=(uint64_t)virt_addr_start + le32(pe_section->SizeOfRawData); + if(virt_addr_end <= 0xffffffff && virt_addr_start <= off && off < virt_addr_end && (uint64_t)off - virt_addr_start + base <=0xffffffff) + { + PEVersion(file, off - virt_addr_start + base, len, file_recovery); + return 0; + } + } + return 1; +} + +/*@ + @ requires \valid(file); + @ requires base <= 0x7fffffff; + @ requires dir_start <= 0x7fffffff; + @ requires \valid_read(pe_sections); + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @*/ +static void pe_resource_language(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery) +{ + struct rsrc_entries_s *rsrc_entries; + unsigned int count; + unsigned int i; +#ifdef DEBUG_EXE + log_info("pe_resource_language(file, %u, %u)\n", base, dir_start); +#endif + { + unsigned char buffer[16]; + unsigned int nameEntries; + unsigned int idEntries; + if(fseek(file, base + dir_start, SEEK_SET)<0) + return ; + if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + nameEntries = buffer[12]+(buffer[13]<<8); + idEntries = buffer[14]+(buffer[15]<<8); + count = nameEntries + idEntries; + } +#ifdef DEBUG_EXE + log_info("pe_resource_language count=%u\n", count); +#endif + if(count==0 || count > 1024) + return ; + /*@ assert 0 < count <= 1024; */ +#ifdef __FRAMAC__ + rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s)); +#else + rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s)); +#endif + /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */ + if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count) + { + free(rsrc_entries); + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s)); +#endif + for(i=0; ifilename); + @*/ +static void pe_resource_id(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery) +{ + struct rsrc_entries_s *rsrc_entries; + unsigned int count; + unsigned int i; +#ifdef DEBUG_EXE + log_info("pe_resource_id(file, %u, %u)\n", base, dir_start); +#endif + { + unsigned char buffer[16]; + unsigned int nameEntries; + unsigned int idEntries; + if(fseek(file, base + dir_start, SEEK_SET)<0) + return ; + if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + nameEntries = buffer[12]+(buffer[13]<<8); + idEntries = buffer[14]+(buffer[15]<<8); + count = nameEntries + idEntries; + } + if(count==0 || count > 1024) + return ; + /*@ assert 0 < count <= 1024; */ +#ifdef __FRAMAC__ + rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s)); +#else + rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s)); +#endif + /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */ + if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count) + { + free(rsrc_entries); + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s)); +#endif + for(i=0; iType), + le32(rsrc_entry->Pos), + base + (le32(rsrc_entry->Pos) & 0x7fffffff)); +#endif + if((le32(rsrc_entry->Pos) & 0x80000000)!=0) + { + pe_resource_language(file, + base, + le32(rsrc_entry->Pos) & 0x7fffffff, + pe_sections, nbr_sections, file_recovery); + } + } + free(rsrc_entries); +} + +/*@ + @ requires \valid(file); + @ requires \valid_read(pe_sections); + @ requires \valid(file_recovery); + @ requires valid_read_string((char*)&file_recovery->filename); + @*/ +static void pe_resource_type(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery) +{ + struct rsrc_entries_s *rsrc_entries; + unsigned int count; + unsigned int i; +#ifdef DEBUG_EXE + log_info("pe_resource_type(file, %u, %u)\n", base, dir_start); +#endif + /* TODO: remove these artifical limits ? */ + if(base > 0x7fffffff || dir_start > 0x7fffffff) + return ; + /*@ assert base <= 0x7fffffff; */ + { + unsigned char buffer[16]; + unsigned int nameEntries; + unsigned int idEntries; + if(fseek(file, base, SEEK_SET)<0) + return ; + if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + nameEntries = buffer[12]+(buffer[13]<<8); + idEntries = buffer[14]+(buffer[15]<<8); + count = nameEntries + idEntries; + } + if(count==0 || count > 1024) + return ; + /*@ assert 0 < count <= 1024; */ +#ifdef __FRAMAC__ + rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s)); +#else + rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s)); +#endif + /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */ + if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count) + { + free(rsrc_entries); + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s)); +#endif + for(i=0; iType); +#ifdef DEBUG_EXE + log_info("resource type=%u, %x, offset %u\n", + rsrcType, + le32(rsrc_entry->Pos), + base + (le32(rsrc_entry->Pos) & 0x7fffffff)); +#endif + /* https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types + * RT_CURSOR=1, RT_ICON=3, RT_VERSION=16 */ + /* Only interested by version resources */ + if(rsrcType==16) + { + if((le32(rsrc_entry->Pos) & 0x80000000)!=0) + { + pe_resource_id(file, + base, + le32(rsrc_entry->Pos) & 0x7fffffff, + pe_sections, nbr_sections, file_recovery); + } + } + } + free(rsrc_entries); +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_pe_exe; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_pe_exe(file_recovery_t *file_recovery) +{ + unsigned char buffer[4096]; + FILE *file; + int buffer_size; + const struct dos_image_file_hdr *dos_hdr; + const struct pe_image_file_hdr *pe_hdr; + unsigned int e_lfanew; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + /*@ assert buffer_size <= sizeof(buffer); */ + if(buffer_size < (int)sizeof(struct dos_image_file_hdr)) + { + fclose(file); + return ; + } + /*@ assert buffer_size >= sizeof(struct dos_image_file_hdr); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + if(memcmp(buffer,exe_header,sizeof(exe_header))!=0) + { + fclose(file); + return ; + } + dos_hdr=(const struct dos_image_file_hdr*)buffer; + e_lfanew=le32(dos_hdr->e_lfanew); + if((unsigned int)buffer_size < e_lfanew+sizeof(struct pe_image_file_hdr)) + { + fclose(file); + return ; + } + if(e_lfanew==0 || + e_lfanew > buffer_size-sizeof(struct pe_image_file_hdr)) + { + fclose(file); + return ; + } + pe_hdr=(const struct pe_image_file_hdr *)(buffer+e_lfanew); + if(le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE) + { + fclose(file); + return ; + } + { + const uint64_t offset_sections=e_lfanew + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader); + /* https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + * Windows loader limits the number of sections to 96 + */ + const unsigned int nbr_sections=(le16(pe_hdr->NumberOfSections) < 96?le16(pe_hdr->NumberOfSections) : 96); + struct pe_image_section_hdr pe_sections[96]; + unsigned int i; + if(nbr_sections == 0) + { + fclose(file); + return ; + } + /*@ assert 0 < nbr_sections <= 96; */ + if(fseek(file, offset_sections, SEEK_SET)<0) + { + fclose(file); + return ; + } + if(fread(pe_sections, sizeof(struct pe_image_section_hdr), nbr_sections, file) != nbr_sections) + { + fclose(file); + return ; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)pe_sections, sizeof(pe_sections)); +#endif +#ifdef DEBUG_EXE + /*@ + @ loop invariant 0 <= i <= nbr_sections; + @*/ + for(i=0; iVirtualSize)>0) + { + log_info("%s 0x%lx-0x%lx\n", pe_section->Name, + (unsigned long)le32(pe_section->VirtualAddress), + (unsigned long)le32(pe_section->VirtualAddress)+le32(pe_section->VirtualSize)-1); + } + } +#endif + /*@ + @ loop invariant 0 <= i <= nbr_sections; + @*/ + for(i=0; iSizeOfRawData)>0) + { + if(memcmp((const char*)pe_section->Name, ".rsrc", 6)==0) + { + pe_resource_type(file, + le32(pe_section->PointerToRawData), + le32(pe_section->SizeOfRawData), + pe_sections, nbr_sections, file_recovery); + fclose(file); + return; + } + } + } + } + fclose(file); +} + +/*@ + @ requires buffer_size >= 2; + @ requires separation: \separated(&file_hint_exe, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_exe.extension || file_recovery_new->extension == extension_dll); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null || file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == \null || file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null || file_recovery_new->file_rename == &file_rename_pe_exe); + @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension)); + @ assigns *file_recovery_new; + @*/ +static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer; + if(memcmp(buffer,exe_header,sizeof(exe_header))!=0) + return 0; + if(le32(dos_hdr->e_lfanew)>0 && + le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr)) + { + const struct pe_image_file_hdr *pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew)); + if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE) + { + /* NE Win16 */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_exe.extension; + file_recovery_new->min_filesize=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr); + return 1; + } + if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE) + { + /* Windows PE */ + if(le16(pe_hdr->Characteristics) & 0x2000) + { + /* Dynamic Link Library */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_dll; + } + else if(le16(pe_hdr->Characteristics) & 0x02) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_exe.extension; + } + else + { +#ifdef DEBUG_EXE + log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics)); +#endif + return 0; + } + file_recovery_new->time=le32(pe_hdr->TimeDateStamp); +#ifdef DEBUG_EXE + { + const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *) + (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr))); + if((const unsigned char*)(pe_image_optional32+1) <= buffer+buffer_size) + { + /*@ assert \valid_read(pe_image_optional32); */ + if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC) + { + log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode)); + log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage)); + } + else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *) + (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr))); + } + log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr), + (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1)); + } + } +#endif + { + unsigned int i; + uint64_t sum=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr); + const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*) + ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader)); + /*@ + @ loop assigns i, pe_image_section, sum; + @*/ + for(i=0; + iNumberOfSections) && + (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size; + i++,pe_image_section++) + { + if(le32(pe_image_section->SizeOfRawData)>0) + { + const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData); +#ifdef DEBUG_EXE + log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name, + (unsigned long)le32(pe_image_section->PointerToRawData), + (unsigned long)(tmp-1)); +#endif + if(le32(pe_image_section->SizeOfRawData)%32==0) + { + if(sum < tmp) + sum=tmp; + } + } + if(le16(pe_image_section->NumberOfRelocations)>0) + { + /*@ assert le16(pe_image_section->NumberOfRelocations)>0; */ + const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations); + /*@ assert tmp > 0; */ +#ifdef DEBUG_EXE + log_debug("relocations 0x%lx-0x%lx\n", + (unsigned long)le32(pe_image_section->PointerToRelocations), + (unsigned long)(tmp-1)); +#endif + if(sum < tmp) + sum = tmp; + } + } + if(le32(pe_hdr->NumberOfSymbols)>0) + { + /*@ assert le32(pe_hdr->NumberOfSymbols)>0; */ + const uint64_t tmp=(uint64_t)le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*(uint64_t)le32(pe_hdr->NumberOfSymbols); + /*@ assert tmp > 0; */ +#ifdef DEBUG_EXE + log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable), + (long unsigned)(tmp-1)); +#endif + if(le32(pe_hdr->NumberOfSymbols)<0x10000) + { + if(sum < tmp) + sum = tmp; + } + } + /* It's not perfect, EXE overlay are not recovered */ + file_recovery_new->calculated_file_size=sum; + } + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_pe_exe; + return 1; + } + } + if(le16(dos_hdr->bytes_in_last_block) <= 512 && + le16(dos_hdr->blocks_in_file) > 0 && + le16(dos_hdr->min_extra_paragraphs) <= le16(dos_hdr->max_extra_paragraphs) + ) + { + /* MSDOS EXE */ + uint64_t coff_offset=le16(dos_hdr->blocks_in_file)*512; + if(le16(dos_hdr->bytes_in_last_block)) + coff_offset-=512-le16(dos_hdr->bytes_in_last_block); + + if(coff_offset < buffer_size-1 && + buffer[coff_offset]==0x4c && buffer[coff_offset+1]==0x01) + { /* COFF_I386MAGIC */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_exe.extension; + file_recovery_new->min_filesize=coff_offset+2; + return 1; + } +#ifdef DEBUG_EXE + { + const struct exe_reloc *exe_relocs; + const unsigned int reloc_table_offset=le16(dos_hdr->reloc_table_offset); + const unsigned int num_relocs=le16(dos_hdr->num_relocs); + log_info("Maybe a DOS EXE\n"); + log_info("blocks %llu\n", (long long unsigned)coff_offset); + log_info("data start %llx\n", (long long unsigned)16*le16(dos_hdr->header_paragraphs)); + log_info("reloc %u\n", num_relocs); + if(reloc_table_offset + num_relocs * sizeof(struct exe_reloc) <= buffer_size) + { + unsigned int i; + /*@ assert reloc_table_offset + num_relocs * sizeof(struct exe_reloc) <= buffer_size; */ + exe_relocs=(const struct exe_reloc *)(buffer+reloc_table_offset); + /*@ assert \valid_read(exe_relocs + (0 .. num_relocs-1)); */ + /*@ + @ loop invariant 0 <= i <= num_relocs; + @ loop variant num_relocs -i; + @ */ + for(i=0; i < num_relocs; i++) + { + /*@ assert 0 <= i <= num_relocs; */ + const struct exe_reloc *exe_reloc=&exe_relocs[i]; + /*@ assert \valid_read(exe_reloc); */ + log_info("offset %x, segment %x\n", + le16(exe_reloc->offset), le16(exe_reloc->segment)); + } + } + } +#endif + } + return 0; +} + +static void register_header_check_exe(file_stat_t *file_stat) +{ + register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat); +} +#endif + +#if defined(MAIN_exe) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.exe"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_exe; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_exe(&file_stats); + if(header_check_exe(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.extension == file_hint_exe.extension || file_recovery_new.extension == extension_dll; */ + file_recovery_new.file_stat=&file_stats; + if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL && + file_recovery_new.data_check!=NULL) + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_size == 0; */; + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + if(file_recovery_new.file_stat!=NULL) + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_exe(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + if(file_recovery_new.file_check!=NULL) + { + /*@ assert file_recovery_new.file_check == &file_check_size; */ + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + if(file_recovery_new.file_rename!=NULL) + { + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert file_recovery_new.file_rename == &file_rename_pe_exe; */ + file_rename_pe_exe(&file_recovery_new); + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_exr.c b/subprojects/lib/src/file_exr.c new file mode 100644 index 0000000..187f2c2 --- /dev/null +++ b/subprojects/lib/src/file_exr.c @@ -0,0 +1,67 @@ +/* + + File: file_exr.c + + Copyright (C) 2019 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_exr(file_stat_t *file_stat); + +const file_hint_t file_hint_exr= { + .extension="exr", + .description="OpenEXR", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_exr +}; + +/* https://www.openexr.com/documentation/openexrfilelayout.pdf */ +/*@ + @ requires separation: \separated(&file_hint_exr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_exr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_exr.extension; + file_recovery_new->min_filesize=0x20; + return 1; +} + +static void register_header_check_exr(file_stat_t *file_stat) +{ + /* OpenEXR v2 */ + static const unsigned char exr_header[5]= { 'v' , 0x2f, '1' , 0x01, 0x02 }; + register_header_check(0, exr_header, sizeof(exr_header), &header_check_exr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_exs.c b/subprojects/lib/src/file_exs.c new file mode 100644 index 0000000..f7761b6 --- /dev/null +++ b/subprojects/lib/src/file_exs.c @@ -0,0 +1,89 @@ +/* + + File: file_exs.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exs) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_exs(file_stat_t *file_stat); + +const file_hint_t file_hint_exs= { + .extension="exs", + .description="Apple Logic", + .max_filesize=1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_exs +}; + +/*@ + @ requires file_recovery->file_rename==&file_rename_exs; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_exs(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + int buffer_size; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + file_rename(file_recovery, buffer, buffer_size, 0x14, "exs", 0); +} + +/*@ + @ requires buffer_size >= 0x14; + @ requires separation: \separated(&file_hint_exs, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_exs); + @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension)); + @ assigns *file_recovery_new; + @*/ +static int header_check_exs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x10], "TBOS", 4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_exs.extension; + file_recovery_new->file_rename=&file_rename_exs; + return 1; +} + +static void register_header_check_exs(file_stat_t *file_stat) +{ + static const unsigned char exs_header[8]= { + 0x01, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00 + }; + register_header_check(0, exs_header, sizeof(exs_header), &header_check_exs, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ext.c b/subprojects/lib/src/file_ext.c new file mode 100644 index 0000000..e73df08 --- /dev/null +++ b/subprojects/lib/src/file_ext.c @@ -0,0 +1,173 @@ +/* + + File: file_ext2_sb.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ext2_sb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "ext2_common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ext2_sb(file_stat_t *file_stat); + +const file_hint_t file_hint_ext2_sb= { + .extension="ext", + .description="ext2/ext3/ext4 Superblock", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=0, + .enable_by_default=1, + .register_header_check=®ister_header_check_ext2_sb +}; + +/*@ + @ requires file_recovery->file_rename==&file_rename_ext; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_ext(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + char buffer_cluster[32]; + FILE *file; + const struct ext2_super_block *sb=(const struct ext2_super_block *)&buffer; + int buffer_size; + unsigned long int block_nr; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size!=sizeof(buffer)) + return; + /*@ assert buffer_size == sizeof(buffer); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + /*@ assert \initialized(buffer + (0 .. sizeof(buffer)-1)); */ + block_nr=(unsigned long int)le32(sb->s_first_data_block) + (unsigned long int)le16(sb->s_block_group_nr)*le32(sb->s_blocks_per_group); + sprintf(buffer_cluster, "sb_%lu", block_nr); +#if defined(__FRAMAC__) + buffer_cluster[sizeof(buffer_cluster)-1]='\0'; +#endif + file_rename(file_recovery, buffer_cluster, strlen(buffer_cluster), 0, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct ext2_super_block); + @ requires separation: \separated(&file_hint_ext2_sb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ext2_sb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ext2_super_block *sb=(const struct ext2_super_block *)buffer; + if(test_EXT2(sb, NULL)!=0) + return 0; + /*@ assert le32(sb->s_log_block_size) <= 6; */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ext2_sb.extension; + file_recovery_new->file_size=(uint64_t)EXT2_MIN_BLOCK_SIZE<s_log_block_size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_ext; + return 1; +} + +/*@ + @ requires file_recovery->data_check==&data_check_extdir; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_extdir(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /* Save only one block */ + file_recovery->calculated_file_size=buffer_size/2; + return DC_STOP; +} + +/*@ + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_extdir(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + char buffer_cluster[32]; + FILE *file; + int buffer_size; + const uint32_t *inode=(const uint32_t *)&buffer[0]; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size!=sizeof(buffer)) + return; + /*@ assert buffer_size == sizeof(buffer); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + /*@ assert \initialized(buffer + (0 .. sizeof(buffer)-1)); */ + sprintf(buffer_cluster, "inode_%u", (unsigned int)le32(*inode)); +#if defined(__FRAMAC__) + buffer_cluster[sizeof(buffer_cluster)-1]='\0'; +#endif + file_rename(file_recovery, buffer_cluster, strlen(buffer_cluster), 0, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct ext2_super_block); + @ requires separation: \separated(&file_hint_ext2_sb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ext2_dir(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char ext2_ll_dir2[6]= { 0x02, 0x02, '.', '.', 0x00, 0x00}; + if(memcmp(&buffer[0x12], ext2_ll_dir2, sizeof(ext2_ll_dir2))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ext2_sb.extension; + file_recovery_new->data_check=&data_check_extdir; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_extdir; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +static void register_header_check_ext2_sb(file_stat_t *file_stat) +{ + static const unsigned char ext2_sb_header[2]= {0x53, 0xEF}; + static const unsigned char ext2_ll_dir1[8]= {0x0c, 0x00, 0x01, 0x02, '.', 0x00, 0x00, 0x00}; + register_header_check(0x38, ext2_sb_header, sizeof(ext2_sb_header), &header_check_ext2_sb, file_stat); + register_header_check(0x4, ext2_ll_dir1, sizeof(ext2_ll_dir1), &header_check_ext2_dir, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ext2.c b/subprojects/lib/src/file_ext2.c new file mode 100644 index 0000000..4df9f04 --- /dev/null +++ b/subprojects/lib/src/file_ext2.c @@ -0,0 +1,82 @@ +/* + + File: file_ext2_fs.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ext2_fs) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "ext2_common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ext2_fs(file_stat_t *file_stat); + +const file_hint_t file_hint_ext2_fs= { + .extension="ext2", + .description="ext2/ext3/ext4 Filesystem", + .max_filesize=0, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_ext2_fs +}; + +/*@ + @ requires buffer_size >= sizeof(struct ext2_super_block); + @ requires separation: \separated(&file_hint_ext2_fs, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_ext2_fs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ext2_super_block *sb=(const struct ext2_super_block *)&buffer[0x400]; + if(test_EXT2(sb, NULL)!=0) + return 0; + /*@ assert le32(sb->s_log_block_size) <= 6; */ + if(le16(sb->s_block_group_nr)!=0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_ext2_fs && + file_recovery->calculated_file_size==(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<s_log_block_size))) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ext2_fs.extension; + file_recovery_new->calculated_file_size=(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<s_log_block_size)); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_ext2_fs(file_stat_t *file_stat) +{ + static const unsigned char ext2_fs_header[2]= {0x53, 0xEF}; + register_header_check(0x438, ext2_fs_header,sizeof(ext2_fs_header), &header_check_ext2_fs, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fat.c b/subprojects/lib/src/file_fat.c new file mode 100644 index 0000000..9c4ae46 --- /dev/null +++ b/subprojects/lib/src/file_fat.c @@ -0,0 +1,159 @@ +/* + + File: file_fat.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fat) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" +#include "fat_common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fat(file_stat_t *file_stat); + +const file_hint_t file_hint_fat= { + .extension="fat", + .description="FAT", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_fat +}; + +/*@ + @ requires \valid(file_recovery_new); + @ requires file_recovery_new->blocksize > 0; + @ requires part_size <= 0xffffffff; + @ requires sector_size <= 65535; + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fat_aux(file_recovery_t *file_recovery_new, const unsigned int part_size, const unsigned int sector_size) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fat.extension; + file_recovery_new->calculated_file_size=(uint64_t)part_size * sector_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(struct fat_boot_sector); + @ requires separation: \separated(&file_hint_fat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)buffer; + uint64_t start_fat1,start_data,part_size; + unsigned long int no_of_cluster,fat_length,fat_length_calc; + const unsigned int sector_size=fat_sector_size(fat_header); + if(!(le16(fat_header->marker)==0xAA55 + && (fat_header->ignored[0]==0xeb || fat_header->ignored[0]==0xe9) + && (fat_header->fats==1 || fat_header->fats==2))) + return 0; /* Obviously not a FAT */ + if(!((fat_header->ignored[0]==0xeb && fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9)) + return 0; + if(sector_size==0 || sector_size%512!=0) + return 0; + /*@ assert sector_size >= 512; */ + switch(fat_header->sectors_per_cluster) + { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + break; + default: + return 0; + } + /*@ assert fat_header->sectors_per_cluster != 0; */ + if(fat_header->fats!=1 && fat_header->fats!=2) + return 0; + /*@ assert fat_header->fats==1 || fat_header->fats==2; */ + if(fat_header->media!=0xF0 && fat_header->media<0xF8) + return 0; + fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length); + part_size=(fat_sectors(fat_header)>0?fat_sectors(fat_header):le32(fat_header->total_sect)); + start_fat1=le16(fat_header->reserved); + start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+sector_size-1)/sector_size; + if(part_size < start_data) + return 0; + /*@ assert part_size >= start_data; */ + no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster; + if(no_of_cluster<4085) + { + /* FAT12 */ + if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0)) + return 0; + if((le16(fat_header->fat_length)>256)||(le16(fat_header->fat_length)==0)) + return 0; + fat_length_calc=((no_of_cluster+2+sector_size*2/3-1)*3/2/sector_size); + } + else if(no_of_cluster<65525) + { + /* FAT16 */ + if(le16(fat_header->fat_length)==0) + return 0; + if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0)) + return 0; + fat_length_calc=((no_of_cluster+2+sector_size/2-1)*2/sector_size); + } + else + { + /* FAT32 */ + if(fat_sectors(fat_header)!=0) + return 0; + if(get_dir_entries(fat_header)!=0) + return 0; + if((le32(fat_header->root_cluster)<2) ||(le32(fat_header->root_cluster)>=2+no_of_cluster)) + return 0; + fat_length_calc=((no_of_cluster+2+sector_size/4-1)*4/sector_size); + } + if(fat_length + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fbf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fbf(file_stat_t *file_stat); + +const file_hint_t file_hint_fbf= { + .extension="fbf", + .description="SymBackup", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fbf +}; + +/*@ + @ requires separation: \separated(&file_hint_fbf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fbf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fbf.extension; + return 1; +} + +static void register_header_check_fbf(file_stat_t *file_stat) +{ + static const unsigned char fbf_header[16]= { + 'S' , 'y' , 'm' , 'B' , 'a' , 'k' , 'U' , 'p' , + ' ' , ' ' , '1' , '.' , '0' , 0x0a, 0x1a, 0x01 + }; + register_header_check(0, fbf_header, sizeof(fbf_header), &header_check_fbf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fbk.c b/subprojects/lib/src/file_fbk.c new file mode 100644 index 0000000..4fb0fb6 --- /dev/null +++ b/subprojects/lib/src/file_fbk.c @@ -0,0 +1,64 @@ +/* + + File: file_fbk.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fbk) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fbk(file_stat_t *file_stat); + +const file_hint_t file_hint_fbk= { + .extension="fbk", + .description="Microsoft Dynamics NAV (MS Navision)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fbk +}; + +/*@ + @ requires separation: \separated(&file_hint_fbk, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fbk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fbk.extension; + return 1; +} + +static void register_header_check_fbk(file_stat_t *file_stat) +{ + static const unsigned char fbk_header[10] = {'T','a','b','l','e','D','a','t','a',' '}; + register_header_check(0, fbk_header, sizeof(fbk_header), &header_check_fbk, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fcp.c b/subprojects/lib/src/file_fcp.c new file mode 100644 index 0000000..5354aec --- /dev/null +++ b/subprojects/lib/src/file_fcp.c @@ -0,0 +1,69 @@ +/* + + File: file_fcp.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fcp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fcp(file_stat_t *file_stat); + +const file_hint_t file_hint_fcp= { + .extension="fcp", + .description="Final Cut Pro", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fcp +}; + +/* + Final Cut Pro is a professional non-linear editing system + developed by Apple Inc. + Mac Creator code: KeyG +*/ + +/*@ + @ requires separation: \separated(&file_hint_fcp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fcp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fcp.extension; + return 1; +} + +static void register_header_check_fcp(file_stat_t *file_stat) +{ + static const unsigned char fcp_header[5]= { 0xA2, 'K','e','y','G'}; + register_header_check(0, fcp_header,sizeof(fcp_header), &header_check_fcp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fcs.c b/subprojects/lib/src/file_fcs.c new file mode 100644 index 0000000..4249574 --- /dev/null +++ b/subprojects/lib/src/file_fcs.c @@ -0,0 +1,202 @@ +/* + + File: file_fcs.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fcs) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_fcs(file_stat_t *file_stat); + +const file_hint_t file_hint_fcs= { + .extension="fcs", + .description="Flow Cytometry Standard 3.0", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fcs +}; + +struct fcs_header +{ + unsigned char magic[6]; + unsigned char reserved[4]; + unsigned char text_start[8]; /* 10 */ + unsigned char text_end[8]; /* 18 */ + unsigned char data_start[8]; /* 26 */ + unsigned char data_end[8]; /* 34 */ + unsigned char analysis_start[8]; /* 34 */ + unsigned char analysis_end[8]; /* 50 */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(string + (0 .. max_length-1)); + @ assigns \nothing; + @*/ +static uint64_t ascii2int(const unsigned char *string, const unsigned int max_length) +{ + uint64_t res=0; + unsigned int i; + /*@ + @ loop invariant res <= 0x1999999999999998; + @ loop assigns res,i; + @*/ + for(i=0;i='0' && string[i]<='9') + { + res=res*10+(string[i]-'0'); + if(res > 0x1999999999999998) + return 0xffffffffffffffff; + } + else if(!(string[i]==' ' && res==0)) + return 0; + } + return res; +} + +/*@ + @ requires \valid_read(string + (0 .. max_length-1)); + @ assigns \nothing; + @*/ +static uint64_t ascii2int2(const unsigned char *string, const unsigned int max_length, const unsigned int delimiter) +{ + uint64_t res=0; + unsigned int i; + /*@ + @ loop invariant res <= 0x1999999999999998; + @ loop assigns res,i; + @*/ + for(i=0;i='0' && string[i]<='9') + { + res=res*10+(string[i]-'0'); + if(res > 0x1999999999999998) + return res; + } + else if(string[i]==delimiter) + return res; + else if(string[i]==' ' && res>0) + return res; + else if(string[i]!=' ') + return 0; + } + return res; +} + +/*@ + @ requires buffer_size >= sizeof(struct fcs_header); + @ requires separation: \separated(&file_hint_fcs, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result != 0) ==> file_recovery_new->extension != \null; + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 58); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_fcs.extension); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ assigns *file_recovery_new; + @*/ +static int header_check_fcs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct fcs_header *fcs=(const struct fcs_header*)buffer; + uint64_t text_start; + uint64_t text_end; + uint64_t data_start; + uint64_t data_end; + uint64_t analysis_start; + uint64_t analysis_end; + uint64_t stext_end=0; + text_start=ascii2int(fcs->text_start, 8); + text_end=ascii2int(fcs->text_end, 8); + data_start=ascii2int(fcs->data_start, 8); + data_end=ascii2int(fcs->data_end, 8); + analysis_start=ascii2int(fcs->analysis_start, 8); + analysis_end=ascii2int(fcs->analysis_end, 8); + if(!(text_start<=text_end && data_start<=data_end && analysis_start<=analysis_end)) + return 0; + if((data_end==0 || analysis_end==0) && text_start < buffer_size) + { /* Explore TEXT segment */ + unsigned int i; + const unsigned char delimiter=buffer[text_start]; + const unsigned int smallest=(buffer_size < text_end ? buffer_size : text_end); + /*@ + @ loop assigns i, data_end, stext_end, analysis_end; + @*/ + for(i=0; i= 0x8000000000000000 - 9 || + analysis_end >= 0x8000000000000000 - 9 || + stext_end >= 0x8000000000000000 - 9) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fcs.extension; + file_recovery_new->min_filesize=58; + file_recovery_new->calculated_file_size=data_end+9; + if(file_recovery_new->calculated_file_size < analysis_end+9) + file_recovery_new->calculated_file_size=analysis_end+9; + if(file_recovery_new->calculated_file_size < stext_end+9) + file_recovery_new->calculated_file_size=stext_end+9; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_fcs(file_stat_t *file_stat) +{ + static const unsigned char fcs_signature[6]= {'F','C','S','3','.','0'}; + register_header_check(0, fcs_signature, sizeof(fcs_signature), &header_check_fcs, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fdb.c b/subprojects/lib/src/file_fdb.c new file mode 100644 index 0000000..0e17f70 --- /dev/null +++ b/subprojects/lib/src/file_fdb.c @@ -0,0 +1,69 @@ +/* + + File: file_fdb.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fdb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fdb(file_stat_t *file_stat); + +const file_hint_t file_hint_fdb= { + .extension="fdb", + .description="Microsoft Dynamics NAV (MS Navision)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fdb +}; + +/*@ + @ requires separation: \separated(&file_hint_fdb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fdb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_fdb) + { + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fdb.extension; + return 1; +} + +static void register_header_check_fdb(file_stat_t *file_stat) +{ + static const unsigned char fdb_header[7] = { 0x00, 0x00, 0x00, 0x5c, 0xa0, 0x83, 0x02}; + register_header_check(5, fdb_header, sizeof(fdb_header), &header_check_fdb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fds.c b/subprojects/lib/src/file_fds.c new file mode 100644 index 0000000..50c2390 --- /dev/null +++ b/subprojects/lib/src/file_fds.c @@ -0,0 +1,77 @@ +/* + + File: file_nes.c + + Copyright (C) 2013 James Holodnak + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fds) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fds(file_stat_t *file_stat); + +const file_hint_t file_hint_fds= { + .extension="fds", + .description="fwNES Disk Image (with header)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_fds +}; + +struct fds_header +{ + char ident[4]; + uint8_t numsides; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires separation: \separated(&file_hint_fds, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fds(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct fds_header *bm=(const struct fds_header *)buffer; + const uint64_t size=16+bm->numsides*65500; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fds.extension; + file_recovery_new->min_filesize=16; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_fds(file_stat_t *file_stat) +{ + static const unsigned char fds_header[4]= {'F','D','S',0x1A}; + register_header_check(0, fds_header,sizeof(fds_header), &header_check_fds, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fh10.c b/subprojects/lib/src/file_fh10.c new file mode 100644 index 0000000..3fae265 --- /dev/null +++ b/subprojects/lib/src/file_fh10.c @@ -0,0 +1,75 @@ +/* + + File: file_fh10.c + + Copyright (C) 2007 Christophe GRENIER + Copyright (C) 2007 Peter Turczak + + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fh10) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fh10(file_stat_t *file_stat); + +const file_hint_t file_hint_fh10= { + .extension="fh10", + .description="Macromedia Freehand 10", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fh10 +}; + +/*@ + @ requires separation: \separated(&file_hint_fh10, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fh10(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=4096; +#ifdef DJGPP + file_recovery_new->extension="fh1"; +#else + file_recovery_new->extension=file_hint_fh10.extension; +#endif + return 1; +} + +static void register_header_check_fh10(file_stat_t *file_stat) +{ + static const unsigned char fh10_header[] = { + 0x1c, 0x01 ,0x00, 0x00, 0x02, 0x00, 0x04, 0x1c, 0x01 , 0x14, 0x00, 0x02, 0x00, 0x14, 0x1c, 0x01, + 0x16, 0x00 ,0x02, 0x00, 0x08, 0x1c, 0x01, 0x1e, 0x00 , 0xa , 0x46, 0x72, 0x65, 0x65, 0x48, 0x61, + 0x6e, 0x64, 0x31, 0x30 + }; + register_header_check(0, fh10_header,sizeof(fh10_header), &header_check_fh10, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fh5.c b/subprojects/lib/src/file_fh5.c new file mode 100644 index 0000000..8484ef3 --- /dev/null +++ b/subprojects/lib/src/file_fh5.c @@ -0,0 +1,95 @@ +/* + + File: file_fh5.c + + Copyright (C) 2007 Christophe GRENIER + Copyright (C) 2007 Peter Turczak + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fh5) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +struct fh5_header_s +{ + unsigned char id[8]; + uint32_t datalen; /* Big Endian size w/o headers */ +} __attribute__ ((gcc_struct, __packed__)); +typedef struct fh5_header_s fh5_header_t; + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fh5(file_stat_t *file_stat); + +const file_hint_t file_hint_fh5= { + .extension="fh5", + .description="Macromedia Freehand 5", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fh5 +}; + +/*@ + @ requires file_recovery->file_check == &file_check_fh5; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +static void file_check_fh5(file_recovery_t *file_recovery) +{ + if(file_recovery->file_size < file_recovery->calculated_file_size) + file_recovery->file_size=0; + else if(file_recovery->file_size> file_recovery->calculated_file_size+4096) + file_recovery->file_size=file_recovery->calculated_file_size+4096; +} + +/*@ + @ requires buffer_size >= sizeof(fh5_header_t); + @ requires separation: \separated(&file_hint_fh5, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fh5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const fh5_header_t *fh5_buffer=(const fh5_header_t *) buffer; + const unsigned int datalen=be32(fh5_buffer->datalen); + if(datalen < sizeof(struct fh5_header_s)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=4096; + file_recovery_new->calculated_file_size=datalen; + file_recovery_new->extension=file_hint_fh5.extension; + file_recovery_new->file_check=&file_check_fh5; + return 1; +} + +static void register_header_check_fh5(file_stat_t *file_stat) +{ + static const unsigned char fh5_header[8] = { 0x41, 0x47, 0x44, 0x31, 0xbe, 0xb8, 0xbb, 0xce }; + register_header_check(0, fh5_header,sizeof(fh5_header), &header_check_fh5, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_filevault.c b/subprojects/lib/src/file_filevault.c new file mode 100644 index 0000000..84907dc --- /dev/null +++ b/subprojects/lib/src/file_filevault.c @@ -0,0 +1,70 @@ +/* + + File: file_filevault.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_filevault) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_filevault(file_stat_t *file_stat); + +const file_hint_t file_hint_filevault= { + .extension="sparseimage", + .description="Filevault", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_filevault +}; + +/*@ + @ requires separation: \separated(&file_hint_filevault, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_filevault(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="img"; +#else + file_recovery_new->extension=file_hint_filevault.extension; +#endif + return 1; +} + +static void register_header_check_filevault(file_stat_t *file_stat) +{ + static const unsigned char filevault_header[8]= { + 'e', 'n', 'c', 'r', 'c', 'd', 's', 'a' + }; + register_header_check(0, filevault_header, sizeof(filevault_header), &header_check_filevault, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fit.c b/subprojects/lib/src/file_fit.c new file mode 100644 index 0000000..7efe407 --- /dev/null +++ b/subprojects/lib/src/file_fit.c @@ -0,0 +1,85 @@ +/* + + File: file_fit.c + + Copyright (C) 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either profile_version 2 of the License, or + (at your option) any later profile_version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fit ) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fit(file_stat_t *file_stat); + +const file_hint_t file_hint_fit = { + .extension="fit", + .description="Flexible & Interoperable Data Transfer / Garmin track file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fit +}; + +struct fits_header +{ + unsigned char header_size; + unsigned char protocol_version; + uint16_t profile_version; + uint32_t data_size; + char signature[4]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct fits_header); + @ requires separation: \separated(&file_hint_fit, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fit(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct fits_header* h = (const struct fits_header *)buffer; + if (h->header_size < 12) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_fit.extension; + file_recovery_new->min_filesize = 12; + file_recovery_new->calculated_file_size=(uint64_t)le32(h->data_size) + h->header_size; + if(h->header_size >= 14) + file_recovery_new->calculated_file_size+=2; /* CRC at the end of the file */ + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_fit(file_stat_t *file_stat) +{ + static const unsigned char fits_header[4]= { '.', 'F', 'I', 'T' }; + register_header_check(8, fits_header, sizeof(fits_header), &header_check_fit, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fits.c b/subprojects/lib/src/file_fits.c new file mode 100644 index 0000000..e4b2763 --- /dev/null +++ b/subprojects/lib/src/file_fits.c @@ -0,0 +1,247 @@ +/* + + File: file_fits.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fits) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#ifdef DEBUG_FITS +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fits(file_stat_t *file_stat); + +const file_hint_t file_hint_fits= { + .extension="fits", + .description="Flexible Image Transport System", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fits +}; + +/* FITS is the standard data format used in astronomy, it's also used in quantic physics + * Image metadata is store in an ASCII header + * Specification can be found at http://fits.gsfc.nasa.gov/ */ + +/*@ + @ requires \valid_read(str + (0 .. 80-1)); + @ assigns \nothing; + @*/ +static uint64_t fits_get_val(const unsigned char *str) +{ + unsigned int i; + uint64_t val=0; + /*@ loop assigns i; */ + for(i=0;i<80 && str[i]!='=';i++); + i++; + /*@ loop assigns i; */ + for(;i<80 && str[i]==' ';i++); + if(i<80 && str[i]=='-') + i++; + /*@ + @ loop invariant val < PHOTOREC_MAX_FILE_SIZE; + @ loop assigns i,val; + @*/ + for(;i<80 && str[i]>='0' && str[i]<='9';i++) + { + val=val*10+(str[i]-'0'); + if(val >= PHOTOREC_MAX_FILE_SIZE) + return val; + } + return val; +} + +/*@ + @ requires buffer_size > 0; + @ requires \valid_read(buffer + (0 .. buffer_size-1)); + @ requires \valid(file_recovery); + @ requires \valid(i_pointer); + @ requires \separated(buffer+(..), file_recovery, i_pointer); + @ requires *i_pointer < buffer_size; + @ assigns *i_pointer, file_recovery->time; + @ ensures \old(*i_pointer) == *i_pointer || (\old(*i_pointer) <= *i_pointer < buffer_size + 80); + @*/ +static uint64_t fits_info(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery, unsigned int *i_pointer) +{ + uint64_t naxis_size=1; + unsigned int i=*i_pointer; + if( i+80 >= buffer_size) + return 1; + /*@ assert *i_pointer == i; */ + /* Header is composed of 80 character fixed-length strings */ + /*@ + @ loop invariant *i_pointer <= i; + @ loop invariant i < buffer_size + 80; + @ loop assigns i, naxis_size, file_recovery->time; + @ loop variant buffer_size + 80 - i; + @*/ + for(; i+80 < buffer_size && + memcmp(&buffer[i], "END ", 4)!=0; + i+=80) + { + if(naxis_size > PHOTOREC_MAX_FILE_SIZE) + naxis_size=0; + /*@ assert naxis_size <= PHOTOREC_MAX_FILE_SIZE; */ + if(memcmp(&buffer[i], "BITPIX",6)==0) + { + const uint64_t tmp=fits_get_val(&buffer[i]); + if(tmp > PHOTOREC_MAX_FILE_SIZE) + naxis_size=0; + else if(tmp>0) + { /* FIXME overflow */ + naxis_size*=(tmp+8-1)/8; + } + } + else if(memcmp(&buffer[i], "NAXIS ",6)==0) + { + /* NAXIS - range [0:999] */ + if(fits_get_val(&buffer[i])==0) + naxis_size=0; + } + else if(memcmp(&buffer[i], "NAXIS",5)==0) + { + /* NAXISn */ + const uint64_t naxis_val=fits_get_val(&buffer[i]); + if(naxis_val > PHOTOREC_MAX_FILE_SIZE) + naxis_size=0; + else + { /* FIXME overflow */ + naxis_size*=naxis_val; + } + } + else if(memcmp(&buffer[i], "CREA_DAT=", 9)==0) + { + /* CREA_DAT= '2007-08-29T16:22:09' */ + /* 0123456789012345678 */ + unsigned int j; + /*@ + @ loop assigns j; + @*/ + for(j=0;j<80 && buffer[i+j]!='\'';j++); + if(j<60 && buffer[i+j]=='\'') + { + file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[i+j+1]); + } + } + } + /*@ assert *i_pointer <= i < buffer_size + 80; */ + *i_pointer=i; + return naxis_size; +} + +/*@ + @ requires file_recovery->data_check==&data_check_fits; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->time; + @*/ +static data_check_t data_check_fits(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size, file_recovery->time; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + /*@ assert \valid_read(&buffer[i] + (0 .. 8-1)); */ + if(memcmp(&buffer[i], "XTENSION", 8)!=0) + break; + { + unsigned int new_i=i; + /*@ assert i==new_i; */ + const uint64_t tmp=fits_info(buffer, buffer_size, file_recovery, &new_i); + /*@ assert (i==new_i && i < buffer_size - 8) || (i <= new_i < buffer_size + 80); */ + /*@ assert i<=new_i; */ + const unsigned int diff=new_i-i; +#ifdef DEBUG_FITS + log_info("data_check_fits cfr=%llu fs=%llu i=%u buffer_size=%u\n", + (long long unsigned)file_recovery->calculated_file_size, + (long long unsigned)file_recovery->file_size, + new_i, buffer_size); +#endif + if(tmp==0) + { + file_recovery->data_check=NULL; + file_recovery->file_check=NULL; + return DC_CONTINUE; + } + /*@ assert diff < buffer_size + 80; */ + file_recovery->calculated_file_size+=(uint64_t)(diff+2880-1)/2880*2880+(tmp+2880-1)/2880*2880; + } + } + if(file_recovery->file_size + buffer_size/2 >= file_recovery->calculated_file_size) + return DC_STOP; + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_fits, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fits(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i=0; + uint64_t naxis_size_max=0; + if(file_recovery_new->blocksize >= 80) + naxis_size_max=fits_info(buffer, buffer_size, file_recovery_new, &i); + if(naxis_size_max > PHOTOREC_MAX_FILE_SIZE) + return 0; + if(naxis_size_max !=0 && naxis_size_max < 2880) + return 0; + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="fts"; +#else + file_recovery_new->extension=file_hint_fits.extension; +#endif + file_recovery_new->min_filesize=2880; + if(naxis_size_max==0) + return 1; + /* File is composed of several 2880-bytes blocks */ + file_recovery_new->data_check=&data_check_fits; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=(i+2880-1)/2880*2880+(naxis_size_max+2880-1)/2880*2880; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +static void register_header_check_fits(file_stat_t *file_stat) +{ + register_header_check(0, "SIMPLE =", 9, &header_check_fits, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_flac.c b/subprojects/lib/src/file_flac.c new file mode 100644 index 0000000..2abef69 --- /dev/null +++ b/subprojects/lib/src/file_flac.c @@ -0,0 +1,118 @@ +/* + + File: file_flac.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flac) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_flac(file_stat_t *file_stat); + +const file_hint_t file_hint_flac= { + .extension="flac", + .description="FLAC audio", + .max_filesize=(uint64_t)1500*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_flac +}; + +/* https://xiph.org/flac/format.html */ + +/*@ + @ requires file_recovery->data_check==&data_check_flac_metadata; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->data_check; + @*/ +static data_check_t data_check_flac_metadata(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size, file_recovery->data_check; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4; */ + const uint32_t *p32=(const uint32_t *)&buffer[i]; + const uint32_t size=be32(*p32)&0x00ffffff; +#ifdef DEBUG_FLAC + log_info("data_check_flac_metadata calculated_file_size=0x%llx: 0x%02x\n", + (long long unsigned)file_recovery->calculated_file_size, buffer[i]); +#endif + if((buffer[i]&0x7f)==0x7f) + return DC_ERROR; + file_recovery->calculated_file_size+=(uint64_t)4+size; + if((buffer[i]&0x80)==0x80) + { + file_recovery->data_check=NULL; + return DC_CONTINUE; + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_flac, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_flac(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint32_t *p32=(const uint32_t *)&buffer[4]; + const uint32_t size=be32(*p32)&0x00ffffff; + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="flc"; +#else + file_recovery_new->extension=file_hint_flac.extension; +#endif + file_recovery_new->min_filesize=4+size; + if(file_recovery_new->blocksize >= 4) + { + file_recovery_new->calculated_file_size=4; + file_recovery_new->data_check=&data_check_flac_metadata; + } + return 1; +} + +static void register_header_check_flac(file_stat_t *file_stat) +{ + /* Stream marker followed by STREAMINFO Metadata block */ + static const unsigned char flac_header[5]= {'f', 'L', 'a', 'C', 0x00}; + static const unsigned char flac_header2[5]= {'f', 'L', 'a', 'C', 0x80}; + register_header_check(0, flac_header,sizeof(flac_header), &header_check_flac, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, flac_header2,sizeof(flac_header2), &header_check_flac, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_flp.c b/subprojects/lib/src/file_flp.c new file mode 100644 index 0000000..0ff83bb --- /dev/null +++ b/subprojects/lib/src/file_flp.c @@ -0,0 +1,88 @@ +/* + + File: file_flp.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_flp(file_stat_t *file_stat); + +const file_hint_t file_hint_flp= { + .extension="flp", + .description="Fruity Loop", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_flp +}; + +struct flp_header +{ + char magic[4]; + uint32_t len; /* = 6 */ + uint16_t format; + uint16_t tracks; + int16_t time_division; + char magic2[4]; + uint32_t len2; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >=sizeof(struct flp_header); + @ requires separation: \separated(&file_hint_flp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_flp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct flp_header *hdr=(const struct flp_header *)buffer; + const unsigned int len2=le32(hdr->len2); + if(strncmp(hdr->magic2, "FLdt", 4)!=0) + return 0; + if(len2==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_flp.extension; + file_recovery_new->calculated_file_size=(uint64_t)len2 + 0x16; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/* File format is similar to a midi file. + * It begins by a header chunk and is followed by a single track chunk */ +static void register_header_check_flp(file_stat_t *file_stat) +{ + static const unsigned char flp_header[8]= {'F', 'L', 'h', 'd', 0x06, 0x00, 0x00, 0x00}; + register_header_check(0, flp_header,sizeof(flp_header), &header_check_flp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_flv.c b/subprojects/lib/src/file_flv.c new file mode 100644 index 0000000..e74308a --- /dev/null +++ b/subprojects/lib/src/file_flv.c @@ -0,0 +1,136 @@ +/* + + File: file_flv.c + + Copyright (C) 2007,2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_flv(file_stat_t *file_stat); + +const file_hint_t file_hint_flv= { + .extension="flv", + .description="Macromedia", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_flv +}; + +struct flv_header +{ + char signature[3]; + uint8_t version; + uint8_t type_flags; + uint32_t data_offset; +} __attribute__ ((gcc_struct, __packed__)); + +struct flv_tag +{ + uint32_t prev_tag_size; + uint8_t info; + uint8_t data_size[3]; + uint8_t timestamp[3]; + uint8_t timestamp_ext; + uint8_t streamID[3]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_flv; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->data_check_tmp; + @*/ +static data_check_t data_check_flv(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size, file_recovery->data_check_tmp; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 15 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 15; */ + const struct flv_tag *tag=(const struct flv_tag *)&buffer[i]; + /*@ assert \valid_read(tag); */ +#ifdef DEBUG_FLV + log_info("cfs=0x%llx file_recovery->data_check_tmp=%u\n", (long long unsigned)file_recovery->calculated_file_size, file_recovery->data_check_tmp); +#endif + if((be32(tag->prev_tag_size)==0 && file_recovery->calculated_file_size < buffer_size/2) || + be32(tag->prev_tag_size)==11+file_recovery->data_check_tmp) + { + file_recovery->data_check_tmp=(tag->data_size[0]<<16) | (tag->data_size[1]<<8) | tag->data_size[2]; + if((tag->info&0xc0)!=0 || file_recovery->data_check_tmp==0 + || tag->streamID[0]!=0 || tag->streamID[1]!=0 || tag->streamID[2]!=0 ) + { + file_recovery->calculated_file_size+=4; + return DC_STOP; + } + /* 4+11=15*/ + file_recovery->calculated_file_size+=(uint64_t)15+file_recovery->data_check_tmp; + } + else + return DC_ERROR; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct flv_header); + @ requires separation: \separated(&file_hint_flv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_flv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct flv_header *flv=(const struct flv_header *)buffer; + const unsigned int data_offset=be32(flv->data_offset); + if((flv->type_flags & 0xfa)==0 && data_offset>=9) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_flv.extension; + if(file_recovery_new->blocksize < 15) + return 1; + file_recovery_new->calculated_file_size=data_offset; + file_recovery_new->data_check=&data_check_flv; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_flv(file_stat_t *file_stat) +{ + static const unsigned char flv_header[4]= {'F', 'L', 'V', 0x01}; + register_header_check(0, flv_header,sizeof(flv_header), &header_check_flv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fm.c b/subprojects/lib/src/file_fm.c new file mode 100644 index 0000000..f103ee9 --- /dev/null +++ b/subprojects/lib/src/file_fm.c @@ -0,0 +1,82 @@ +/* + + File: file_fm.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fm(file_stat_t *file_stat); + +const file_hint_t file_hint_fm= { + .extension="fm", + .description="Football Manager", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fm +}; + +struct fm_header +{ + char magic[9]; + uint64_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct fm_header); + @ requires separation: \separated(&file_hint_fm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct fm_header *hdr=(const struct fm_header *)buffer; + const uint64_t size=le64(hdr->size); + if(size > PHOTOREC_MAX_FILE_SIZE) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fm.extension; + file_recovery_new->calculated_file_size=size + 12833; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_fm(file_stat_t *file_stat) +{ + static const unsigned char fm_header[9]= { + 0x02, 0x01, 'f' , 'm' , 'f' , '.' , 0x07, 0x00, + 0x00 + }; + register_header_check(0, fm_header, sizeof(fm_header), &header_check_fm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fob.c b/subprojects/lib/src/file_fob.c new file mode 100644 index 0000000..99f2e8a --- /dev/null +++ b/subprojects/lib/src/file_fob.c @@ -0,0 +1,85 @@ +/* + + File: file_fob.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fob) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "memmem.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fob(file_stat_t *file_stat); + +const file_hint_t file_hint_fob= { + .extension="fob", + .description="Microsoft Dynamics NAV (MS Navision)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fob +}; + +/*@ + @ requires separation: \separated(&file_hint_fob, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fob(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char sign_navnl[5] = {'N','A','V','N','L'}; + static const unsigned char sign_navw[4] = {'N','A','V','W'}; + const char *sbuffer=(const char *)buffer; + unsigned int tmp=0; + const char *pos1=(const char *)td_memmem(buffer, buffer_size, sign_navnl, sizeof(sign_navnl)); + const char *pos2=(const char *)td_memmem(buffer, buffer_size, sign_navw, sizeof(sign_navw)); + if(pos1==NULL && pos2==NULL) + return 0; + if(pos1!=NULL) + tmp=pos1-sbuffer; + if(pos2!=NULL && pos2-sbuffer > tmp) + tmp=pos2-sbuffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fob.extension; + file_recovery_new->min_filesize=tmp; + return 1; +} + +static void register_header_check_fob(file_stat_t *file_stat) +{ + register_header_check(0, "Codeunit ", 9, &header_check_fob, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, "Dataport ", 9, &header_check_fob, file_stat); + register_header_check(0, "Form ", 5, &header_check_fob, file_stat); + register_header_check(0, "MenuSuite ", 10, &header_check_fob, file_stat); + register_header_check(0, "Report ", 7, &header_check_fob, file_stat); + register_header_check(0, "Table ", 6, &header_check_fob, file_stat); + register_header_check(0, "XMLport ", 8, &header_check_fob, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_fos.c b/subprojects/lib/src/file_fos.c new file mode 100644 index 0000000..14ca470 --- /dev/null +++ b/subprojects/lib/src/file_fos.c @@ -0,0 +1,64 @@ +/* + + File: file_fos.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fos) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fos(file_stat_t *file_stat); + +const file_hint_t file_hint_fos= { + .extension="fos", + .description="Fallout 4 Savegame", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fos +}; + +/*@ + @ requires separation: \separated(&file_hint_fos, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fos(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fos.extension; + file_recovery_new->min_filesize=0x10; + return 1; +} + +static void register_header_check_fos(file_stat_t *file_stat) +{ + register_header_check(0, "FO4_SAVEGAME", 11, &header_check_fos, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_found.c b/subprojects/lib/src/file_found.c new file mode 100644 index 0000000..72964b3 --- /dev/null +++ b/subprojects/lib/src/file_found.c @@ -0,0 +1,69 @@ +/* + + File: file_found.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "intrf.h" +#ifdef HAVE_NCURSES +#include "intrfn.h" +#endif +#include "dir.h" +#include "list.h" +#include "lang.h" +#include "filegen.h" +#include "file_found.h" + +alloc_data_t *file_found(alloc_data_t *current_search_space, const uint64_t offset, file_stat_t *file_stat) +{ + if(current_search_space==NULL) + return current_search_space; + if(current_search_space->start == offset) + { + current_search_space->file_stat=file_stat; + current_search_space->data=1; + return current_search_space; + } + if(current_search_space->start < offset && offset <= current_search_space->end) + { + alloc_data_t *next_search_space; + next_search_space=(alloc_data_t*)MALLOC(sizeof(*next_search_space)); + memcpy(next_search_space, current_search_space, sizeof(*next_search_space)); + current_search_space->end=offset-1; + next_search_space->start=offset; + next_search_space->file_stat=file_stat; + next_search_space->data=1; + td_list_add(&next_search_space->list, ¤t_search_space->list); + return next_search_space; + } + return current_search_space; +} diff --git a/subprojects/lib/src/file_found.h b/subprojects/lib/src/file_found.h new file mode 100644 index 0000000..9607c40 --- /dev/null +++ b/subprojects/lib/src/file_found.h @@ -0,0 +1,38 @@ +/* + + File: file_found.h + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_FOUND_H +#define _FILE_FOUND_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires \valid(current_search_space); + @ requires \valid(file_stat); + @ requires \separated(current_search_space, file_stat); + @*/ +alloc_data_t *file_found(alloc_data_t *current_search_space, const uint64_t offset, file_stat_t *file_stat); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_fp5.c b/subprojects/lib/src/file_fp5.c new file mode 100644 index 0000000..0da4079 --- /dev/null +++ b/subprojects/lib/src/file_fp5.c @@ -0,0 +1,66 @@ +/* + + File: file_fp5.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fp5) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fp5(file_stat_t *file_stat); + +const file_hint_t file_hint_fp5= { + .extension="fp5", + .description="File Maker Pro", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fp5 +}; + +/*@ + @ requires separation: \separated(&file_hint_fp5, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fp5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fp5.extension; + return 1; +} + +static void register_header_check_fp5(file_stat_t *file_stat) +{ + static const unsigned char fp5_header[0x10]= { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0xc0, 0x00 + }; + register_header_check(0, fp5_header,sizeof(fp5_header), &header_check_fp5, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fp7.c b/subprojects/lib/src/file_fp7.c new file mode 100644 index 0000000..d009d82 --- /dev/null +++ b/subprojects/lib/src/file_fp7.c @@ -0,0 +1,84 @@ +/* + + File: file_fp7.c + + Copyright (C) 2009,2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fp7) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fp7(file_stat_t *file_stat); + +const file_hint_t file_hint_fp7= { + .extension="fp7", + .description="File Maker Pro", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fp7 +}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +static void file_check_fp7(file_recovery_t *file_recovery) +{ + file_recovery->file_size=file_recovery->file_size/4096*4096; +} + +/*@ + @ requires separation: \separated(&file_hint_fp7, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fp7(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer_size < 0x230 || memcmp(&buffer[0x20d], "HBAM", 4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=4096; + file_recovery_new->file_check=&file_check_fp7; + if(memcmp(&buffer[0x21e], "Pro 12", 6)==0) + file_recovery_new->extension="fmp12"; + else + file_recovery_new->extension=file_hint_fp7.extension; + return 1; +} + +static void register_header_check_fp7(file_stat_t *file_stat) +{ + static const unsigned char fp7_header[0x14]= { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x05, 0x00, 0x02, 0x00, 0x02, 0xc0, 'H', + 'B', 'A', 'M', '7' + }; + register_header_check(0, fp7_header,sizeof(fp7_header), &header_check_fp7, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_freeway.c b/subprojects/lib/src/file_freeway.c new file mode 100644 index 0000000..815c4fb --- /dev/null +++ b/subprojects/lib/src/file_freeway.c @@ -0,0 +1,67 @@ +/* + + File: file_freeway.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_freeway) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_freeway(file_stat_t *file_stat); + +const file_hint_t file_hint_freeway= { + .extension="freeway", + .description="Freeway 5 Pro", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_freeway +}; + +/*@ + @ requires separation: \separated(&file_hint_freeway, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_freeway(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_freeway.extension; + return 1; +} + +static void register_header_check_freeway(file_stat_t *file_stat) +{ + static const unsigned char freeway_header[0x10]= { + 0x13, 'F' , 'r' , 'e' , 'e' , 'w' , 'a' , 'y' , + ' ' , '5' , ' ' , 'P' , 'r' , 'o' , ' ' , '5' , + }; + register_header_check(0x10, freeway_header, sizeof(freeway_header), &header_check_freeway, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_frm.c b/subprojects/lib/src/file_frm.c new file mode 100644 index 0000000..e9e24bd --- /dev/null +++ b/subprojects/lib/src/file_frm.c @@ -0,0 +1,86 @@ +/* + + File: file_frm.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_frm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_frm(file_stat_t *file_stat); + +const file_hint_t file_hint_frm= { + .extension="frm", + .description="Pro/ENGINEER Drawing Form", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_frm +}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_frm(file_recovery_t *file_recovery) +{ + const unsigned char frm_footer[11]= { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C'}; + file_search_footer(file_recovery, frm_footer, sizeof(frm_footer), 1); +} + +/*@ + @ requires buffer_size >= 18; + @ requires separation: \separated(&file_hint_frm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_frm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[14]) || !isprint(buffer[15]) || !isprint(buffer[16]) || !isprint(buffer[17])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_frm; + file_recovery_new->extension=file_hint_frm.extension; + return 1; +} + +static void register_header_check_frm(file_stat_t *file_stat) +{ + static const unsigned char frm_header[14]= { + '#', 'U', 'G', 'C', ':', '2', ' ', 'D', + 'W', 'G', 'F', 'O', 'R', 'M'}; + register_header_check(0, frm_header,sizeof(frm_header), &header_check_frm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fs.c b/subprojects/lib/src/file_fs.c new file mode 100644 index 0000000..5f5647d --- /dev/null +++ b/subprojects/lib/src/file_fs.c @@ -0,0 +1,125 @@ +/* + + File: file_fs.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fs) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fs(file_stat_t *file_stat); + +const file_hint_t file_hint_fs= { + .extension="fs", + .description="Zope", + .max_filesize=200*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fs +}; + +/* See http://www.linkitsolutions.org/uploader/dilu/lib/python2.6/site-packages/ZODB/FileStorage/FileStorage.py for more information */ +struct transaction_header +{ + uint64_t id; + uint64_t len; + char status; + uint16_t len_username; + uint16_t len_descr; + uint16_t len_ext; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_fs; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_fs(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x11 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x11; */ + const struct transaction_header *hdr=(const struct transaction_header *)&buffer[i]; + const uint64_t len=be64(hdr->len); + if(len < sizeof(struct transaction_header)-8) + return DC_STOP; + if(hdr->status!=' ' && hdr->status!='p' && hdr->status!='c' && hdr->status!='u') + return DC_STOP; + if(len > PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; +#ifdef DEBUG_FS + log_info("0x%08llx len=%llu status=%c\n", (long long unsigned)file_recovery->calculated_file_size, (long long unsigned)len, hdr->status); +#endif + file_recovery->calculated_file_size+=(uint64_t)8+len; +#ifdef DEBUG_FS + log_info("0x%08llx\n", (long long unsigned)file_recovery->calculated_file_size); +#endif + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct transaction_header); + @ requires separation: \separated(&file_hint_fs, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct transaction_header *hdr=(const struct transaction_header *)&buffer[4]; + const uint64_t len=be64(hdr->len); + if(len < sizeof(struct transaction_header)-8) + return 0; + if(hdr->status!=' ' && hdr->status!='p' && hdr->status!='c' && hdr->status!='u') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fs.extension; + if(file_recovery_new->blocksize < 0x11) + return 1; + file_recovery_new->data_check=&data_check_fs; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=4; + return 1; +} + +static void register_header_check_fs(file_stat_t *file_stat) +{ + static const unsigned char fs_header[4]={ 'F', 'S','2','1' }; + register_header_check(0, fs_header,sizeof(fs_header), &header_check_fs, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_fwd.c b/subprojects/lib/src/file_fwd.c new file mode 100644 index 0000000..f629564 --- /dev/null +++ b/subprojects/lib/src/file_fwd.c @@ -0,0 +1,63 @@ +/* + + File: file_fwd.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fwd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fwd(file_stat_t *file_stat); + +const file_hint_t file_hint_fwd= { + .extension="fwd", + .description="FRWD Sports Computer", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fwd +}; + +/*@ + @ requires separation: \separated(&file_hint_fwd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_fwd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_fwd.extension; + return 1; +} + +static void register_header_check_fwd(file_stat_t *file_stat) +{ + register_header_check(0, "FRWD0120", 8, &header_check_fwd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gam.c b/subprojects/lib/src/file_gam.c new file mode 100644 index 0000000..6f30355 --- /dev/null +++ b/subprojects/lib/src/file_gam.c @@ -0,0 +1,66 @@ +/* + + File: file_gam.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gam) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gam(file_stat_t *file_stat); + +const file_hint_t file_hint_gam= { + .extension="gam", + .description="Games Factory", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gam +}; + +/*@ + @ requires separation: \separated(&file_hint_gam, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gam(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gam.extension; + return 1; +} + +static void register_header_check_gam(file_stat_t *file_stat) +{ + static const unsigned char gam_header[6]= { + 'G' , 'A' , 'P' , 'P' , 0x07, 0x02 + }; + register_header_check(0, gam_header, sizeof(gam_header), &header_check_gam, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gct.c b/subprojects/lib/src/file_gct.c new file mode 100644 index 0000000..6159791 --- /dev/null +++ b/subprojects/lib/src/file_gct.c @@ -0,0 +1,70 @@ +/* + + File: file_gct.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gct) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gct(file_stat_t *file_stat); + +const file_hint_t file_hint_gct= { + .extension="gct", + .description="XFI Electronic Fuel Injection Systems", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gct +}; + +/*@ + @ requires separation: \separated(&file_hint_gct, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gct(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gct.extension; + file_recovery_new->calculated_file_size=2416; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_gct(file_stat_t *file_stat) +{ + static const unsigned char gct_header[9]= { + 'J' , 'L' , 'G' , 'E' , 'N' , '2' , 'X' , 'F' , + 'I' + }; + register_header_check(0, gct_header, sizeof(gct_header), &header_check_gct, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gho.c b/subprojects/lib/src/file_gho.c new file mode 100644 index 0000000..1557fd2 --- /dev/null +++ b/subprojects/lib/src/file_gho.c @@ -0,0 +1,68 @@ +/* + + File: file_gho.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gho) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gho(file_stat_t *file_stat); + +const file_hint_t file_hint_gho= { + .extension="gho", + .description="Ghost", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gho +}; + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_gho, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ghost(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char gho_header_next[8]= { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if(memcmp (buffer+8, gho_header_next, sizeof(gho_header_next))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gho.extension; + return 1; +} + +static void register_header_check_gho(file_stat_t *file_stat) +{ + static const unsigned char gho_header[3]= { 0xfe, 0xef, 0x01 }; + register_header_check(0, gho_header, sizeof(gho_header), &header_check_ghost, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gi.c b/subprojects/lib/src/file_gi.c new file mode 100644 index 0000000..94eae87 --- /dev/null +++ b/subprojects/lib/src/file_gi.c @@ -0,0 +1,82 @@ +/* + + File: file_gi.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gi) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gi(file_stat_t *file_stat); + +const file_hint_t file_hint_gi= { + .extension="gi", + .description="Roxio Creator", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gi +}; + +struct header_gi +{ + char magic[12]; + uint64_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct header_gi); + @ requires separation: \separated(&file_hint_gi, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gi(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct header_gi *hdr=(const struct header_gi *)buffer; + const uint64_t size=le64(hdr->size); + if(size > PHOTOREC_MAX_FILE_SIZE) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gi.extension; + file_recovery_new->calculated_file_size=size+20; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_gi(file_stat_t *file_stat) +{ + static const unsigned char gi_header[12]= { + 0xda, 0xda, 0xfe, 0xfe, 0x00, 0x06, 0x1c, 0x04, + 0x00, 0x04, 0x00, 0x00 + }; + register_header_check(0, gi_header, sizeof(gi_header), &header_check_gi, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gif.c b/subprojects/lib/src/file_gif.c new file mode 100644 index 0000000..8ddda44 --- /dev/null +++ b/subprojects/lib/src/file_gif.c @@ -0,0 +1,217 @@ +/* + + File: file_gif.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gif) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gif(file_stat_t *file_stat); +static data_check_t data_check_gif2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); + +const file_hint_t file_hint_gif= { + .extension="gif", + .description="Graphic Interchange Format", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gif +}; + +/*@ + @ requires file_recovery->file_check == &file_check_gif; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_gif(file_recovery_t *file_recovery) +{ + const char gif_footer[2]= {0x00, 0x3b}; + char buffer[2]; + /* file_recovery->calculated_file_size is always >= */ + if(file_recovery->calculated_file_size < 2 || + my_fseek(file_recovery->handle, file_recovery->calculated_file_size-2, SEEK_SET)<0 || + fread(buffer, 2, 1, file_recovery->handle)!=1) + { + file_recovery->file_size=0; + return; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + if(memcmp(buffer, gif_footer, sizeof(gif_footer))!=0) + { + file_recovery->file_size=0; + return; + } + file_recovery->file_size=file_recovery->calculated_file_size; +} + +/*@ + @ requires file_recovery->data_check==&data_check_gif; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->data_check; + @*/ +static data_check_t data_check_gif(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 1; */ +#ifdef DEBUG_GIF + log_info("data_check_gif calculated_file_size=0x%llx: 0x%02x\n", + (long long unsigned)file_recovery->calculated_file_size, buffer[i]); +#endif + switch(buffer[i]) + { + case 0x21: + /* Plain Text Extension 21 01 ... */ + /* Graphic Control Extension 21 f9 04 XX XX XX XX 00 */ + /* Comment Extension 21 fe ... */ + /* Application Extension 21 ff */ + file_recovery->calculated_file_size+=2; + if(file_recovery->calculated_file_size >= PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + /*@ assert file_recovery->calculated_file_size < PHOTOREC_MAX_FILE_SIZE; */ + file_recovery->data_check=&data_check_gif2; + return data_check_gif2(buffer, buffer_size, file_recovery); + case 0x2c: + if(i + 20 < buffer_size) + { + unsigned int j=10+1; + /* 1 Image Descriptor id=0x2c + * 4: NW corner + * 4: width, heigth, + * 1: is a local color table present ? */ + if(((buffer[i+9]>>7)&0x1)>0) + { + /* local color table */ + j+=3<<((buffer[i+9]&7)+1); + } + file_recovery->calculated_file_size+=j; + /* 1: Start of image - LZW minimum code size */ + /* Table Based Image Data */ + if(file_recovery->calculated_file_size >= PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + file_recovery->data_check=&data_check_gif2; + return data_check_gif2(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; + case 0x3b: + /* Trailer */ + file_recovery->calculated_file_size++; + return DC_STOP; + default: + return DC_ERROR; + } + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&data_check_gif2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->data_check; + @*/ +static data_check_t data_check_gif2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size, file_recovery->data_check; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 1; */ +#ifdef DEBUG_GIF + log_info("data_check_gif2 calculated_file_size=0x%llx\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->calculated_file_size+=(uint64_t)1+buffer[i]; + if(file_recovery->calculated_file_size >= PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + /*@ assert file_recovery->calculated_file_size < PHOTOREC_MAX_FILE_SIZE; */ + if(buffer[i]==0) + { + file_recovery->data_check=&data_check_gif; + return data_check_gif(buffer, buffer_size, file_recovery); + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 6+7+(3<<8)+1; + @ requires separation: \separated(&file_hint_gif, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_gif.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1 && file_recovery_new->blocksize>=2) ==> (file_recovery_new->calculated_file_size >= 6+7); + @ ensures (\result == 1 && file_recovery_new->blocksize>=2) ==> (file_recovery_new->data_check == &data_check_gif); + @ ensures (\result == 1 && file_recovery_new->blocksize>=2) ==> (file_recovery_new->file_check == &file_check_gif); + @ assigns *file_recovery_new; + @*/ +static int header_check_gif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t offset; + offset=6; /* Header */ + offset+=7; /* Logical Screen Descriptor */ + if((buffer[10]>>7)&0x1) + { + /* Global Color Table */ + offset+=3<<((buffer[10]&7)+1); + } + if(offset < buffer_size && buffer[offset]!=0x21 && buffer[offset]!=0x2c) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gif.extension; + file_recovery_new->min_filesize=42; + if(file_recovery_new->blocksize < 2) + return 1; + file_recovery_new->calculated_file_size=offset; + file_recovery_new->file_check=&file_check_gif; + file_recovery_new->data_check=&data_check_gif; + return 1; +} + +static void register_header_check_gif(file_stat_t *file_stat) +{ + static const unsigned char gif_header[6]= { 'G','I','F','8','7','a'}; + static const unsigned char gif_header2[6]= { 'G','I','F','8','9','a'}; + register_header_check(0, gif_header,sizeof(gif_header), &header_check_gif, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, gif_header2,sizeof(gif_header2), &header_check_gif, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_gm6.c b/subprojects/lib/src/file_gm6.c new file mode 100644 index 0000000..26e9565 --- /dev/null +++ b/subprojects/lib/src/file_gm6.c @@ -0,0 +1,169 @@ +/* + + File: file_gm6.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gm6) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gm6(file_stat_t *file_stat); + +const file_hint_t file_hint_gm6= { + .extension="gm*", + .description="Game Maker (4.3 - 8.1)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gm6 +}; + +//Version 8.1 file (.gm81) +/*@ + @ requires separation: \separated(&file_hint_gm6, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gm81(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="gm81"; + return 1; +} + +//Version 7.0-8.0 file (.gmk) +/*@ + @ requires separation: \separated(&file_hint_gm6, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gmk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="gmk"; + return 1; +} + +//Version 6.0-6.1 file (.gm6) +/*@ + @ requires separation: \separated(&file_hint_gm6, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gm6(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="gm6"; + return 1; +} + +//Version 4.3-5.3A file (.gmd) +/*@ + @ requires separation: \separated(&file_hint_gm6, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gmd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="gmd"; + return 1; +} + +static void register_header_check_gm6(file_stat_t *file_stat) +{ + /* + These are the headers that identify Game Maker files for 8.1 and earlier. + First set of 4 bytes: Little-endian, constant 1234321 (decimal) + Second set of 4 bytes: Little-endian, Version identifier + Source: "Binary Format of GameMaker Save Files (gmd, gm6, gmk)" by IsmAvatar + URL: http://ismavatar.com/lgm/formats/gmformat7.txt + */ + //Version 8.1 (.gm81) + static const unsigned char gm81_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x2a, 0x03, 0x00, 0x00 + }; + //Version 8.0 (.gmk) + static const unsigned char gm80_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x20, 0x03, 0x00, 0x00 + }; + //Version 7.0 variant 2 (.gmk) + static const unsigned char gm72_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0xbe, 0x02, 0x00, 0x00 + }; + //Version 7.0 variant 1 (.gmk) + static const unsigned char gm71_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0xbd, 0x02, 0x00, 0x00 + }; + //Version 7.0 early variant (.gmk) + static const unsigned char gm62_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x6c, 0x02, 0x00, 0x00 + }; + //Version 6.0-6.1 (.gm6) + static const unsigned char gm60_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x58, 0x02, 0x00, 0x00 + }; + //Version 5.3 (.gmd) + static const unsigned char gm53_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x12, 0x02, 0x00, 0x00 + }; + //Version 5.2 (.gmd) + static const unsigned char gm52_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0x08, 0x02, 0x00, 0x00 + }; + //Version 5.1 (.gmd) + static const unsigned char gm51_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0xfe, 0x01, 0x00, 0x00 + }; + //Version 5.0 (.gmd) + static const unsigned char gm50_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0xf4, 0x01, 0x00, 0x00 + }; + //Version 4.3 (.gmd) + static const unsigned char gm43_header[8] = { + 0x91, 0xd5, 0x12, 0x00, 0xae, 0x01, 0x00, 0x00 + }; + + //Register all variant header signatures with respective extensions + register_header_check(0, gm81_header, sizeof(gm81_header), &header_check_gm81, file_stat); + register_header_check(0, gm80_header, sizeof(gm80_header), &header_check_gmk, file_stat); + register_header_check(0, gm72_header, sizeof(gm72_header), &header_check_gmk, file_stat); + register_header_check(0, gm71_header, sizeof(gm71_header), &header_check_gmk, file_stat); + register_header_check(0, gm62_header, sizeof(gm62_header), &header_check_gmk, file_stat); + register_header_check(0, gm60_header, sizeof(gm60_header), &header_check_gm6, file_stat); + register_header_check(0, gm53_header, sizeof(gm53_header), &header_check_gmd, file_stat); + register_header_check(0, gm52_header, sizeof(gm52_header), &header_check_gmd, file_stat); + register_header_check(0, gm51_header, sizeof(gm51_header), &header_check_gmd, file_stat); + register_header_check(0, gm50_header, sizeof(gm50_header), &header_check_gmd, file_stat); + register_header_check(0, gm43_header, sizeof(gm43_header), &header_check_gmd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gp2.c b/subprojects/lib/src/file_gp2.c new file mode 100644 index 0000000..5d74233 --- /dev/null +++ b/subprojects/lib/src/file_gp2.c @@ -0,0 +1,84 @@ +/* + + File: file_gp2.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gp2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gp2(file_stat_t *file_stat); + +const file_hint_t file_hint_gp2= { + .extension="gp2", /* .gp, .gobe */ + .description="Gobe Productive Document", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gp2 +}; + +/*@ + @ requires file_recovery->file_check == &file_check_gp2; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_gp2(file_recovery_t *file_recovery) +{ + const unsigned char gp2_footer[8]= { + 0x00, 0x00, 0x00, 0x01, 'E' , 'N' , 'D' , '!' + }; + file_search_footer(file_recovery, gp2_footer, sizeof(gp2_footer), 0); +} + +/*@ + @ requires separation: \separated(&file_hint_gp2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gp2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gp2.extension; + file_recovery_new->file_check=&file_check_gp2; + return 1; +} + +static void register_header_check_gp2(file_stat_t *file_stat) +{ + static const unsigned char gp2_header[20]= { + 'G' , 'O' , 'B' , 'E' , ' ' , 'S' , 'C' , 'O' , + 'T' , 'T' , '/' , '0' , '1' , '/' , '0' , '2' , + 'D' , 'O' , 'C' , '!' + }; + register_header_check(0, gp2_header, sizeof(gp2_header), &header_check_gp2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gp5.c b/subprojects/lib/src/file_gp5.c new file mode 100644 index 0000000..d9e9f46 --- /dev/null +++ b/subprojects/lib/src/file_gp5.c @@ -0,0 +1,96 @@ +/* + + File: file_gp5.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gp5) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gp5(file_stat_t *file_stat); + +const file_hint_t file_hint_gp5= { + .extension="gp5", + .description="Guitar Pro 4 & 5", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gp5 +}; + +/*@ + @ requires file_recovery->file_check == &file_check_gp5; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_gp5(file_recovery_t *file_recovery) +{ + const unsigned char gp5_footer[13]= { + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00 + }; + file_search_footer(file_recovery, gp5_footer, sizeof(gp5_footer), 0); +} + +/*@ + @ requires buffer_size >= 23; + @ requires separation: \separated(&file_hint_gp5, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gp5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[22]!='.') + return 0; + if(buffer[21]=='4') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="gp4"; + return 1; + } + if(buffer[21]!='5') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gp5.extension; + file_recovery_new->file_check=&file_check_gp5; + return 1; +} + +static void register_header_check_gp5(file_stat_t *file_stat) +{ + static const unsigned char gp5_header[21]= { + 0x18, 'F' , 'I' , 'C' , 'H' , 'I' , 'E' , 'R' , + ' ' , 'G' , 'U' , 'I' , 'T' , 'A' , 'R' , ' ' , + 'P' , 'R' , 'O' , ' ' , 'v' + }; + register_header_check(0, gp5_header, sizeof(gp5_header), &header_check_gp5, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gpg.c b/subprojects/lib/src/file_gpg.c new file mode 100644 index 0000000..c983c2d --- /dev/null +++ b/subprojects/lib/src/file_gpg.c @@ -0,0 +1,863 @@ +/* + + File: file_gpg.c + + Copyright (C) 2008-2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gpg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#ifdef DEBUG_GPG +#include "log.h" +#endif +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +static const char *extension_pgp="pgp"; +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gpg(file_stat_t *file_stat); + +const file_hint_t file_hint_gpg= { + .extension="gpg", + .description="OpenPGP/GPG (Partial support)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gpg +}; + +/* See rfc4880 OpenPGP Message Format */ + +/* Public-Key Encrypted Session Key Packets */ +#define OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY 1 +/* Signature Packet */ +#define OPENPGP_TAG_SIGNATURE 2 +/* Symmetric-Key Encrypted Session Key Packets */ +#define OPENPGP_TAG_SYMKEY_ENC_SESSION_KEY 3 +/* One-Pass Signature Packets (Tag 4) */ +#define OPENPGP_TAG_ONE_PASS_SIG 4 +/* Secret-Key Packet (Tag 5) */ +#define OPENPGP_TAG_SEC_KEY 5 +/* Public-Key Packet (Tag 6)*/ +#define OPENPGP_TAG_PUB_KEY 6 +/* Secret-Subkey Packet (Tag 7) */ +#define OPENPGP_TAG_SEC_SUBKEY 7 +/* Compressed Data Packet (Tag 8) */ +/* Symmetrically Encrypted Data Packet */ +#define OPENPGP_TAG_SYM_ENC_DATA 9 +/* Marker Packet (Tag 10) */ +#define OPENPGP_TAG_MARKER 10 +/* Literal Data Packet (Tag 11) + * Trust Packet (Tag 12) */ +#define OPENPGP_TAG_TRUST 12 + /* User ID Packet */ +#define OPENPGP_TAG_USER_ID 13 + /* Public-Subkey Packet (Tag 14) */ +#define OPENPGP_TAG_PUB_SUBKEY 14 +/* User Attribute Packet (Tag 17) + */ +/* Sym. Encrypted Integrity Protected Data Packet */ +#define OPENPGP_TAG_SYM_ENC_INTEGRITY 18 + /* Modification Detection Code Packet (Tag 19) */ + +static const unsigned char pgp_header[5]= {0xa8, 0x03, 'P', 'G', 'P'}; + +/*@ + @ ensures 0 <= \result <= 0x3f; + @ assigns \nothing; + @*/ +static unsigned int openpgp_packet_tag(const unsigned char buf) +{ + /* Bit 7 -- Always one */ + if((buf&0x80)==0) + return 0; /* Invalid */ + return ((buf&0x40)==0?((buf>>2)&0x0f):(buf&0x3f)); +} + +/*@ requires \valid_read(buf+(0..5)); + @ requires \valid(length_type); + @ requires \valid(indeterminate_length); + @ requires \separated(buf+(..), indeterminate_length, length_type); + @ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==3)|| (*length_type==5); + @ assigns *length_type, *indeterminate_length; + */ +static unsigned int old_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *indeterminate_length) +{ + /* Old format */ + switch(buf[0]&0x3) + { + case 0: + *length_type=2; + return buf[1]; + case 1: + *length_type=3; + return (buf[1] << 8) | buf[2]; + case 2: + { + const uint32_t *tmp32_ptr=(const uint32_t *)&buf[1]; + *length_type=5; + return be32(*tmp32_ptr); + } + default: + *length_type=1; + *indeterminate_length=1; + return 0; + } +} + +/*@ requires \valid_read(buf+(0..5)); + @ requires \valid(length_type); + @ requires \valid(partial_body_length); + @ requires separation: \separated(buf+(0..5), length_type, partial_body_length); + @ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==5); + @ ensures (*partial_body_length==0) || (*partial_body_length==1); + @ assigns *length_type, *partial_body_length; + */ +static unsigned int new_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *partial_body_length) +{ + const unsigned char buf0=buf[0]; + *partial_body_length=0; + /* One-Octet Body Length */ + if(buf0<=191) + { + *length_type=1; + /*@ assert buf0 <= 191; */ + return buf0; + } + /* Two-Octet Body Length */ + if(buf0<=223) + { + /*@ assert 192 <= buf0 <= 223; */ + unsigned int tmp=buf0; + /*@ assert 192 <= tmp <= 223; */ + tmp = ((tmp-192) << 8) + buf[1] + 192; + *length_type=2; + /*@ assert 192 <= tmp <= ((223-192) << 8) + 255 + 192; */ + return tmp; + } + /*@ assert 224 <= buf0; */ + /* Five-Octet Body Length */ + if(buf0==255) + { + const uint32_t *tmp32=(const uint32_t *)&buf[1]; + const unsigned int tmp=be32(*tmp32); + *length_type=5; + /*@ assert tmp <= 0xffffffff; */ + return tmp; + } + /*@ assert buf0 != 255; */ + /*@ assert 224 <= buf0 <= 254; */ + { + const unsigned int tmp=buf0&0x1fu; + /*@ assert tmp <= 30; */ + const unsigned int tmp2=1u << tmp; + /* Partial Body Lengths */ + *length_type=1; + *partial_body_length=1; + /*@ assert tmp2 <= (1<<30); */ + return tmp2; + } +} + +/*@ + @ ensures \result == -1 || 0 <= \result <= 2048; + @ assigns \nothing; + @*/ +static int is_valid_mpi(const uint16_t size) +{ + const uint16_t tmp=be16(size); + if(tmp <= 16384) + return (tmp+7)/8; + return -1; +} + +/*@ + @ ensures \result == 0 || \result == 1; + @ assigns \nothing; + @*/ +static int is_valid_pubkey_algo(const int algo) +{ + /* 1 - RSA (Encrypt or Sign) + * 2 - RSA Encrypt-Only + * 3 - RSA Sign-Only + * 16 - Elgamal (Encrypt-Only), see [ELGAMAL] + * 17 - DSA (Digital Signature Standard) + * 18 - Reserved for Elliptic Curve + * 19 - Reserved for ECDSA + * 20 - Elgamal (Encrypt or Sign) + * 21 - Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME) + * 100 to 110 - Private/Experimental algorithm + */ + switch(algo) + { + case 1: + case 2: + case 3: + case 16: + case 17: + case 20: + return 1; + default: + return 0; + } +} + +/*@ + @ ensures \result == 0 || \result == 1; + @ assigns \nothing; + @*/ +static int is_valid_sym_algo(const int algo) +{ + /* + 0 - Plaintext or unencrypted data + 1 - IDEA [IDEA] + 2 - TripleDES (DES-EDE, [SCHNEIER] [HAC] - + 168 bit key derived from 192) + 3 - CAST5 (128 bit key, as per [RFC2144]) + 4 - Blowfish (128 bit key, 16 rounds) [BLOWFISH] + 5 - Reserved + 6 - Reserved + 7 - AES with 128-bit key [AES] + 8 - AES with 192-bit key + 9 - AES with 256-bit key + 10 - Twofish with 256-bit key [TWOFISH] + 100 to 110 - Private/Experimental algorithm + */ + switch(algo) + { + case 1: + case 2: + case 3: + case 4: + case 7: + case 8: + case 9: + case 10: + return 1; + default: + return 0; + } +} + +/*@ + @ ensures \result == 0 || \result == 1; + @ assigns \nothing; + @*/ +static int is_valid_S2K(const unsigned int algo) +{ + /* ID S2K Type + * -- -------- + * 0 Simple S2K + * 1 Salted S2K + * 2 Reserved value + * 3 Iterated and Salted S2K + * 100 to 110 Private/Experimental S2K + */ + return (algo==0 || algo==1 || algo==3); +} + +/*@ + @ requires \valid(handle); + @ requires offset + tmp2 < 0x8000000000000000; + @ requires \separated(handle, &errno, &Frama_C_entropy_source); + @ assigns *handle, errno; + @ assigns Frama_C_entropy_source; + @*/ +static unsigned int file_check_gpg_pubkey(FILE *handle, const uint64_t offset, const uint64_t tmp2) +{ + int len2; + char buffer[2]; + const uint16_t *mpi2_ptr=(uint16_t *)&buffer; + if(my_fseek(handle, offset+tmp2, SEEK_SET) < 0 || + fread(buffer, sizeof(buffer), 1, handle) != 1) + return 0; +#ifdef __FRAMAC__ + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + len2=is_valid_mpi(*mpi2_ptr); +#ifdef DEBUG_GPG + log_info(" data: [ %u bits]\n", be16(*mpi2_ptr)); +#endif + if(len2 < 0) + return 0; + return len2; +} + +/*@ + @ requires file_recovery->file_check == &file_check_gpg; + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_gpg(file_recovery_t *file_recovery) +{ + unsigned int tag=0; + unsigned int nbr=0; + int partial_body_length=0; + int stop=0; + uint64_t offset=0; + const uint64_t org_file_size=file_recovery->file_size; + file_recovery->file_size=0; + /*@ + @ loop invariant \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ loop invariant valid_file_recovery(file_recovery); + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source; + @ loop assigns tag, nbr, partial_body_length, stop, offset; + @*/ + while(stop==0) + { + char sbuffer[32]; + const unsigned char *buffer=(const unsigned char *)&sbuffer; + unsigned int i=0; + unsigned int length_type=0; + unsigned int length; + const int old_partial_body_length=partial_body_length; + if(nbr >=0xffffffff || offset >= 0x7000000000000000) + return; + /*@ assert offset < 0x7000000000000000; */ + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 || + fread(&sbuffer, sizeof(sbuffer), 1, file_recovery->handle) != 1) + { + if(nbr>=2 && offset <= org_file_size) + file_recovery->file_size=org_file_size; + return; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&sbuffer, sizeof(sbuffer)); +#endif + if(partial_body_length==0) + { + if((buffer[0]&0x80)==0) + break; /* Invalid */ + tag=openpgp_packet_tag(buffer[0]); + if((buffer[0]&0x40)==0) + { + length=old_format_packet_length(&buffer[0], &length_type, &stop); + /*@ assert (length_type == 1) || (length_type == 2) || (length_type==3) || (length_type==5); */ + } + else + { + length=new_format_packet_length(&buffer[1], &length_type, &partial_body_length); + length_type++; + /*@ assert (length_type == 2) || (length_type == 3) || (length_type==6); */ + } + } + else + { + length=new_format_packet_length(&buffer[0], &length_type, &partial_body_length); + /*@ assert (length_type == 1) || (length_type == 2) || (length_type==5); */ + } + /*@ assert 0 <= length_type <= 6; */ +#ifdef DEBUG_GPG + log_info("GPG 0x%04x: %02u tag=%2u, size=%u + %u)\n", + 0, nbr, tag, length_type, length); +#endif +#if 0 + if(tag==0 || tag==15 || (tag>19 && tag!=61)) /* Reserved or unused */ + return; +#endif + if(length_type==0) + break; /* Don't know how to find the size */ + /*@ assert 0 < length_type <= 6; */ + i+=length_type; + /*@ assert 0 < i <= 6; */ + offset+=length_type; + if(offset >= 0x7000000000000000) + return ; + /*@ assert offset < 0x7000000000000000; */ + /*@ assert length < 0x7000000000000000; */ + if(offset + length >= 0x7000000000000000) + return ; + /*@ assert offset + length < 0x7000000000000000; */ + if(old_partial_body_length==0) + { + if(tag==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY) + { + const uint16_t *mpi_ptr=(const uint16_t *)&buffer[i+1+8+1]; + const int len=is_valid_mpi(*mpi_ptr); + const int pubkey_algo=buffer[i+1+8]; + /* uint8_t version must be 3 + * uint64_t pub_key_id + * uint8_t pub_key_algo + * encrypted_session_key */ + if(buffer[i]==3 && is_valid_pubkey_algo(pubkey_algo) && + len>0) + { + /* assert 0 < len <=2048; */ + const unsigned int tmp2=1+8+1+2+len; + /* assert 12 < tmp2 <=12+2048; */ +#ifdef DEBUG_GPG + log_info("GPG :pubkey enc packet: version %u, algo %u, keyid %02X%02X%02X%02X%02X%02X%02X%02X\n", + buffer[i], pubkey_algo, + buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], + buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]); + log_info(" data: [ %u bits]\n", be16(*mpi_ptr)); +#endif + if(tmp2 > length) + return ; + /*@ assert tmp2 <= length; */ + if(pubkey_algo==16 || pubkey_algo==20) + { + const int len2=file_check_gpg_pubkey(file_recovery->handle, offset, tmp2); + if(len2 <= 0) + return; + if((unsigned)(1+8+1+2+len+2+len2) > length) + return; + } + } + else + return; + } + else if(tag==OPENPGP_TAG_SIGNATURE) + { + /* v3 - length=5 */ + if(buffer[i]==3 && buffer[i+1]==5 && is_valid_pubkey_algo(buffer[i+1+1+5+8])) + { +#ifdef DEBUG_GPG + log_info(":signature packet: algo %u\n", buffer[i+1+1+5+8]); + log_info(":signature packet: sig_class 0x%02x\n", buffer[i+1+1]); +#endif + } + /* v4 */ + else if(buffer[i]==4 && is_valid_pubkey_algo(buffer[i+2])) + { +#ifdef DEBUG_GPG + log_info(":signature packet: algo %u\n", buffer[i+2]); +#endif + } + else + return; + } + else if(tag==OPENPGP_TAG_SYMKEY_ENC_SESSION_KEY) + { + /* v4 */ + if(buffer[i]==4 && is_valid_sym_algo(buffer[i+1]) && is_valid_S2K(buffer[i+2])) + { + } + else + return; + } + else if(tag==OPENPGP_TAG_ONE_PASS_SIG) + { + if(buffer[i]==3 && is_valid_sym_algo(buffer[i+1])) + { + } + else + return; + } + else if(tag==OPENPGP_TAG_SYM_ENC_DATA) + { + } + else if(tag==OPENPGP_TAG_MARKER) + { + /* Must be at the beginning of the packet */ + if(nbr!=0) + return; + } + else if(tag==OPENPGP_TAG_SYM_ENC_INTEGRITY) + { +#ifdef DEBUG_GPG + log_info("GPG :encrypted data packet:\n"); +#endif + /* Version must be 1 */ + if(buffer[i]!=1) + return; + } + else if(tag==OPENPGP_TAG_PUB_KEY || + tag==OPENPGP_TAG_PUB_SUBKEY || + tag==OPENPGP_TAG_SEC_KEY|| + tag==OPENPGP_TAG_SEC_SUBKEY) + { + if((buffer[i]==2 || buffer[i]==3) && is_valid_pubkey_algo(buffer[i+1+4+2])) + { /* version 2 or 3 */ + } + else if(buffer[i]==4 && is_valid_pubkey_algo(buffer[i+1+4])) + { /* version 4 */ + } + else + return; + } + } + if(partial_body_length==0) + nbr++; + offset+=length; + } + if(nbr<2) + return; + file_recovery->file_size=(stop==0?org_file_size:(uint64_t)offset); +} + +/*@ + @ requires buffer_size >= 23; + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_gpg.extension || file_recovery_new->extension == extension_pgp); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_gpg); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @*/ +// X assigns *file_recovery_new; +static int header_check_gpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t i=0; + unsigned int packet_tag[16]; + unsigned int nbr=0; + int partial_body_length=0; + int stop=0; + memset(packet_tag, 0, sizeof(packet_tag)); + /*@ assert \initialized(packet_tag + (0 .. 15)); */ + /*@ + @ loop invariant 0 <= nbr <=16; + @ loop assigns i, packet_tag[0..nbr], nbr, partial_body_length, stop; + @*/ + while(nbr<16 && i < buffer_size - 23 && stop==0) + { + /*@ assert 0 <= i < buffer_size - 23; */ + unsigned int length_type=0; + unsigned int tag; + unsigned int length; + const int old_partial_body_length=partial_body_length; + if(partial_body_length==0) + { + if((buffer[i]&0x80)==0) + break; /* Invalid */ + packet_tag[nbr]=openpgp_packet_tag(buffer[i]); + if((buffer[i]&0x40)==0) + { + length=old_format_packet_length(&buffer[i], &length_type, &stop); + /*@ assert (length_type == 1) || (length_type == 2) || (length_type==3) || (length_type==5); */ + } + else + { + length=new_format_packet_length(&buffer[i+1], &length_type, &partial_body_length); + length_type++; + /*@ assert (length_type == 2) || (length_type == 3) || (length_type==6); */ + } + } + else + { + length=new_format_packet_length(&buffer[i], &length_type, &partial_body_length); + /*@ assert (length_type == 1) || (length_type == 2) || (length_type==5); */ + } + /*@ assert 0 <= length_type <= 6; */ + tag=packet_tag[nbr]; +#ifdef DEBUG_GPG + log_info("GPG 0x%04lx: %02u tag=%2u, size=%u + %u)\n", + i, nbr, tag, length_type, length); +#endif +#if 0 + if(tag==0 || tag==15 || (tag>19 && tag!=61)) /* Reserved or unused */ + return 0; +#endif + if(length_type==0) + break; /* Don't know how to find the size */ + /*@ assert 0 < length_type <= 6; */ + i+=length_type; + /*@ assert 0 <= i < buffer_size - 23 + 6; */ + if(old_partial_body_length==0) + { + if(tag==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY) + { + const uint16_t *mpi_ptr=(const uint16_t *)&buffer[i+1+8+1]; + const int len=is_valid_mpi(*mpi_ptr); + /* uint8_t version must be 3 + * uint64_t pub_key_id + * uint8_t pub_key_algo + * encrypted_session_key */ + if(buffer[i]==3 && is_valid_pubkey_algo(buffer[i+1+8]) && + len>0) + { + const unsigned int offset_mpi=i+1+8+1+2+len; +#ifdef DEBUG_GPG + log_info("GPG :pubkey enc packet: version %u, algo %u, keyid %02X%02X%02X%02X%02X%02X%02X%02X\n", + buffer[i], buffer[i+1+8], + buffer[i+1], buffer[i+2], buffer[i+3], buffer[i+4], + buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]); + log_info(" data: [ %u bits]\n", be16(*mpi_ptr)); +#endif + if(offset_mpi +2 > length) + return 0; + if((buffer[i+1+8]==16 || buffer[i+1+8]==20) && + offset_mpi + 2 <= buffer_size) + { + int len2; + /*@ assert 0 <= offset_mpi + 2 <= buffer_size; */ + mpi_ptr=(const uint16_t *)&buffer[offset_mpi]; + len2=is_valid_mpi(*mpi_ptr); +#ifdef DEBUG_GPG + log_info(" data: [ %u bits]\n", be16(*mpi_ptr)); +#endif + if(len2 <= 0) + return 0; + if((unsigned)(1+8+1+2+len+2+len2) > length) + return 0; + } + } + else + return 0; + } + else if(tag==OPENPGP_TAG_SIGNATURE) + { + /* v3 - length=5 */ + if(buffer[i]==3 && buffer[i+1]==5 && is_valid_pubkey_algo(buffer[i+1+1+5+8])) + { +#ifdef DEBUG_GPG + log_info(":signature packet: algo %u\n", buffer[i+1+1+5+8]); + log_info(":signature packet: sig_class 0x%02x\n", buffer[i+1+1]); +#endif + } + /* v4 */ + else if(buffer[i]==4 && is_valid_pubkey_algo(buffer[i+2])) + { +#ifdef DEBUG_GPG + log_info(":signature packet: algo %u\n", buffer[i+2]); +#endif + } + else + return 0; + } + else if(tag==OPENPGP_TAG_SYMKEY_ENC_SESSION_KEY) + { + /* v4 */ + if(buffer[i]==4 && is_valid_sym_algo(buffer[i+1]) && is_valid_S2K(buffer[i+2])) + { + } + else + return 0; + } + else if(tag==OPENPGP_TAG_ONE_PASS_SIG) + { + if(buffer[i]==3 && is_valid_sym_algo(buffer[i+1])) + { + } + else + return 0; + } + else if(tag==OPENPGP_TAG_SYM_ENC_DATA) + { + unsigned int j; + int ok=0; + /* The symmetric cipher used may be specified in a Public-Key or + * Symmetric-Key Encrypted Session Key packet that precedes the + * Symmetrically Encrypted Data packet. + * PhotoRec assumes it must */ + /*@ loop assigns j, ok; */ + for(j=0; jfile_check=&file_check_gpg; + file_recovery_new->extension=extension_pgp; + return 1; + } + /* encrypted_data.gpg */ + if(((packet_tag[0]==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY || + packet_tag[0]==OPENPGP_TAG_SYMKEY_ENC_SESSION_KEY) && + (packet_tag[1]==OPENPGP_TAG_SYM_ENC_DATA || + packet_tag[1]==OPENPGP_TAG_SYM_ENC_INTEGRITY)) || + /* pubring.gpg */ + (packet_tag[0]==OPENPGP_TAG_PUB_KEY && + packet_tag[1]==OPENPGP_TAG_USER_ID && + packet_tag[2]==OPENPGP_TAG_SIGNATURE && + packet_tag[3]==OPENPGP_TAG_TRUST) || + (packet_tag[0]==OPENPGP_TAG_PUB_KEY && + packet_tag[1]==OPENPGP_TAG_USER_ID && + packet_tag[2]==OPENPGP_TAG_SIGNATURE && + packet_tag[3]==OPENPGP_TAG_PUB_SUBKEY) || + /* secring.gpg */ + (packet_tag[0]==OPENPGP_TAG_SEC_KEY && + packet_tag[1]==OPENPGP_TAG_USER_ID && + packet_tag[2]==OPENPGP_TAG_SIGNATURE && + packet_tag[3]==OPENPGP_TAG_TRUST) || + (packet_tag[0]==OPENPGP_TAG_SEC_KEY && + packet_tag[1]==61 && + packet_tag[2]==61 && + packet_tag[3]==61)) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_gpg; + file_recovery_new->extension=file_hint_gpg.extension; + return 1; + } +#ifdef DEBUG_GPG + log_info("tag don't match: nbr=%u - ", nbr); + for(i=0; ifile_hint!=NULL; */ + { + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + header_check_gpg(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_recovery_new.handle=fopen(fn, "rb"); + /*@ assert file_recovery_new.file_check == &file_check_gpg; */ + if(file_recovery_new.handle!=NULL) + { + file_check_gpg(&file_recovery_new); + fclose(file_recovery_new.handle); + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_gpx.c b/subprojects/lib/src/file_gpx.c new file mode 100644 index 0000000..62f0eea --- /dev/null +++ b/subprojects/lib/src/file_gpx.c @@ -0,0 +1,67 @@ +/* + + File: file_gpx.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gpx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gpx(file_stat_t *file_stat); + +const file_hint_t file_hint_gpx= { + .extension="gpx", + .description="Guitar Pro 6", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gpx +}; + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_gpx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_gpx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char magic[8]={ 0x68, 0x48, 0x68, 0xcd, 0x4c, 0x00, 0x01, 0x80 }; + if(memcmp(&buffer[8], magic, 8)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gpx.extension; + return 1; +} + +static void register_header_check_gpx(file_stat_t *file_stat) +{ + register_header_check(0, "BCFZ", 4, &header_check_gpx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_gsm.c b/subprojects/lib/src/file_gsm.c new file mode 100644 index 0000000..fa184f7 --- /dev/null +++ b/subprojects/lib/src/file_gsm.c @@ -0,0 +1,158 @@ +/* + + File: file_gsm.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gsm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gsm(file_stat_t *file_stat); + +const file_hint_t file_hint_gsm= { + .extension="gsm", + .description="Group Speciale Mobile GSM 06.10", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_gsm +}; + +struct block_header +{ + unsigned char marker; + unsigned char payload[32]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_gsm; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_gsm(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + sizeof(struct block_header) < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - sizeof(struct block_header); */ + const struct block_header *hdr=(const struct block_header *)&buffer[i]; + if(hdr->marker < 0xd0 || hdr->marker > 0xdf) + return DC_STOP; + file_recovery->calculated_file_size+=sizeof(struct block_header); + } + return DC_CONTINUE; +} + +/*@ + @ requires separation: \separated(&file_hint_gsm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_gsm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i=0; + /*@ assert file_recovery_new->blocksize <= buffer_size; */ + /*@ loop assigns i; */ + for(i=0; + (i+1) * sizeof(struct block_header) <= file_recovery_new->blocksize; + i++) + { + /*@ assert (i+1) * sizeof(struct block_header) <= file_recovery_new->blocksize; */ + /*@ assert (i+1) * sizeof(struct block_header) <= buffer_size; */ + /*@ assert \valid_read(buffer + (0 .. buffer_size-1)); */ + /*@ assert \valid_read(buffer + (0 .. (i+1) * sizeof(struct block_header)-1)); */ + const struct block_header *hdr=(const struct block_header *)&buffer[i*sizeof(struct block_header)]; + /*@ assert \valid_read(hdr); */ + if(hdr->marker < 0xd0 || hdr->marker > 0xdf) + return 0; + } + if(i<3) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_gsm) + { + /*@ assert \valid_function(file_recovery->file_check); */ + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_gsm.extension; + file_recovery_new->min_filesize=sizeof(struct block_header); + file_recovery_new->calculated_file_size=0; + file_recovery_new->data_check=&data_check_gsm; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_gsm(file_stat_t *file_stat) +{ + static const unsigned char gsm_header1[1]={ 0xd0 }; + static const unsigned char gsm_header2[1]={ 0xd1 }; + static const unsigned char gsm_header3[1]={ 0xd2 }; + static const unsigned char gsm_header4[1]={ 0xd3 }; + static const unsigned char gsm_header5[1]={ 0xd4 }; + static const unsigned char gsm_header6[1]={ 0xd5 }; + static const unsigned char gsm_header7[1]={ 0xd6 }; + static const unsigned char gsm_header8[1]={ 0xd7 }; + static const unsigned char gsm_header9[1]={ 0xd8 }; + static const unsigned char gsm_header10[1]={ 0xd9 }; + static const unsigned char gsm_header11[1]={ 0xda }; + static const unsigned char gsm_header12[1]={ 0xdb }; + static const unsigned char gsm_header13[1]={ 0xdc }; + static const unsigned char gsm_header14[1]={ 0xdd }; + static const unsigned char gsm_header15[1]={ 0xde }; + static const unsigned char gsm_header16[1]={ 0xdf }; + + register_header_check(0, gsm_header1, sizeof(gsm_header1), &header_check_gsm, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, gsm_header2, sizeof(gsm_header2), &header_check_gsm, file_stat); + register_header_check(0, gsm_header3, sizeof(gsm_header3), &header_check_gsm, file_stat); + register_header_check(0, gsm_header4, sizeof(gsm_header4), &header_check_gsm, file_stat); + register_header_check(0, gsm_header5, sizeof(gsm_header5), &header_check_gsm, file_stat); + register_header_check(0, gsm_header6, sizeof(gsm_header6), &header_check_gsm, file_stat); + register_header_check(0, gsm_header7, sizeof(gsm_header7), &header_check_gsm, file_stat); + register_header_check(0, gsm_header8, sizeof(gsm_header8), &header_check_gsm, file_stat); + register_header_check(0, gsm_header9, sizeof(gsm_header9), &header_check_gsm, file_stat); + register_header_check(0, gsm_header10, sizeof(gsm_header10), &header_check_gsm, file_stat); + register_header_check(0, gsm_header11, sizeof(gsm_header11), &header_check_gsm, file_stat); + register_header_check(0, gsm_header12, sizeof(gsm_header12), &header_check_gsm, file_stat); + register_header_check(0, gsm_header13, sizeof(gsm_header13), &header_check_gsm, file_stat); + register_header_check(0, gsm_header14, sizeof(gsm_header14), &header_check_gsm, file_stat); + register_header_check(0, gsm_header15, sizeof(gsm_header15), &header_check_gsm, file_stat); + register_header_check(0, gsm_header16, sizeof(gsm_header16), &header_check_gsm, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_gz.c b/subprojects/lib/src/file_gz.c new file mode 100644 index 0000000..ca51131 --- /dev/null +++ b/subprojects/lib/src/file_gz.c @@ -0,0 +1,419 @@ +/* + + File: file_gz.c + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(MAIN_fidentify) || defined(MAIN_photorec) || defined(__FRAMAC__) +#undef HAVE_LIBZ +#undef HAVE_ZLIB_H +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "file_gz.h" + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gz) +#ifdef HAVE_ZLIB_H +#include +#endif +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_gz(file_stat_t *file_stat); +#ifndef SINGLE_FORMAT +extern const file_hint_t file_hint_doc; +#endif + +const file_hint_t file_hint_gz= { + .extension="gz", + .description="gzip compressed data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_gz +}; + +struct gzip_header +{ + uint16_t id; + uint8_t compression_method; + uint8_t flags; + uint32_t mtime; + uint8_t extra_flags; + uint8_t os; +} __attribute__ ((gcc_struct, __packed__)); + +/* flags: + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + */ +#define GZ_FTEXT 1 +#define GZ_FHCRC 2 +#define GZ_FEXTRA 4 +#define GZ_FNAME 8 +#define GZ_FCOMMENT 0x10 + +/*@ + @ requires file_recovery->file_rename==&file_rename_gz; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_gz(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + int buffer_size; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size<10) + return; + /*@ assert \initialized(buffer+(0..10)); */ + if(!(buffer[0]==0x1F && buffer[1]==0x8B && buffer[2]==0x08 && (buffer[3]&0xe0)==0)) + return ; + { + const unsigned int flags=buffer[3]; + int off=10; + if((flags&GZ_FEXTRA)!=0) + { + if(buffer_size<12) + return; + /*@ assert \initialized(buffer + (0 .. 12)); */ + off+=2; + off+=buffer[10]|(buffer[11]<<8); + } + if((flags&GZ_FNAME)!=0) + { + file_rename(file_recovery, buffer, buffer_size, off, NULL, 1); + } + } +} + +#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) +/*@ assigns \nothing; */ +static void file_check_bgzf(file_recovery_t *file_recovery) +{ +} + +/*@ + @ requires buffer_size >= sizeof(struct gzip_header); + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ requires \valid_read(buffer_uncompr + (0 .. 4-1)); + @ requires \valid(file_recovery_new); + @ requires separation: \separated(buffer+(..), file_recovery_new); + @ requires valid_file_recovery(file_recovery_new); + @ ensures \result == 1; + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_bgzf(const unsigned char *buffer, const unsigned char *buffer_uncompr, const unsigned int buffer_size, file_recovery_t *file_recovery_new) +{ + const struct gzip_header *gz=(const struct gzip_header *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=22; + file_recovery_new->time=le32(gz->mtime); + file_recovery_new->file_rename=&file_rename_gz; + file_recovery_new->file_check=&file_check_bgzf; + if(memcmp(buffer_uncompr, "BAI\1", 4)==0) + { + /* https://github.com/samtools/hts-specs SAM/BAM and related high-throughput sequencing file formats */ + file_recovery_new->extension="bai"; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + if(memcmp(buffer_uncompr, "BAM\1", 4)==0) + { + /* https://github.com/samtools/hts-specs SAM/BAM and related high-throughput sequencing file formats */ + file_recovery_new->extension="bam"; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + if(memcmp(buffer_uncompr, "CSI\1", 4)==0) + { + /* https://github.com/samtools/hts-specs SAM/BAM and related high-throughput sequencing file formats */ + file_recovery_new->extension="csi"; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + file_recovery_new->extension="bgz"; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} +#endif + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_gz, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_gz(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int off=10; + const unsigned int flags=buffer[3]; + const struct gzip_header *gz=(const struct gzip_header *)buffer; + int bgzf=0; + /* gzip file format: + * a 10-byte header, containing a magic number, a version number and a timestamp + * optional extra headers, such as the original file name, + * a body, containing a deflate-compressed payload + * a CRC-32 checksum + * the length (32 bits) of the original uncompressed data + */ + /* gzip, deflate */ + if(!(buffer[0]==0x1F && buffer[1]==0x8B && buffer[2]==0x08 && (buffer[3]&0xe0)==0)) + return 0; + + /* + * 4,5,6,7: mtime + * 8: xfl/extra flags + * 9: OS 3 - Unix, 7 - Macintosh, 11 - NTFS filesystem (NT) + */ + if((flags&GZ_FEXTRA)!=0) + { + off+=2; + off+=buffer[10]|(buffer[11]<<8); + if(buffer[12]=='B' && buffer[13]=='C' && buffer[14]==2 && buffer[15]==0) + bgzf=1; + } + if((flags&GZ_FNAME)!=0) + { + for(; off= 512 || off >= buffer_size) + return 0; + /*@ assert off < 512; */ + /*@ assert off < buffer_size ; */ +#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) + { + static const unsigned char schematic_header[12]={ 0x0a, 0x00, 0x09, + 'S', 'c', 'h', 'e', 'm', 'a', 't', 'i', 'c'}; + static const unsigned char tar_header_posix[8] = { 'u','s','t','a','r',' ',' ',0x00}; + const unsigned char *buffer_compr=buffer+off; + unsigned char buffer_uncompr[4096]; + const unsigned int uncomprLen=sizeof(buffer_uncompr)-1; + const unsigned int bs=td_max(512U,file_recovery_new->blocksize); + /*@ assert bs >=512; */ + const unsigned int comprLen=td_min(buffer_size,bs)-off; + /*@ assert comprLen > 0; */ + int err; + z_stream d_stream; /* decompression stream */ + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = (Bytef*)buffer_compr; + d_stream.avail_in = 0; + d_stream.next_out = buffer_uncompr; + + err = inflateInit2(&d_stream, -MAX_WBITS); + if(err!=Z_OK) + return 0; + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if(err!=Z_OK) + { + /* Decompression has failed, free ressources */ + inflateEnd(&d_stream); + return 0; + } + } + err = inflateEnd(&d_stream); + if(err!=Z_OK) + return 0; + /* Probably too small to be a file */ + if(d_stream.total_out < 16) + return 0; +#ifndef SINGLE_FORMAT + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_doc) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + if(file_recovery->file_check==&file_check_bgzf) + { + /*@ assert \valid_function(file_recovery->file_check); */ + header_ignored(file_recovery_new); + return 0; + } + buffer_uncompr[d_stream.total_out]='\0'; + if(bgzf!=0) + { + return header_check_bgzf(buffer, buffer_uncompr, d_stream.total_out, file_recovery_new); + } + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=22; + file_recovery_new->time=le32(gz->mtime); + file_recovery_new->file_rename=&file_rename_gz; + if(d_stream.avail_in==0 && d_stream.total_in < comprLen && d_stream.total_out < uncomprLen) + { + /* an 8-byte footer, containing a CRC-32 checksum and + * the length of the original uncompressed data, modulo 2^32 + */ + file_recovery_new->calculated_file_size=off+d_stream.total_in+8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + if(memcmp(buffer_uncompr, "PVP ", 4)==0) + { + /* php Video Pro */ + file_recovery_new->extension="pvp"; + return 1; + } + if(memcmp(buffer_uncompr, "\nextension="xoj"; + return 1; + } + if( memcmp(buffer_uncompr, "\r\n\nextension="als"; + return 1; + } + if(memcmp(buffer_uncompr, "\nextension="prproj"; + return 1; + } + if(memcmp(buffer_uncompr, "\nextension="gnucash"; + return 1; + } + if(strstr((const char*)&buffer_uncompr, "")!=NULL) + { + file_recovery_new->extension="kmy"; + return 1; + } +#ifndef DJGPP + if(memcmp(buffer_uncompr, "RDX2", 4)==0) + { + /* R - language and environment for statistical computing and graphics */ + file_recovery_new->extension="RData"; + return 1; + } + if(memcmp(buffer_uncompr, "extension="xml.gz"; + return 1; + } + if(memcmp(buffer_uncompr, schematic_header, sizeof(schematic_header))==0) + { + /* Minecraft Schematic File */ + file_recovery_new->extension="schematic"; + return 1; + } + { + unsigned int i; + for(i=0; iextension="html.gz"; + return 1; + } + } + } + } +#endif + if(d_stream.total_out>0x110 && + memcmp(&buffer_uncompr[0x101],tar_header_posix,sizeof(tar_header_posix))==0) + { +#ifdef DJGPP + file_recovery_new->extension="tgz"; +#else + file_recovery_new->extension="tar.gz"; +#endif + return 1; + } + } +#else +#ifndef SINGLE_FORMAT + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_doc) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=22; + file_recovery_new->time=le32(gz->mtime); + file_recovery_new->file_rename=&file_rename_gz; +#endif + file_recovery_new->extension=file_hint_gz.extension; + return 1; +} + +static void register_header_check_gz(file_stat_t *file_stat) +{ + static const unsigned char gz_header_magic[3]= {0x1F, 0x8B, 0x08}; + register_header_check(0, gz_header_magic,sizeof(gz_header_magic), &header_check_gz, file_stat); +} +#endif + +const char*td_zlib_version(void) +{ +#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) + return ZLIB_VERSION; +#else + return "none"; +#endif +} diff --git a/subprojects/lib/src/file_gz.h b/subprojects/lib/src/file_gz.h new file mode 100644 index 0000000..7451f86 --- /dev/null +++ b/subprojects/lib/src/file_gz.h @@ -0,0 +1,36 @@ +/* + + File: file_gz.h + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_GZ_H +#define _FILE_GZ_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ assigns \result; + @*/ +const char*td_zlib_version(void); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_hdf.c b/subprojects/lib/src/file_hdf.c new file mode 100644 index 0000000..233bf4e --- /dev/null +++ b/subprojects/lib/src/file_hdf.c @@ -0,0 +1,162 @@ +/* + + File: file_hdf.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hdf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_HDF +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hdf(file_stat_t *file_stat); + +const file_hint_t file_hint_hdf= { + .extension="hdf", + .description="Hierarchical Data Format 4", + .max_filesize=PHOTOREC_MAX_SIZE_32, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_hdf +}; + +struct ddh_struct +{ + uint16_t size; + uint32_t next; +} __attribute__ ((gcc_struct, __packed__)); + +struct dd_struct +{ + uint16_t tag; + uint16_t ref; + uint32_t offset; + uint32_t length; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \separated(file_recovery, file_recovery->handle, &errno, &Frama_C_entropy_source, &__fc_heap_status); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +static void file_check_hdf(file_recovery_t *file_recovery) +{ + uint64_t file_size=0; + uint64_t offset_old; + uint64_t offset=4; + struct dd_struct *dd=(struct dd_struct *)MALLOC(sizeof(struct dd_struct)*65536); + do + { + struct ddh_struct ddh; + unsigned int i; + unsigned int size; + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 || + fread(&ddh, sizeof(ddh), 1, file_recovery->handle) !=1) + { + free(dd); + file_recovery->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&ddh, sizeof(ddh)); +#endif + size=be16(ddh.size); + if(size==0 || + fread(dd, sizeof(struct dd_struct)*size, 1, file_recovery->handle) !=1) + { + free(dd); + file_recovery->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(dd, sizeof(struct dd_struct)*size); +#endif + if(file_size < offset + sizeof(struct dd_struct) * size) + file_size = offset + sizeof(struct dd_struct) * size; +#ifdef DEBUG_HDF + log_info("size=%u next=%lu\n", size, be32(ddh.next)); +#endif + /*@ + @ loop assigns i, file_size; + @*/ + for(i=0; i < size; i++) + { + const struct dd_struct *p=&dd[i]; + const unsigned int p_offset=be32(p->offset); + const unsigned int p_length=be32(p->length); +#ifdef DEBUG_HDF + log_info("tag=0x%04x, ref=%u, offset=%lu, length=%lu\n", + be16(p->tag), be16(p->ref), p_offset, p_length); +#endif + if(p_offset!=0xffffffff && + file_size < (uint64_t)p_offset + (uint64_t)p_length) + file_size = (uint64_t)p_offset + (uint64_t)p_length; + } + offset_old=offset; + offset=be32(ddh.next); + } while(offset > offset_old); + free(dd); + file_size++; +#ifdef DEBUG_HDF + log_info("file_size %llu\n", (long long unsigned)file_size); +#endif + if(file_recovery->file_size < file_size) + file_recovery->file_size=0; + else + file_recovery->file_size = file_size; +} + +/*@ + @ requires buffer_size >= sizeof(struct ddh_struct); + @ requires separation: \separated(&file_hint_hdf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hdf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ddh_struct *ddh=(const struct ddh_struct *)&buffer[4]; + if(be16(ddh->size)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_hdf.extension; + file_recovery_new->file_check=&file_check_hdf; + return 1; +} + +static void register_header_check_hdf(file_stat_t *file_stat) +{ + static const unsigned char hdf_header[4]= { 0x0e, 0x03, 0x13, 0x01}; + register_header_check(0, hdf_header, sizeof(hdf_header), &header_check_hdf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_hdr.c b/subprojects/lib/src/file_hdr.c new file mode 100644 index 0000000..125d275 --- /dev/null +++ b/subprojects/lib/src/file_hdr.c @@ -0,0 +1,93 @@ +/* + + File: file_hdr.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hdr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hdr(file_stat_t *file_stat); + +const file_hint_t file_hint_hdr= { + .extension="hdr", + .description="InstallShield", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_hdr +}; + +struct hdr_header { + uint32_t magic; + uint16_t unk1; + uint16_t val0100; + uint32_t val00000000; + uint16_t val0200; + uint16_t val0000; + uint16_t unk2; /* 0 if cab */ + uint16_t val0000_bis; + uint32_t filesize; /* 0x200 if cab */ + uint32_t val00000000_bis; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct hdr_header); + @ requires separation: \separated(&file_hint_hdr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hdr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct hdr_header *hdr=(const struct hdr_header*)buffer; + const unsigned int filesize=le32(hdr->filesize); + if(le16(hdr->val0100)!=0x100) + return 0; + if(le32(hdr->val00000000)!=0) + return 0; + reset_file_recovery(file_recovery_new); + if(le16(hdr->unk2)==0 && filesize==0x200) + { + file_recovery_new->extension="cab"; + file_recovery_new->min_filesize=0x200; + return 1; + } + file_recovery_new->extension=file_hint_hdr.extension; + file_recovery_new->calculated_file_size=filesize; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_hdr(file_stat_t *file_stat) +{ + register_header_check(0, "ISc(", 4, &header_check_hdr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_hds.c b/subprojects/lib/src/file_hds.c new file mode 100644 index 0000000..ff003de --- /dev/null +++ b/subprojects/lib/src/file_hds.c @@ -0,0 +1,86 @@ +/* + + File: file_hds.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hds) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hds(file_stat_t *file_stat); + +const file_hint_t file_hint_hds= { + .extension="hds", + .description="Parallels disk image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_hds +}; + +// always little-endian +struct parallels_header { + char magic[16]; // "WithoutFreeSpace" + uint32_t version; + uint32_t heads; + uint32_t cylinders; + uint32_t tracks; + uint32_t catalog_entries; + uint32_t nb_sectors; + char padding[24]; +} __attribute__((gcc_struct,__packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct parallels_header); + @ requires separation: \separated(&file_hint_hds, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hds(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct parallels_header *hdr=(const struct parallels_header *)buffer; + if(le32(hdr->heads)==0 || + le32(hdr->cylinders)==0 || + le32(hdr->tracks)==0 || + le32(hdr->nb_sectors)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_hds.extension; + return 1; +} + +static void register_header_check_hds(file_stat_t *file_stat) +{ + static const unsigned char hds_header[20]= { + 'W','i','t','h','o','u','t','F','r','e','e','S','p','a','c','e', + 0x02, 0x00, 0x00, 0x00 + }; + register_header_check(0, hds_header,sizeof(hds_header), &header_check_hds, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_hfsp.c b/subprojects/lib/src/file_hfsp.c new file mode 100644 index 0000000..049448b --- /dev/null +++ b/subprojects/lib/src/file_hfsp.c @@ -0,0 +1,73 @@ +/* + + File: file_hfs.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hfsp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "hfsp_struct.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hfsp(file_stat_t *file_stat); + +const file_hint_t file_hint_hfsp= { + .extension="hfsp", + .description="HFS+/HFSX", + .max_filesize=2048, + .recover=0, + .enable_by_default=1, + .register_header_check=®ister_header_check_hfsp +}; + +/*@ + @ requires buffer_size >= sizeof(struct hfsp_vh); + @ requires separation: \separated(&file_hint_hfsp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hfsp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct hfsp_vh *vh=(const struct hfsp_vh *)buffer; + if (!(be32(vh->blocksize)%512==0 && be32(vh->blocksize)!=0 && be32(vh->free_blocks)<=be32(vh->total_blocks))) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_hfsp.extension; + return 1; +} + +static void register_header_check_hfsp(file_stat_t *file_stat) +{ + register_header_check(0, "H+\0\4", 4, &header_check_hfsp, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, "HX\0\5", 4, &header_check_hfsp, file_stat); +#endif +} + +#endif diff --git a/subprojects/lib/src/file_hm.c b/subprojects/lib/src/file_hm.c new file mode 100644 index 0000000..893a725 --- /dev/null +++ b/subprojects/lib/src/file_hm.c @@ -0,0 +1,68 @@ +/* + + File: file_hm.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hm(file_stat_t *file_stat); + +const file_hint_t file_hint_hm = { + .extension = "hm", + .description = "HyperMesh, structural analysis software", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_hm +}; + +/*@ + @ requires separation: \separated(&file_hint_hm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_hm.extension; + return 1; +} + +static void register_header_check_hm(file_stat_t *file_stat) +{ + static const unsigned char hm_header[23] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x40, 0x1f, 0x8b, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xed + }; + register_header_check(0, hm_header, sizeof(hm_header), &header_check_hm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_hr9.c b/subprojects/lib/src/file_hr9.c new file mode 100644 index 0000000..21517fd --- /dev/null +++ b/subprojects/lib/src/file_hr9.c @@ -0,0 +1,80 @@ +/* + + File: file_hr9.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hr9) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_hr9(file_stat_t *file_stat); + +const file_hint_t file_hint_hr9= { + .extension="hr9", + .description="Heredis - Genealogy", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_hr9 +}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_hr9(file_recovery_t *file_recovery) +{ + const unsigned char hr9_footer[4]= {0xc0, 0xde, 0xca, 0xfe}; + file_search_footer(file_recovery, hr9_footer, sizeof(hr9_footer), 0x50-4); +} + +/*@ + @ requires separation: \separated(&file_hint_hr9, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_hr9(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_hr9.extension; + file_recovery_new->file_check=&file_check_hr9; + return 1; +} + +static void register_header_check_hr9(file_stat_t *file_stat) +{ + static const unsigned char hr9_header[17]= { + 0xc0, 0xde, 0xca, 0xfe, 0x00, 0x00, 0x00, 0x00, + 'H', 'e', 'r', 'e', 'd', 'i', 's', 0x99, + 0x20 + }; + register_header_check(0, hr9_header,sizeof(hr9_header), &header_check_hr9, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_http.c b/subprojects/lib/src/file_http.c new file mode 100644 index 0000000..4cd79e3 --- /dev/null +++ b/subprojects/lib/src/file_http.c @@ -0,0 +1,63 @@ +/* + + File: file_http.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_http) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_http(file_stat_t *file_stat); + +const file_hint_t file_hint_http= { + .extension="http", + .description="HTTP Cache", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_http +}; + +/*@ + @ requires separation: \separated(&file_hint_http, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_http(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_http.extension; + return 1; +} + +static void register_header_check_http(file_stat_t *file_stat) +{ + register_header_check(0, "HTTP/1.1 200 OK\r\nDate:", 22, &header_check_http, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ibd.c b/subprojects/lib/src/file_ibd.c new file mode 100644 index 0000000..7bf32b0 --- /dev/null +++ b/subprojects/lib/src/file_ibd.c @@ -0,0 +1,120 @@ +/* + + File: file_ibd.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ibd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ibd(file_stat_t *file_stat); + +const file_hint_t file_hint_ibd= { + .extension="ibd", + .description="InnoDB database file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ibd +}; + +#define FSP_HEADER_OFFSET 38 +#define FSP_SPACE_FLAGS 16 /* fsp_space_t.flags, similar to dict_table_t::flags */ +#define FIL_PAGE_TYPE_FSP_HDR 8 /* File space header */ +#define DICT_TF_BITS 6 /* number of flag bits */ +#define DICT_TF_FORMAT_SHIFT 5 /* file format */ +#ifdef __FRAMAC__ +#define DICT_TF_FORMAT_MASK 0x20 +#else +#define DICT_TF_FORMAT_MASK \ + ((~(~0U << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT))) << DICT_TF_FORMAT_SHIFT) +#endif +#define DICT_TF_FORMAT_ZIP 1 /* InnoDB plugin for 5.1: compressed tables */ + +struct innodb_fil_header +{ + uint32_t space_or_chksum; + uint32_t offset; + uint32_t prev; + uint32_t next; + uint64_t lsn; + uint16_t type; + uint64_t file_flush_lsn; + uint32_t arch_log_no_or_space_id; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct innodb_fil_header); + @ requires buffer_size > FSP_HEADER_OFFSET + FSP_SPACE_FLAGS; + @ requires separation: \separated(&file_hint_ibd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ibd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct innodb_fil_header *hdr=(const struct innodb_fil_header *)buffer; + const uint32_t *flags_ptr=(const uint32_t *)&buffer[FSP_HEADER_OFFSET + FSP_SPACE_FLAGS]; + const uint32_t flags=be32(*flags_ptr); + if(be16(hdr->type)==0) + { + /* Antelope (pre-5.1.7) */ + if(flags==0) + return 0; + } + else if(be16(hdr->type)==FIL_PAGE_TYPE_FSP_HDR) + { + const unsigned int format = (flags & DICT_TF_FORMAT_MASK) >> DICT_TF_FORMAT_SHIFT; + if(flags==0) + { + /* Antelope (5.1.7 or newer) */ + } + else if(format==DICT_TF_FORMAT_ZIP) + { + /* Barracuda */ + } + else + return 0; + } + else + return 0; + if(buffer_size >= 0xc078 && memcmp(&buffer[0xc070], "supremum", 8)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ibd.extension; + file_recovery_new->min_filesize=0xc078; + return 1; +} + +static void register_header_check_ibd(file_stat_t *file_stat) +{ + register_header_check(0xc063, "infimum", 7, &header_check_ibd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_icc.c b/subprojects/lib/src/file_icc.c new file mode 100644 index 0000000..45e580b --- /dev/null +++ b/subprojects/lib/src/file_icc.c @@ -0,0 +1,78 @@ +/* + + File: file_icc.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_icc) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_icc(file_stat_t *file_stat); + +const file_hint_t file_hint_icc= { + .extension="icc", + .description="Color profiles", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_icc +}; + +/*@ + @ requires buffer_size >= 128; + @ requires separation: \separated(&file_hint_icc, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_icc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t file_size=(((uint64_t)buffer[0])<<24) + + (((uint64_t)buffer[1])<<16) + (((uint64_t)buffer[2])<<8) + (uint64_t)buffer[3]; + unsigned int i; + if(file_size<128 || buffer[10]!=0 || buffer[11]!=0) + return 0; + /*@ loop assigns i; */ + for(i=100; i<128; i++) + if(buffer[i]!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_icc.extension; + file_recovery_new->calculated_file_size=file_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/* http://www.npes.org/ICC/ICC1-V41_ForPublicReview.pdf */ + +static void register_header_check_icc(file_stat_t *file_stat) +{ + static const unsigned char icc_header[4]= { 'a', 'c', 's', 'p' }; + register_header_check(36, icc_header,sizeof(icc_header), &header_check_icc, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_icns.c b/subprojects/lib/src/file_icns.c new file mode 100644 index 0000000..4107c7f --- /dev/null +++ b/subprojects/lib/src/file_icns.c @@ -0,0 +1,138 @@ +/* + + File: file_icns.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_icns) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_icns(file_stat_t *file_stat); + +const file_hint_t file_hint_icns= { + .extension="icns", + .description="Apple Icon Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_icns +}; + +struct icns_header +{ + uint32_t magic; + uint32_t size; +}; + +struct icon_data +{ + char type[4]; + uint32_t size; +// uint8_t data[0]; +}; + +/*@ + @ requires \valid_read(type + (0 .. 3)); + @ assigns \nothing; + @*/ +static int check_icon_type(const char *type) +{ + /* https://en.wikipedia.org/wiki/Apple_Icon_Image_format */ + if(memcmp(type, "ICON", 4)==0 || + memcmp(type, "ICN#", 4)==0 || + memcmp(type, "icm#", 4)==0 || + memcmp(type, "icm4", 4)==0 || + memcmp(type, "icm8", 4)==0 || + memcmp(type, "ics#", 4)==0 || + memcmp(type, "ics4", 4)==0 || + memcmp(type, "ics8", 4)==0 || + memcmp(type, "is32", 4)==0 || + memcmp(type, "s8mk", 4)==0 || + memcmp(type, "icl4", 4)==0 || + memcmp(type, "icl8", 4)==0 || + memcmp(type, "il32", 4)==0 || + memcmp(type, "l8mk", 4)==0 || + memcmp(type, "ich#", 4)==0 || + memcmp(type, "ich4", 4)==0 || + memcmp(type, "ich8", 4)==0 || + memcmp(type, "ih32", 4)==0 || + memcmp(type, "h8mk", 4)==0 || + memcmp(type, "it32", 4)==0 || + memcmp(type, "t8mk", 4)==0 || + memcmp(type, "icp4", 4)==0 || + memcmp(type, "icp5", 4)==0 || + memcmp(type, "icp6", 4)==0 || + memcmp(type, "ic07", 4)==0 || + memcmp(type, "ic08", 4)==0 || + memcmp(type, "ic09", 4)==0 || + memcmp(type, "ic10", 4)==0 || + memcmp(type, "ic11", 4)==0 || + memcmp(type, "ic12", 4)==0 || + memcmp(type, "ic13", 4)==0 || + memcmp(type, "ic14", 4)==0 || + memcmp(type, "TOC ", 4)==0 || + memcmp(type, "icnV", 4)==0) + return 1; + return 0; +} + +/*@ + @ requires buffer_size >= sizeof(struct icns_header) + sizeof(struct icon_data); + @ requires separation: \separated(&file_hint_icns, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_icns(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct icns_header *hdr=(const struct icns_header *)buffer; + const struct icon_data *icon=(const struct icon_data *)&buffer[8]; + const unsigned int hdr_size=be32(hdr->size); + const unsigned int icon_size=be32(icon->size); + if(hdr_size < sizeof(struct icns_header)) + return 0; + if(icon_size < sizeof(struct icon_data)) + return 0; + if(icon_size > hdr_size - 8) + return 0; + if(!check_icon_type(icon->type)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_icns.extension; + file_recovery_new->calculated_file_size=hdr_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_icns(file_stat_t *file_stat) +{ + register_header_check(0, "icns", 4, &header_check_icns, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ico.c b/subprojects/lib/src/file_ico.c new file mode 100644 index 0000000..1ac1583 --- /dev/null +++ b/subprojects/lib/src/file_ico.c @@ -0,0 +1,172 @@ +/* + + File: file_ico.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ico) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ico(file_stat_t *file_stat); + +const file_hint_t file_hint_ico= { + .extension="ico", + .description="Windows Icon", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ico +}; + +static const unsigned char header_ico1[6]= {0x00 , 0x00, 0x01, 0x00, 0x01, 0x00}; +static const unsigned char header_ico2[6]= {0x00 , 0x00, 0x01, 0x00, 0x02, 0x00}; +static const unsigned char header_ico3[6]= {0x00 , 0x00, 0x01, 0x00, 0x03, 0x00}; +static const unsigned char header_ico4[6]= {0x00 , 0x00, 0x01, 0x00, 0x04, 0x00}; +static const unsigned char header_ico5[6]= {0x00 , 0x00, 0x01, 0x00, 0x05, 0x00}; +static const unsigned char header_ico6[6]= {0x00 , 0x00, 0x01, 0x00, 0x06, 0x00}; +static const unsigned char header_ico7[6]= {0x00 , 0x00, 0x01, 0x00, 0x07, 0x00}; +static const unsigned char header_ico8[6]= {0x00 , 0x00, 0x01, 0x00, 0x08, 0x00}; +static const unsigned char header_ico9[6]= {0x00 , 0x00, 0x01, 0x00, 0x09, 0x00}; + +/* + * http://en.wikipedia.org/wiki/ICO_(icon_image_file_format) + */ + +struct ico_header +{ + uint16_t reserved; + uint16_t type; + uint16_t count; +} __attribute__ ((gcc_struct, __packed__)); + +struct ico_directory +{ + uint8_t width; + uint8_t heigth; + uint8_t color_count; + uint8_t reserved; + uint16_t color_planes; + uint16_t bits_per_pixel; + uint32_t bitmap_size; + uint32_t bitmap_offset; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct ico_header); + @ requires separation: \separated(&file_hint_ico, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ico(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ico_header *ico=(const struct ico_header*)buffer; + const struct ico_directory *ico_dir; + unsigned int i; + uint64_t fs=0; +#ifdef DEBUG_ICO + log_info("ICO: reserved=%u type=%u count=%u\n", le16(ico->reserved), le16(ico->type), le16(ico->count)); +#endif + if(le16(ico->reserved)!=0 || le16(ico->type)!=1 || le16(ico->count)==0) + return 0; + /*@ + @ loop assigns ico_dir, i, fs; + @*/ + for(i=0, ico_dir=(const struct ico_directory*)(ico+1); + (const unsigned char *)(ico_dir+1) <= buffer+buffer_size && icount); + i++, ico_dir++) + { +#ifdef DEBUG_ICO + log_info("ICO%u: reserved=%u color_planes=%u width=%u heigth=%u bps=%u offset=%u size=%u\n", + i, ico_dir->reserved, le16(ico_dir->color_planes), ico_dir->width, ico_dir->heigth, le16(ico_dir->bits_per_pixel), + le32(ico_dir->bitmap_offset), le32(ico_dir->bitmap_size)); +#endif + if(ico_dir->reserved!=0 && ico_dir->reserved!=255) + return 0; + if(le16(ico_dir->color_planes)>1) + return 0; + if(ico_dir->width!=ico_dir->heigth) + return 0; /* Reject non square icon */ + switch(ico_dir->width) + { + case 16: + case 24: + case 32: + case 48: + case 64: + case 128: + case 0: /* 256 */ + break; + default: + return 0; + } + switch(le16(ico_dir->bits_per_pixel)) + { + case 0: + case 1: + case 4: + case 8: + case 16: + case 24: + case 32: + break; + default: + return 0; + } + if(le32(ico_dir->bitmap_size)==0) + return 0; + if(le32(ico_dir->bitmap_offset) < sizeof(struct ico_header)+le16(ico->count)*sizeof(struct ico_directory)) + return 0; + if(fs < (uint64_t)le32(ico_dir->bitmap_size) + le32(ico_dir->bitmap_offset)) + fs=(uint64_t)le32(ico_dir->bitmap_size) + le32(ico_dir->bitmap_offset); + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ico.extension; + file_recovery_new->calculated_file_size=fs; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_ico(file_stat_t *file_stat) +{ + register_header_check(0, header_ico1, sizeof(header_ico1), &header_check_ico, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, header_ico2, sizeof(header_ico2), &header_check_ico, file_stat); + register_header_check(0, header_ico3, sizeof(header_ico3), &header_check_ico, file_stat); + register_header_check(0, header_ico4, sizeof(header_ico4), &header_check_ico, file_stat); + register_header_check(0, header_ico5, sizeof(header_ico5), &header_check_ico, file_stat); + register_header_check(0, header_ico6, sizeof(header_ico6), &header_check_ico, file_stat); + register_header_check(0, header_ico7, sizeof(header_ico7), &header_check_ico, file_stat); + register_header_check(0, header_ico8, sizeof(header_ico8), &header_check_ico, file_stat); + register_header_check(0, header_ico9, sizeof(header_ico9), &header_check_ico, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_idx.c b/subprojects/lib/src/file_idx.c new file mode 100644 index 0000000..8e59e53 --- /dev/null +++ b/subprojects/lib/src/file_idx.c @@ -0,0 +1,91 @@ +/* + + File: file_idx.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_idx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_idx(file_stat_t *file_stat); + +const file_hint_t file_hint_idx= { + .extension="idx", + .description="RT60", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_idx +}; + +/*@ + @ requires file_recovery->data_check==&data_check_idx; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_idx(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4; */ + if(memcmp(&buffer[i], "RT60", 4)!=0) + return DC_STOP; + file_recovery->calculated_file_size+=0x30; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 0x22; + @ requires separation: \separated(&file_hint_idx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_idx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x18], "RT60", 4)!=0) + return 0; + if(file_recovery->data_check==&data_check_idx) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_idx.extension; + file_recovery_new->data_check=&data_check_idx; + file_recovery_new->min_filesize=0x30; + return 1; +} + +static void register_header_check_idx(file_stat_t *file_stat) +{ + register_header_check(0, "RT60", 4, &header_check_idx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ifo.c b/subprojects/lib/src/file_ifo.c new file mode 100644 index 0000000..0874895 --- /dev/null +++ b/subprojects/lib/src/file_ifo.c @@ -0,0 +1,81 @@ +/* + + File: file_ifo.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ifo) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ifo(file_stat_t *file_stat); + +const file_hint_t file_hint_ifo= { + .extension="ifo", + .description="DVD Video manager or title set", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ifo +}; + +struct ifo_hdr +{ + char name[12]; + uint32_t ls_BUP[4]; + uint32_t ls_IFO; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct ifo_hdr); + @ requires separation: \separated(&file_hint_ifo, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ifo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ifo_hdr *hdr=(const struct ifo_hdr *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ifo.extension; + file_recovery_new->calculated_file_size=((uint64_t)be32(hdr->ls_IFO)+1)*2048; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_ifo(file_stat_t *file_stat) +{ + static const unsigned char ifo_header_vmg[12]= { 'D', 'V', 'D', 'V', 'I', 'D', 'E', 'O', '-', 'V', 'M', 'G'}; + static const unsigned char ifo_header_vts[12]= { 'D', 'V', 'D', 'V', 'I', 'D', 'E', 'O', '-', 'V', 'T', 'S'}; + register_header_check(0, ifo_header_vmg, sizeof(ifo_header_vmg), &header_check_ifo, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, ifo_header_vts, sizeof(ifo_header_vts), &header_check_ifo, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_imb.c b/subprojects/lib/src/file_imb.c new file mode 100644 index 0000000..6f2d947 --- /dev/null +++ b/subprojects/lib/src/file_imb.c @@ -0,0 +1,65 @@ +/* + + File: file_imb.c + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_imb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_imb(file_stat_t *file_stat); + +const file_hint_t file_hint_imb= { + .extension="imb", + .description="Incredimail", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_imb +}; + +/*@ + @ requires separation: \separated(&file_hint_imb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_imb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_imb.extension; + file_recovery_new->min_filesize=16; + return 1; +} + +static void register_header_check_imb(file_stat_t *file_stat) +{ + static const unsigned char imb_header[15]= { 0x00, 0x00, 0x00, 'I','n','c','r','e','d','i','m','a','i','l',' '}; + register_header_check(1, imb_header,sizeof(imb_header), &header_check_imb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_indd.c b/subprojects/lib/src/file_indd.c new file mode 100644 index 0000000..0e1d019 --- /dev/null +++ b/subprojects/lib/src/file_indd.c @@ -0,0 +1,182 @@ +/* + + File: file_indd.c + + Copyright (C) 2007 Christophe GRENIER + Copyright (C) 2007 Peter Turczak + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_indd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_indd(file_stat_t *file_stat); + +const file_hint_t file_hint_indd= { + .extension="indd", + .description="InDesign File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_indd +}; + +/* See http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/cs6/XMPSpecificationPart3.pdf + * for more information about the file format */ + +// Headers are: DE393979-5188-4b6c-8E63-EEF8AEE0DD38 +// Trailers are: FDCEDB70-F786-4b4f-A4D3-C728B3417106 +static const unsigned char kINDDContigObjHeaderGUID [16] = +{ 0xDE, 0x39, 0x39, 0x79, 0x51, 0x88, 0x4B, 0x6C, 0x8E, 0x63, 0xEE, 0xF8, 0xAE, 0xE0, 0xDD, 0x38 }; + +struct InDesignMasterPage { + uint8_t fGUID [16]; + uint8_t fMagicBytes [8]; + uint8_t fObjectStreamEndian; + uint8_t fIrrelevant1 [239]; + uint64_t fSequenceNumber; + uint8_t fIrrelevant2 [8]; + uint32_t fFilePages; + uint8_t fIrrelevant3 [3812]; +} __attribute__ ((gcc_struct, __packed__)); + +struct InDesignContigObjMarker { + uint8_t fGUID [16]; + uint32_t fObjectUID; + uint32_t fObjectClassID; + uint32_t fStreamLength; + uint32_t fChecksum; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_indd; + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_indd(file_recovery_t *file_recovery) +{ + const uint64_t file_size_org=file_recovery->file_size; + uint64_t offset; + if(file_recovery->file_sizecalculated_file_size) + { + file_recovery->file_size=0; + return ; + } + offset=file_recovery->calculated_file_size; + /*@ + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source; + @ loop assigns offset; + @*/ + do + { + char buffer[sizeof(struct InDesignContigObjMarker)]; + const struct InDesignContigObjMarker *hdr=(const struct InDesignContigObjMarker *)&buffer;; +#ifdef DEBUG_INDD + log_info("file_check_indd offset=%llu (0x%llx)\n", (long long unsigned)offset, (long long unsigned)offset); +#endif + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0) + { + file_recovery->file_size=0; + return ; + } + if(fread(buffer, sizeof(buffer), 1, file_recovery->handle) != 1) + { + file_recovery->file_size=(offset+4096-1)/4096*4096; + if(file_recovery->file_size>file_size_org) + file_recovery->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + if(memcmp(hdr->fGUID, kINDDContigObjHeaderGUID, sizeof(kINDDContigObjHeaderGUID))!=0) + { + file_recovery->file_size=(offset+4096-1)/4096*4096; + if(file_recovery->file_size>file_size_org) + file_recovery->file_size=0; + return ; + } + /* header + data + trailer */ + offset+=(uint64_t)le32(hdr->fStreamLength)+2*sizeof(struct InDesignContigObjMarker); + } while(offset < file_size_org); + file_recovery->file_size=(offset+4096-1)/4096*4096; + if(file_recovery->file_size>file_size_org) + file_recovery->file_size=0; + return ; +} + +/*@ + @ requires buffer_size >= 4096 + sizeof(struct InDesignMasterPage); + @ requires separation: \separated(&file_hint_indd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_indd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct InDesignMasterPage *hdr; + const struct InDesignMasterPage *hdr0 = (const struct InDesignMasterPage *)buffer; + const struct InDesignMasterPage *hdr1 = (const struct InDesignMasterPage *)&buffer[4096]; + hdr=(le64(hdr0->fSequenceNumber) > le64(hdr1->fSequenceNumber) ? hdr0 : hdr1); + if(hdr->fObjectStreamEndian!=1 && hdr->fObjectStreamEndian!=2) + return 0; + if(le32(hdr->fFilePages)==0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_indd) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="ind"; +#else + file_recovery_new->extension=file_hint_indd.extension; +#endif + /* Contiguous object pages may follow, file_check_indd will search for them */ + file_recovery_new->calculated_file_size=(uint64_t)(le32(hdr->fFilePages))*4096; + file_recovery_new->file_check=&file_check_indd; +#ifdef DEBUG_INDD + log_info("header_check_indd: Guessed length: %llu.\n", (long long unsigned)file_recovery_new->calculated_file_size); +#endif + return 1; +} + +static void register_header_check_indd(file_stat_t *file_stat) +{ + static const unsigned char indd_header[24]={ + 0x06, 0x06, 0xed, 0xf5, 0xd8, 0x1d, 0x46, 0xe5, + 0xbd, 0x31, 0xef, 0xe7, 0xfe, 0x74, 0xb7, 0x1d, + 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54 }; + register_header_check(0, indd_header,sizeof(indd_header), &header_check_indd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_info.c b/subprojects/lib/src/file_info.c new file mode 100644 index 0000000..d48a236 --- /dev/null +++ b/subprojects/lib/src/file_info.c @@ -0,0 +1,68 @@ +/* + + File: file_info.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_info) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_info(file_stat_t *file_stat); + +const file_hint_t file_hint_info= { + .extension="info", + .description="ZoomBrowser Thumbnail info", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_info +}; + +/*@ + @ requires separation: \separated(&file_hint_info, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_info(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_info.extension; + return 1; +} + +static void register_header_check_info(file_stat_t *file_stat) +{ + static const unsigned char info_header[20]= { + 'z' , 'b' , 'e' , 'x' , 0x04, 0x00, 0x00, 'L' , + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00 + }; + register_header_check(0, info_header, sizeof(info_header), &header_check_info, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_iso.c b/subprojects/lib/src/file_iso.c new file mode 100644 index 0000000..6bf79b7 --- /dev/null +++ b/subprojects/lib/src/file_iso.c @@ -0,0 +1,89 @@ +/* + + File: file_iso.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_iso) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "iso9660.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_iso(file_stat_t *file_stat); + +const file_hint_t file_hint_iso= { + .extension="iso", + .description="ISO", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_iso +}; + +/*@ + @ requires separation: \separated(&file_hint_iso, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_iso(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer_size<0x8000+512) /* +2048 for the full mapping */ + return 0; + { + const struct iso_primary_descriptor *iso1=(const struct iso_primary_descriptor*)&buffer[0x8000]; + const unsigned int volume_space_size_le=le32(iso1->volume_space_size_le); + const unsigned int volume_space_size_be=be32(iso1->volume_space_size_be); + const unsigned int logical_block_size_le=le16(iso1->logical_block_size_le); + const unsigned int logical_block_size_be=be16(iso1->logical_block_size_be); + if(volume_space_size_le==volume_space_size_be && logical_block_size_le==logical_block_size_be) + { /* ISO 9660 */ + const uint64_t size=(uint64_t)volume_space_size_le * logical_block_size_le; + if(size < 0x8000+512) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_iso.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->min_filesize=0x8000+512; + return 1; + } + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_iso.extension; + file_recovery_new->min_filesize=0x8000+512; + return 1; +} + +static void register_header_check_iso(file_stat_t *file_stat) +{ + static const unsigned char iso_header[6]= { 0x01, 'C', 'D', '0', '0', '1'}; + register_header_check(0x8000, iso_header,sizeof(iso_header), &header_check_iso, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_it.c b/subprojects/lib/src/file_it.c new file mode 100644 index 0000000..c8d9bbc --- /dev/null +++ b/subprojects/lib/src/file_it.c @@ -0,0 +1,94 @@ +/* + + File: file_it.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_it) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_it(file_stat_t *file_stat); + +const file_hint_t file_hint_it= { + .extension="it", + .description="Impulse Tracker", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_it +}; + +/* https://github.com/schismtracker/schismtracker/wiki/ITTECH.TXT */ +struct impulse_header +{ + uint32_t magic; + char song_name[26]; + uint16_t PHiligt; + uint16_t OrdNum; + uint16_t InsNum; + uint16_t SmpNum; + uint16_t PatNum; + uint16_t Cwtv; + uint16_t Cmwt; + uint16_t Flags; + uint16_t Special; + uint8_t GV; + uint8_t MV; + uint8_t IS; + uint8_t IT; + uint8_t Sep; + uint8_t PWD; + uint16_t MsgLgth; + uint16_t MsgOff; + uint32_t Reserved; + char Chnl_Pan[64]; + char Chnl_Vol[64]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct impulse_header); + @ requires separation: \separated(&file_hint_it, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_it(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct impulse_header *header=(const struct impulse_header *)buffer; + if(header->Reserved!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_it.extension; + return 1; +} + +static void register_header_check_it(file_stat_t *file_stat) +{ + register_header_check(0, "IMPM", 4, &header_check_it, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_itu.c b/subprojects/lib/src/file_itu.c new file mode 100644 index 0000000..234e85e --- /dev/null +++ b/subprojects/lib/src/file_itu.c @@ -0,0 +1,74 @@ +/* + + File: file_itu.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_itunes) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_itunes(file_stat_t *file_stat); + +const file_hint_t file_hint_itunes= { + .extension="itu", + .description="iTunes", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_itunes +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_itunes, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_itunes(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size= (uint64_t)buffer[8] + + (((uint64_t)buffer[9])<<8) + (((uint64_t)buffer[10])<<16) + (((uint64_t)buffer[11])<<24); + if(size < 0x68) + return 0; + /* mhbd */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_itunes.extension; + file_recovery_new->min_filesize=0x68; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_itunes(file_stat_t *file_stat) +{ + static const unsigned char itunes_header[8]= {'m', 'h', 'b', 'd', 0x68, 0x00, 0x00, 0x00}; + register_header_check(0, itunes_header,sizeof(itunes_header), &header_check_itunes, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_jks.c b/subprojects/lib/src/file_jks.c new file mode 100644 index 0000000..a49f39c --- /dev/null +++ b/subprojects/lib/src/file_jks.c @@ -0,0 +1,80 @@ +/* + + File: file_jks.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jks) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_jks(file_stat_t *file_stat); + +const file_hint_t file_hint_jks= { + .extension="jks", + .description="Java Keystore", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_jks +}; + +/* http://metastatic.org/source/JKS.java */ +struct jks_header +{ + uint32_t magic; + uint32_t version; + uint32_t nbr_of_entries; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct jks_header); + @ requires separation: \separated(&file_hint_jks, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_jks(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct jks_header *hdr=(const struct jks_header *)buffer; + if(be32(hdr->nbr_of_entries)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_jks.extension; + file_recovery_new->min_filesize=sizeof(struct jks_header)+4+2+8; + return 1; +} + +static void register_header_check_jks(file_stat_t *file_stat) +{ + static const unsigned char jks_header[8]= { + 0xfe, 0xed, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x02, + }; + register_header_check(0, jks_header, sizeof(jks_header), &header_check_jks, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_jpg.c b/subprojects/lib/src/file_jpg.c new file mode 100644 index 0000000..2117605 --- /dev/null +++ b/subprojects/lib/src/file_jpg.c @@ -0,0 +1,2860 @@ +/* + + File: file_jpg.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) || defined(SINGLE_FORMAT) || defined(MAIN_fidentify) +#undef HAVE_LIBJPEG +#undef DEBUG_JPEG +#undef HAVE_JPEGLIB_H +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include "types.h" +#ifdef HAVE_SETJMP_H +#include +#endif +#ifdef HAVE_JPEGLIB_H +#include +#include "suspend.h" +#endif +#include /* isprint */ +#include "filegen.h" +#include "common.h" +#include "log.h" +#include "file_jpg.h" +#if !defined(MAIN_jpg) && !defined(SINGLE_FORMAT) +#include "file_riff.h" +#endif +#include "file_tiff.h" +#include "setdate.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#if !defined(MAIN_jpg) && !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_doc; +extern const file_hint_t file_hint_indd; +extern const file_hint_t file_hint_mov; +extern const file_hint_t file_hint_riff; +extern const file_hint_t file_hint_rw2; +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_jpg(file_stat_t *file_stat); +static void file_check_jpg(file_recovery_t *file_recovery); +static data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); + +/*@ + @ requires i < buffer_size; + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ assigns \nothing; + @*/ +static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned i, const unsigned int size); + +const file_hint_t file_hint_jpg= { + .extension="jpg", + .description="JPG picture", + .max_filesize=50*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_jpg +}; + +/*@ + @ requires \valid_read(buffer + (0 .. buffer_size-1)); + @ requires \valid(height); + @ requires \valid(width); + @ requires \separated(buffer, height, width); + @ assigns *height, *width; + @*/ +static void jpg_get_size(const unsigned char *buffer, const unsigned int buffer_size, unsigned int *height, unsigned int *width) +{ + unsigned int i=2; + /*@ loop assigns i, *height, *width; */ + while(i+8= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ requires mpo_offset <= PHOTOREC_MAX_FILE_SIZE; + @ requires separation: \separated(handle, &errno, &Frama_C_entropy_source, mpo + (..)); + @ assigns *handle, errno; + @ assigns Frama_C_entropy_source; + @*/ +static uint64_t file_check_mpo_be(FILE *handle, const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size) +{ + const uint16_t *tmp16; + const uint32_t *tmp32=(const uint32_t *)(&mpo[4]); + unsigned int offset=be32(*tmp32); + unsigned int i; + unsigned int nbr; + unsigned int NumberOfImages=0; + unsigned int MPEntry_offset=0; + uint64_t max_offset=0; +#ifdef DEBUG_JPEG + log_info("file_check_mpo_be\n"); +#endif + if(offset >= size - 2) + return 0; + /*@ assert offset < size - 2; */ + tmp16=(const uint16_t*)(&mpo[offset]); + nbr=be16(*tmp16); + offset+=2; + /* @offset: MP Index Fields*/ + if(offset + nbr * 12 > size) + return 0; + /*@ assert offset + nbr * 12 <= size; */ + /*@ + @ loop invariant 0 <= i <= nbr; + @ loop assigns i, NumberOfImages, MPEntry_offset; + @ loop variant nbr-i; + @*/ + for(i=0; i< nbr; i++) + { + /*@ assert 0 <= i < nbr; */ + const unsigned char *field_ptr=&mpo[offset + i * 12]; + /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */ + const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr; + const unsigned int count=be32(field->count); + const unsigned int type=be16(field->type); + switch(be16(field->tag)) + { + case 0xb000: + /* MPFVersion, type must be undefined */ + if(type!=7 || count!=4) + return 0; + break; + case 0xb001: + /* NumberOfImages, type must be long */ + if(type!=4 || count!=1) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + NumberOfImages=be32(*tmp); + if(NumberOfImages >= 0x100000) + return 0; + /*@ assert NumberOfImages < 0x100000; */ + } + break; + case 0xb002: + /* MPEntry, type must be undefined */ + if(type!=7 || count!=sizeof(struct MP_Entry)*NumberOfImages) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + MPEntry_offset=be32(*tmp); + } + break; + } + } +#ifdef DEBUG_JPEG + log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages); +#endif + /*@ assert NumberOfImages < 0x100000; */ + if(MPEntry_offset > size) + return 0; + if(MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages > size) + return 0; + /*@ assert MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages <= size; */ + /*@ + @ loop invariant 0 <= i <= NumberOfImages; + @ loop assigns i, max_offset, *handle, errno; + @ loop assigns Frama_C_entropy_source; + @ loop variant NumberOfImages-i; + @*/ + for(i=0; ioffset); +#ifdef DEBUG_JPEG + log_info("offset=%lu, size=%lu\n", + (long unsigned)be32(MPEntry->offset), + (long unsigned)be32(MPEntry->size)); +#endif + if(tmp>0) + tmp+=mpo_offset; + if(my_fseek(handle, tmp, SEEK_SET) < 0 || + fread(buffer, sizeof(buffer), 1, handle) != 1) + return 0; + tmp+=be32(MPEntry->size); +#ifdef __FRAMAC__ + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + if(memcmp(buffer, jpg_header, sizeof(jpg_header))!=0) + return 0; + if(max_offset < tmp) + max_offset = tmp; + } + return max_offset; +} + +/*@ + @ requires \valid(handle); + @ requires size >= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ requires mpo_offset <= PHOTOREC_MAX_FILE_SIZE; + @ requires separation: \separated(handle, &errno, &Frama_C_entropy_source, mpo + (..)); + @ assigns *handle, errno; + @ assigns Frama_C_entropy_source; + @*/ +static uint64_t file_check_mpo_le(FILE *handle, const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size) +{ + const uint16_t *tmp16; + /* Offset to first IFD */ + const uint32_t *tmp32=(const uint32_t *)(&mpo[4]); + unsigned int offset=le32(*tmp32); + unsigned int i; + unsigned int nbr; + unsigned int NumberOfImages=0; + unsigned int MPEntry_offset=0; + uint64_t max_offset=0; +#ifdef DEBUG_JPEG + log_info("file_check_mpo_le\n"); +#endif + if(offset >= size - 2) + return 0; + /*@ assert offset < size - 2; */ + tmp16=(const uint16_t*)(&mpo[offset]); + nbr=le16(*tmp16); + offset+=2; + /* @offset: MP Index Fields*/ + if(offset + nbr * 12 > size) + return 0; + /*@ assert offset + nbr * 12 <= size; */ + /*@ + @ loop invariant 0 <= i <= nbr; + @ loop assigns i, NumberOfImages, MPEntry_offset; + @ loop variant nbr-i; + @*/ + for(i=0; i< nbr; i++) + { + /*@ assert 0 <= i < nbr; */ + const unsigned char *field_ptr=&mpo[offset + i * 12]; + /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */ + const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr; + /*@ assert \valid_read(field); */ + const unsigned int count=le32(field->count); + const unsigned int type=le16(field->type); + switch(le16(field->tag)) + { + case 0xb000: + /* MPFVersion, type must be undefined */ + if(type!=7 || count!=4) + return 0; + break; + case 0xb001: + /* NumberOfImages, type must be long */ + if(type!=4 || count!=1) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + NumberOfImages=le32(*tmp); + if(NumberOfImages >= 0x100000) + return 0; + /*@ assert NumberOfImages < 0x100000; */ + } + break; + case 0xb002: + /* MPEntry, type must be undefined */ + if(type!=7 || count!=sizeof(struct MP_Entry)*NumberOfImages) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + MPEntry_offset=le32(*tmp); + } + break; + } + } +#ifdef DEBUG_JPEG + log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages); +#endif + /*@ assert NumberOfImages < 0x100000; */ + if(NumberOfImages == 0) + return 0; + /*@ assert 0 < NumberOfImages < 0x100000; */ + if(MPEntry_offset >= size) + return 0; + /*@ assert size > MPEntry_offset; */ + if(MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages > size) + return 0; + /*@ assert MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages <= size; */ + /*@ + @ loop invariant 0 <= i <= NumberOfImages; + @ loop assigns i, max_offset, *handle, errno; + @ loop assigns Frama_C_entropy_source; + @ loop variant NumberOfImages-i; + @*/ + for(i=0; ioffset); +#ifdef DEBUG_JPEG + log_info("mpo_offset=%lu offset=%lu, size=%lu\n", + (long unsigned)mpo_offset, + (long unsigned)le32(MPEntry->offset), + (long unsigned)le32(MPEntry->size)); +#endif + if(tmp>0) + tmp+=mpo_offset; + if(my_fseek(handle, tmp, SEEK_SET) < 0 || + fread(buffer, sizeof(buffer), 1, handle) != 1) + return 0; + tmp+=le32(MPEntry->size); +#ifdef __FRAMAC__ + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + if(memcmp(buffer, jpg_header, sizeof(jpg_header))!=0) + return 0; + if(max_offset < tmp) + max_offset = tmp; + } + return max_offset; +} + +/*@ + @ requires size >= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ assigns \nothing; + @*/ +static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size) +{ + const uint16_t *tmp16; + const uint32_t *tmp32=(const uint32_t *)(&mpo[4]); + unsigned int offset=be32(*tmp32); + unsigned int i; + unsigned int nbr; + unsigned int NumberOfImages=0; + unsigned int MPEntry_offset=0; + uint64_t max_offset=0; +#ifdef DEBUG_JPEG + log_info("check_mpo_be\n"); +#endif + if(offset >= size - 2) + return 0; + /*@ assert offset < size - 2; */ + tmp16=(const uint16_t*)(&mpo[offset]); + nbr=be16(*tmp16); + offset+=2; + /* @offset: MP Index Fields*/ + if(offset + nbr * 12 > size) + return 0; + /*@ assert offset + nbr * 12 <= size; */ + /*@ + @ loop invariant 0 <= i <= nbr; + @ loop assigns i, NumberOfImages, MPEntry_offset; + @ loop variant nbr-i; + @*/ + for(i=0; i< nbr; i++) + { + /*@ assert 0 <= i < nbr; */ + const unsigned char *field_ptr=&mpo[offset + i * 12]; + /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */ + const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr; + const unsigned int count=be32(field->count); + const unsigned int type=be16(field->type); + switch(be16(field->tag)) + { + case 0xb000: + /* MPFVersion, type must be undefined */ + if(type!=7 || count!=4) + return 0; + break; + case 0xb001: + /* NumberOfImages, type must be long */ + if(type!=4 || count!=1) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + NumberOfImages=be32(*tmp); + if(NumberOfImages >= 0x100000) + return 0; + /*@ assert NumberOfImages < 0x100000; */ + } + break; + case 0xb002: + /* MPEntry, type must be undefined */ + if(type!=7 || count!=sizeof(struct MP_Entry)*NumberOfImages) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + MPEntry_offset=be32(*tmp); + } + break; + } + } +#ifdef DEBUG_JPEG + log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages); +#endif + /*@ assert NumberOfImages < 0x100000; */ + if(NumberOfImages == 0) + return 0; + if(MPEntry_offset > size) + return 0; + if(MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages > size) + return 0; + /*@ + @ loop invariant 0 <= i <= NumberOfImages; + @ loop assigns i, max_offset; + @ loop variant NumberOfImages-i; + @*/ + for(i=0; isize); +#ifdef DEBUG_JPEG + log_info("offset=%lu, size=%lu\n", + (long unsigned)be32(MPEntry->offset), + (long unsigned)be32(MPEntry->size)); +#endif + if(be32(MPEntry->offset)>0) + tmp+=(uint64_t)be32(MPEntry->offset)+mpo_offset; + if(max_offset < tmp) + max_offset = tmp; + } + return max_offset; +} + +/*@ + @ requires size >= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ assigns \nothing; + @*/ +static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size) +{ + const uint16_t *tmp16; + /* Offset to first IFD */ + const uint32_t *tmp32=(const uint32_t *)(&mpo[4]); + unsigned int offset=le32(*tmp32); + unsigned int i; + unsigned int nbr; + unsigned int NumberOfImages=0; + unsigned int MPEntry_offset=0; + uint64_t max_offset=0; +#ifdef DEBUG_JPEG + log_info("check_mpo_le\n"); +#endif + if(offset >= size - 2) + return 0; + /*@ assert offset < size - 2; */ + tmp16=(const uint16_t*)(&mpo[offset]); + nbr=le16(*tmp16); + offset+=2; + /* @offset: MP Index Fields*/ + if(offset + nbr * 12 > size) + return 0; + /*@ assert offset + nbr * 12 <= size; */ + /*@ + @ loop invariant 0 <= i <= nbr; + @ loop assigns i, NumberOfImages, MPEntry_offset; + @ loop variant nbr-i; + @*/ + for(i=0; i< nbr; i++) + { + /*@ assert 0 <= i < nbr; */ + const unsigned char *field_ptr=&mpo[offset + i * 12]; + /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */ + const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr; + /*@ assert \valid_read(field); */ + const unsigned int count=le32(field->count); + const unsigned int type=le16(field->type); + switch(le16(field->tag)) + { + case 0xb000: + /* MPFVersion, type must be undefined */ + if(type!=7 || count!=4) + return 0; + break; + case 0xb001: + /* NumberOfImages, type must be long */ + if(type!=4 || count!=1) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + NumberOfImages=le32(*tmp); + if(NumberOfImages >= 0x100000) + return 0; + /*@ assert NumberOfImages < 0x100000; */ + } + break; + case 0xb002: + /* MPEntry, type must be undefined */ + if(type!=7 || count!=sizeof(struct MP_Entry)*NumberOfImages) + return 0; + { + const uint32_t *tmp=(const uint32_t *)&field->value[0]; + MPEntry_offset=le32(*tmp); + } + break; + } + } +#ifdef DEBUG_JPEG + log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages); +#endif + /*@ assert NumberOfImages < 0x100000; */ + if(MPEntry_offset > size) + return 0; + if(MPEntry_offset + sizeof(struct MP_Entry)*NumberOfImages > size) + return 0; + /*@ + @ loop invariant 0 <= i <= NumberOfImages; + @ loop assigns i, max_offset; + @ loop variant NumberOfImages-i; + @*/ + for(i=0; isize); +#ifdef DEBUG_JPEG + log_info("mpo_offset=%lu offset=%lu, size=%lu\n", + (long unsigned)mpo_offset, + (long unsigned)le32(MPEntry->offset), + (long unsigned)le32(MPEntry->size)); +#endif + if(le32(MPEntry->offset)>0) + tmp+=(uint64_t)le32(MPEntry->offset) + mpo_offset; + if(max_offset < tmp) + max_offset = tmp; + } + return max_offset; +} + +/*@ + @ requires size >= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ assigns \nothing; + @*/ +static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const unsigned int size) +{ + /* MP header: + * - MP Endian (4Byte) + * - Offset to First IFD (4Byte) + */ + if(mpo[0]=='I' && mpo[1]=='I' && mpo[2]=='*' && mpo[3]==0) + { + return check_mpo_le(mpo, offset, size); + } + else if(mpo[0]=='M' && mpo[1]=='M' && mpo[2]==0 && mpo[3]=='*') + { + return check_mpo_be(mpo, offset, size); + } + return 0; +} + +/*@ + @ requires \valid(handle); + @ requires size >= 8; + @ requires \valid_read(mpo + ( 0 .. size-1)); + @ requires separation: \separated(handle, &errno, &Frama_C_entropy_source, mpo + (..)); + @ assigns *handle, errno; + @ assigns Frama_C_entropy_source; + @*/ +static uint64_t file_check_mpo_aux(FILE *handle, const unsigned char *mpo, const uint64_t offset, const unsigned int size) +{ + /* MP header: + * - MP Endian (4Byte) + * - Offset to First IFD (4Byte) + */ + if(offset > PHOTOREC_MAX_FILE_SIZE) + return 0; + /*@ assert offset <= PHOTOREC_MAX_FILE_SIZE; */ + if(mpo[0]=='I' && mpo[1]=='I' && mpo[2]=='*' && mpo[3]==0) + { + return file_check_mpo_le(handle, mpo, offset, size); + } + else if(mpo[0]=='M' && mpo[1]=='M' && mpo[2]==0 && mpo[3]=='*') + { + return file_check_mpo_be(handle, mpo, offset, size); + } + return 0; +} + +/*@ + @ requires fr->file_check==&file_check_mpo; + @ requires separation: \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns errno; + @ assigns Frama_C_entropy_source; + @ assigns fr->calculated_file_size; + @ assigns fr->extra; + @ assigns fr->file_size; + @ assigns fr->flags; + @ assigns *fr->handle; + @ assigns fr->offset_error; + @ assigns fr->offset_ok; + @ assigns fr->time; + @*/ +static void file_check_mpo(file_recovery_t *fr) +{ + char sbuffer[512]; + const unsigned char *buffer=(const unsigned char *)&sbuffer; + uint64_t offset=0; + unsigned int size=0; + size_t nbytes; + uint64_t jpg_fs; +#ifdef DEBUG_JPEG + log_info("file_check_mpo %s calculated_file_size=%llu, error at %llu\n", fr->filename, + (long long unsigned)fr->calculated_file_size, + (long long unsigned)fr->offset_error); +#endif + { + /* Check the first jpg */ + const uint64_t fs=fr->file_size; +#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) + fr->calculated_file_size=0; +#endif + file_check_jpg(fr); + if(fr->file_size==0) + return ; + jpg_fs=fr->file_size; + fr->file_size=fs; + } + /*@ + @ loop assigns *fr->handle, Frama_C_entropy_source, errno; + @ loop assigns sbuffer[0 .. 511], fr->file_size, offset, nbytes, size; + @*/ + do + { + offset+=(uint64_t)2+size; + if(offset >= 0x8000000000000000) + { + fr->file_size=0; + return ; + } + /*@ assert offset < 0x8000000000000000; */ + if(my_fseek(fr->handle, offset, SEEK_SET) < 0) + { + fr->file_size=0; + return ; + } + nbytes=fread(&sbuffer, 1, sizeof(sbuffer), fr->handle); +#if defined(__FRAMAC__) + Frama_C_make_unknown(sbuffer, sizeof(sbuffer)); +#endif +// log_info("file_check_mpo offset=%llu => nbytes=%d, buffer=%02x %02x\n", +// (long long unsigned)offset, nbytes, buffer[0], buffer[1]); + /* 0xda SOS Start Of Scan */ + if(nbytes<8 || buffer[0]!=0xff || buffer[1]==0xda) + { + fr->file_size=0; + return ; + } + /*@ assert nbytes >= 8; */ + size=(buffer[2]<<8)+buffer[3]; + } while(!(buffer[1]==0xe2 && + buffer[4]=='M' && buffer[5]=='P' && buffer[6]=='F' && buffer[7]==0)); +#ifdef DEBUG_JPEG + log_info("Found at %lu\n", (long unsigned)offset); +#endif + if(8+size > nbytes) + { + size=nbytes-8; + /*@ assert size == nbytes - 8; */ + } + /*@ assert 8 + size <= nbytes; */ + if(size<16) + { + fr->file_size=0; + return ; + } + /*@ assert 16 <= size <= 65535; */ + { + const uint64_t max_offset=check_mpo(buffer+8, offset+8, size-8); + if(max_offset > fr->file_size) + { + fr->file_size=0; + return ; + } + fr->file_size=max_offset; + } + if(file_check_mpo_aux(fr->handle, buffer+8, offset+8, size-8) == 0) + { +#ifndef __FRAMAC__ + log_info("file_check_mpo %s failed, limiting to first jpeg: %llu\n", fr->filename, (long long unsigned)jpg_fs); +#endif + fr->file_size=jpg_fs; + } +} + +/*@ assigns \nothing; */ +static int is_marker_valid(const unsigned int marker) +{ + switch(marker) + { + case 0xc0: /* SOF0 Start of Frame */ + case 0xc1: /* SOF1 Extended sequential */ + case 0xc2: /* SOF2 Progressive */ + case 0xc3: /* SOF3 Lossless */ + case 0xc4: /* Define Huffman table */ + case 0xc5: /* SOF5 Differential sequential */ + case 0xc6: /* SOF6 Differential progressive */ + case 0xc7: /* SOF7 Differential lossless */ + case 0xc8: /* Start of Frame (JPG) (Reserved for JPEG extensions) */ + case 0xc9: /* SOF9 Extended sequential, arithmetic coding */ + case 0xca: /* SOF10 Progressive, arithmetic coding */ + case 0xcb: /* SOF11 Lossless, arithmetic coding */ + case 0xcc: /* DAC arithmetic-coding conditioning*/ + case 0xcd: /* SOF13 Differential sequential, arithmetic coding */ + case 0xce: /* SOF14 Differential progressive, arithmetic coding */ + case 0xcf: /* SOF15 Differential lossless, arithmetic coding */ + case 0xdb: /* DQT: Define Quantization Table */ + case 0xdd: /* DRI: define restart interval */ + case 0xe0 ... 0xef: /* APP0 - APP15 */ + case 0xfe: /* COM */ + case 0xff: + return 1; +#if 0 + case 0x02 ... 0xbf: /* Reserved */ + case 0xd0 ... 0xd7: /* JPEG_RST0 .. JPEG_RST7 markers */ + case 0xd8: /* SOI Start of Image */ + case 0xd9: /* EOI End of Image */ + case 0xda: /* SOS: Start Of Scan */ + case 0xdc: /* DNL: Define Number of Lines */ + case 0xde: /* DHP: define hierarchical progression */ + case 0xf0 ... 0xfd: /* Reserved for JPEG extensions */ +#endif + default: + return 0; + } +} + +/*@ + @ requires \valid_read(buffer + (0 .. buffer_size-1)); + @ assigns \nothing; + @*/ +static time_t jpg_get_date(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int i, const unsigned int size) +{ /* APP1 Exif information */ + const unsigned int tiff_offset=i+2+8; + if(tiff_offset < buffer_size && size > 8) + { + /*@ assert tiff_offset < buffer_size; */ + /*@ assert size > 8; */ + unsigned int tiff_size=size-0x08; + if(buffer_size - tiff_offset < tiff_size) + { + tiff_size=buffer_size - tiff_offset; + /*@ assert tiff_offset + tiff_size == buffer_size; */ + } + else + { + /*@ assert tiff_offset + tiff_size <= buffer_size; */ + } + /*@ assert tiff_offset + tiff_size <= buffer_size; */ + return get_date_from_tiff_header(&buffer[tiff_offset], tiff_size); + } + return 0; +} + + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_jpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures \result == 1 ==> file_recovery_new->file_size == 0; + @ ensures (\result == 1) ==> (file_recovery_new->extension != \null); + @ ensures \result == 1 ==> file_recovery_new->calculated_file_size == 0; + @ ensures \result == 1 && buffer_size >= 4 ==> file_recovery_new->data_check == data_check_jpg; + @ ensures \result == 1 ==> file_recovery_new->file_check == file_check_jpg; + @ ensures \result == 1 ==> file_recovery_new->file_rename == \null; + @ ensures \result == 1 ==> file_recovery_new->extension == file_hint_jpg.extension; + @ ensures \result == 1 ==> file_recovery_new->min_filesize > 0; + @ ensures \result == 1 ==> file_recovery_new->offset_ok == 0; + @*/ +static int header_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i=2; + time_t jpg_time=0; + /*@ loop assigns i, jpg_time; */ + while(i+4blocksize && buffer[i]!=0xff) + return 0; + if(i+1 < file_recovery_new->blocksize && buffer[i+1]!=0xda) + return 0; + if(i < 512 && buffer[i]!=0xff) + return 0; + if(i+1 < 512 && buffer[i+1]!=0xda) + return 0; + if(file_recovery->file_stat==NULL) + { + if(i < buffer_size && buffer[i]!=0xff) + return 0; + if(i+1 < buffer_size && buffer[i+1]!=0xda) + return 0; + } + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL) + { + static const unsigned char jpg_header_app0_avi[0x0c]= { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 'A', 'V', 'I', '1', 0x00, 0x00 + }; + static const unsigned char jpg_header_app0_jfif11_null[0x14]= { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 'J', 'F', 'I', 'F', 0x00, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char jpg_header_app0_jfif11_com[0x17]= { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 'J', 'F', 'I', 'F', 0x00, 0x01, 0x01, 0x01, 0x00, 0x48, + 0x00, 0x48, 0x00, 0x00, 0xff, 0xfe, 0x00 + }; + + unsigned int width=0; + unsigned int height=0; + jpg_get_size(buffer, buffer_size, &height, &width); +#if !defined(MAIN_jpg) && !defined(SINGLE_FORMAT) + if(file_recovery->file_stat->file_hint==&file_hint_indd) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + if(file_recovery->file_stat->file_hint==&file_hint_doc && + strstr(file_recovery->filename, ".albm")!=NULL) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + if( file_recovery->file_stat->file_hint==&file_hint_jpg) + { + /* Don't recover the thumb instead of the jpg itself */ + if( file_recovery->file_size <= 1024 && + buffer[3]==0xec) /* APP12 */ + { +#ifndef __FRAMAC__ + log_info("jpg %llu %llu\n", + (long long unsigned)file_recovery->calculated_file_size, + (long long unsigned)file_recovery->file_size); +#endif + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + /* Don't recover the thumb instead of the jpg itself */ + if(file_recovery->file_size <= 16384 && + buffer[3]==0xe0 && + width>0 && width<200 && height>0 && height<200) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + /* Some JPG have two APP1 markers, avoid to dicard the first one */ + if( buffer[3]==0xe1 && + memcmp(&buffer[6], "http://ns.adobe.com/xap/", 24)==0) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + if(file_recovery->file_check==&file_check_mpo) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + } +#if !defined(MAIN_jpg) && !defined(SINGLE_FORMAT) + /* Don't extract jpg inside AVI */ + if( file_recovery->file_stat->file_hint==&file_hint_riff && + (memcmp(buffer, jpg_header_app0_avi, sizeof(jpg_header_app0_avi))==0 || + file_recovery->data_check == &data_check_avi_stream)) + { + header_ignored(file_recovery_new); + return 0; + } + /* Don't extract jpg inside MOV */ + if( file_recovery->file_stat->file_hint==&file_hint_mov && + (memcmp(buffer, jpg_header_app0_jfif11_null, sizeof(jpg_header_app0_jfif11_null))==0 || + memcmp(buffer, jpg_header_app0_jfif11_com, sizeof(jpg_header_app0_jfif11_com))==0)) + { + header_ignored(file_recovery_new); + return 0; + } + /* Don't extract jpg inside rw2 */ + if( file_recovery->file_stat->file_hint==&file_hint_rw2 && + file_recovery->file_size <= 8192) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + switch(buffer[3]) + { + case 0xe0: /* APP0 */ + if(buffer[6]!='J' || buffer[7]!='F') /* Should be JFIF/JFXX */ + { + header_ignored(file_recovery_new); + return 0; + } + break; + case 0xe1: /* APP1 */ + if(buffer[6]!='E' || buffer[7]!='x' || buffer[8]!='i'|| buffer[9]!='f') /* Should be Exif */ + { + header_ignored(file_recovery_new); + return 0; + } + break; + case 0xfe: /* COM */ + if(!isprint(buffer[6]) || !isprint(buffer[7])) + { + header_ignored(file_recovery_new); + return 0; + } + break; + default: + header_ignored(file_recovery_new); + return 0; + } + } + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=i; + file_recovery_new->calculated_file_size=0; + file_recovery_new->time=jpg_time; + file_recovery_new->extension=file_hint_jpg.extension; + file_recovery_new->file_check=&file_check_jpg; + if(buffer_size >= 4) + file_recovery_new->data_check=&data_check_jpg; + /*@ assert valid_read_string(file_recovery_new->extension); */ + return 1; +} + +#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields, must be the first field */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + FILE * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + int start_of_file; /* have we gotten any data yet? */ + unsigned long int offset; + unsigned long int file_size; + unsigned long int file_size_max; + unsigned long int offset_ok; + unsigned int blocksize; +} my_source_mgr; + +static void my_output_message (j_common_ptr cinfo); +static void my_error_exit (j_common_ptr cinfo); +static void my_emit_message (j_common_ptr cinfo, int msg_level); + +static void my_output_message (j_common_ptr cinfo) +{ +#ifdef DEBUG_JPEG + struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err; + char buffermsg[JMSG_LENGTH_MAX]; + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffermsg); + log_info("jpeg: %s\n", buffermsg); +#endif +} + +static void my_error_exit (j_common_ptr cinfo) +{ + struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err; + (*cinfo->err->output_message) (cinfo); + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +static void my_emit_message (j_common_ptr cinfo, int msg_level) +{ + struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err; + struct jpeg_error_mgr *err = &myerr->pub; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +static void jpg_init_source (j_decompress_ptr cinfo) +{ + my_source_mgr * src = (my_source_mgr *) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; + src->offset= 0; + src->file_size = 0; + src->file_size_max = 0; +// src->offset_ok = 0; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +static boolean jpg_fill_input_buffer (j_decompress_ptr cinfo) +{ + my_source_mgr * src = (my_source_mgr *) cinfo->src; + size_t nbytes; +#if 0 + log_info("jpg_fill_input_buffer file_size=%llu -> %llu (offset=%llu, blocksize=%u)\n", + (long long unsigned)src->file_size, + (long long unsigned)src->file_size+src->blocksize - (src->offset + src->file_size)%src->blocksize, + (long long unsigned)src->offset, + src->blocksize); +#endif + nbytes = fread(src->buffer, 1, + src->blocksize - (src->offset + src->file_size)%src->blocksize, + src->infile); + if (nbytes <= 0) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + { + // (cinfo)->err->msg_code = JERR_INPUT_EMPTY; + (*(cinfo)->err->error_exit) ((j_common_ptr)cinfo);; + } + // cinfo->err->msg_code = JWRN_JPEG_EOF; + (*(cinfo)->err->emit_message) ((j_common_ptr)cinfo, -1); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + src->pub.next_input_byte = src->buffer; + if(src->file_size_max!=0 && src->file_size + nbytes > src->file_size_max) + { + const uint64_t off_end=(src->file_size_max > src->file_size ? src->file_size_max - src->file_size: 0); +// memset(&src->buffer[off_end], 0, nbytes); + src->buffer[off_end] = (JOCTET) 0xFF; + src->buffer[off_end+1] = (JOCTET) JPEG_EOI; + nbytes=off_end+2; + } + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + src->file_size += nbytes; + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +static void jpg_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_source_mgr * src = (my_source_mgr *) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + src->offset_ok=src->file_size - src->pub.bytes_in_buffer; + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) jpg_fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +static void jpg_term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* WARNING: This function must be listed in clang Control Flow Integrity (CFI) function blacklist, section cfi-icall */ +static void jpeg_testdisk_alloc_src (j_decompress_ptr cinfo, const unsigned int blocksize) +{ + my_source_mgr *src= (my_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_source_mgr)); + cinfo->src = (struct jpeg_source_mgr *) src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + blocksize * sizeof(JOCTET)); +} + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +static void jpeg_testdisk_src (j_decompress_ptr cinfo, FILE * infile, const uint64_t offset, const unsigned int blocksize) +{ + my_source_mgr * src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_testdisk_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + jpeg_testdisk_alloc_src(cinfo, blocksize); + } + + src = (my_source_mgr *) cinfo->src; + src->pub.init_source = &jpg_init_source; + src->pub.fill_input_buffer = &jpg_fill_input_buffer; + src->pub.skip_input_data = &jpg_skip_input_data; + src->pub.resync_to_restart = &jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = &jpg_term_source; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ + src->infile = infile; + src->offset = offset; + src->blocksize=blocksize; +} + +struct jpeg_session_struct +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_decompress_struct cinfo_backup; + unsigned char *frame; + unsigned int row_stride; + unsigned int output_components; + unsigned int output_width; + unsigned int output_height; + uint64_t offset; + FILE *handle; + unsigned int flags; + unsigned int blocksize; +}; + +static void jpeg_init_session(struct jpeg_session_struct *jpeg_session) +{ + jpeg_session->frame=NULL; + jpeg_session->row_stride=0; + jpeg_session->output_components=0; + jpeg_session->output_width=0; + jpeg_session->output_height=0; + jpeg_session->offset=0; + jpeg_session->handle=NULL; + jpeg_session->flags=0; +} + +static void jpeg_session_delete(struct jpeg_session_struct *jpeg_session) +{ + jpeg_destroy_decompress(&jpeg_session->cinfo); + free(jpeg_session->frame); + jpeg_session->frame=NULL; + jpeg_session->row_stride=0; +} + +static inline int jpeg_session_resume(struct jpeg_session_struct *jpeg_session) +{ + my_source_mgr * src; + memcpy(&jpeg_session->cinfo, &jpeg_session->cinfo_backup, sizeof(jpeg_session->cinfo)); + if(resume_memory((j_common_ptr)&jpeg_session->cinfo)) + return -1; + src = (my_source_mgr *) jpeg_session->cinfo.src; + if(my_fseek(jpeg_session->handle, jpeg_session->offset + src->file_size, SEEK_SET) < 0) + return -1; + return 0; +} + +static inline void jpeg_session_suspend(struct jpeg_session_struct *jpeg_session) +{ + suspend_memory((j_common_ptr)&jpeg_session->cinfo); + memcpy(&jpeg_session->cinfo_backup, &jpeg_session->cinfo, sizeof(jpeg_session->cinfo)); +} + +static void jpeg_session_start(struct jpeg_session_struct *jpeg_session) +{ + if(my_fseek(jpeg_session->handle, jpeg_session->offset, SEEK_SET) < 0) + { + log_critical("jpeg_session_start: fseek failed.\n"); + } + jpeg_create_decompress(&jpeg_session->cinfo); + jpeg_testdisk_src(&jpeg_session->cinfo, jpeg_session->handle, jpeg_session->offset, jpeg_session->blocksize); + (void) jpeg_read_header(&jpeg_session->cinfo, TRUE); + jpeg_session->cinfo.two_pass_quantize = FALSE; + jpeg_session->cinfo.dither_mode = JDITHER_NONE; + jpeg_session->cinfo.dct_method = JDCT_FASTEST; + jpeg_session->cinfo.do_block_smoothing = FALSE; + jpeg_session->cinfo.do_fancy_upsampling = FALSE; + (void) jpeg_start_decompress(&jpeg_session->cinfo); + jpeg_session->output_width=jpeg_session->cinfo.output_width; + jpeg_session->output_height=jpeg_session->cinfo.output_height; + jpeg_session->output_components=jpeg_session->cinfo.output_components; + jpeg_session->row_stride = jpeg_session->cinfo.output_width * jpeg_session->cinfo.output_components; + jpeg_session->frame=NULL; +} + +static uint64_t jpg_xy_to_offset(FILE *infile, const unsigned int x, const unsigned y, + const uint64_t offset_rel1, const uint64_t offset_rel2, const uint64_t offset, const unsigned int blocksize) +{ + static struct my_error_mgr jerr; + static uint64_t file_size_max; + static struct jpeg_session_struct jpeg_session; + unsigned int checkpoint_status; + int avoid_leak; + jpeg_init_session(&jpeg_session); + jpeg_session.handle=infile; + jpeg_session.offset=offset; + jpeg_session.blocksize=blocksize; + file_size_max=(offset_rel1 + blocksize - (offset % blocksize) -1) / blocksize * blocksize; +#ifdef DEBUG_JPEG + log_info("jpg_xy_to_offset(infile, x=%u, y=%u, offset_rel1=%lu, offset_rel2=%lu)\n", + x, y, (long unsigned)offset_rel1, (long unsigned)offset_rel2); +#endif + jpeg_session.cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.output_message = &my_output_message; + jerr.pub.error_exit = &my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) + { + if(jpeg_session.frame!=NULL && jpeg_session.cinfo.output_scanline >= y) + { + int data=0; + unsigned int i; + for(i=0; i< (jpeg_session.output_width-x) * jpeg_session.output_components; i++) + { + if(jpeg_session.frame[x*jpeg_session.output_components+i]!=0x80) + data=1; + } + if(data==1) + { + jpeg_session_delete(&jpeg_session); + return offset + file_size_max; + } + } + file_size_max+=blocksize; + } + checkpoint_status=0; + avoid_leak=0; + while(file_size_maxfile_size_max=file_size_max; + } + { + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + while (jpeg_session.cinfo.output_scanline < jpeg_session.cinfo.output_height && + jpeg_session.cinfo.output_scanline < y) + { + JSAMPROW row_pointer[1]; + row_pointer[0] = (unsigned char *)jpeg_session.frame; + (void)jpeg_read_scanlines(&jpeg_session.cinfo, row_pointer, 1); + } + if(src->file_size < src->file_size_max) + { + jpeg_session_suspend(&jpeg_session); + checkpoint_status=1; + } + if(jpeg_session.cinfo.output_scanline < jpeg_session.cinfo.output_height) + { + JSAMPROW row_pointer[1]; + unsigned int i; + row_pointer[0] = (unsigned char *)jpeg_session.frame; + /* 0x100/2=0x80, medium value */ + memset(jpeg_session.frame, 0x80, jpeg_session.row_stride); + (void)jpeg_read_scanlines(&jpeg_session.cinfo, row_pointer, 1); + for(i=(x+1)*jpeg_session.output_components; i < jpeg_session.output_width * jpeg_session.output_components; i++) + { + if(jpeg_session.frame[i]!=0x80) + { + (void) jpeg_finish_decompress(&jpeg_session.cinfo); + jpeg_session_delete(&jpeg_session); + return offset + file_size_max; + } + } + } + } + file_size_max+=blocksize; + } +/* Do not call jpeg_finish_decompress(&cinfo); to avoid an endless loop */ + jpeg_session_delete(&jpeg_session); + return offset + offset_rel2; +} + +static unsigned int is_line_cut(const unsigned int output_scanline, const unsigned int output_width, const unsigned int output_components, const unsigned char *frame, const unsigned int y) +{ + unsigned int result_x=0; + if(y+8 < output_scanline) + { + unsigned int result_max=0; + unsigned int x; + for(x=8 - 1; x < output_width; x+=8) + { + unsigned int result=0; + unsigned int j; + for(j=0; + j<8 && y+j < output_scanline; + j++) + { + unsigned int c; + unsigned int pos; + for(c=0, pos= ((y+j) * output_width + x ) * output_components; + c=8; y-=8) + { + const unsigned int old_val=val; + val=is_line_cut(output_scanline, output_width, output_components, frame, y); + if(val==0) + { + return y+8; + } + if(old_val!=0 && val!=old_val) + { + return y; + } + } + return output_scanline; +} + +#define JPG_MAX_OFFSETS 10240 + +/* FIXME: it doesn handle correctly when there is a few extra sectors */ +static uint64_t jpg_find_error(struct jpeg_session_struct *jpeg_session, const unsigned int *offsets, const uint64_t checkpoint_offset) +{ + FILE *handle = jpeg_session->handle; + const unsigned int output_scanline = jpeg_session->cinfo.output_scanline; + const unsigned int output_width = jpeg_session->output_width; + const unsigned int output_components = jpeg_session->output_components; + //const unsigned int blocksize = jpeg_session->blocksize; + const unsigned char *frame = jpeg_session->frame; + const uint64_t offset = jpeg_session->offset; + const unsigned int row_stride = output_width * output_components; + unsigned int result=0; + unsigned int result_max=0; + unsigned int result_x; + unsigned int result_y; + unsigned int y; + unsigned int i; + unsigned int pos_new; + unsigned int output_scanline_max; + if(output_scanline/8 >= JPG_MAX_OFFSETS) + return 0; + if(jpeg_session->output_height < 10) + return 0; + output_scanline_max=jpg_find_border(output_scanline, output_width, output_components, frame); + for(i = 0, pos_new= 8 * row_stride; + i < row_stride; + i++, pos_new++) + { + result += abs(2 * frame[pos_new] - frame[pos_new - row_stride] - frame[pos_new + row_stride]); + } + result_x=0; + result_y=8; + result_max=result; + + for(y=8; y+8 < output_scanline; y+=8) + { + unsigned int pos; + for(i = 0, + pos = y * row_stride, + pos_new = (y + 8) * row_stride; + i < row_stride; + i++, pos++, pos_new++) + { + if(i % (8 * output_components)==0) + { + int stop=0; +// log_info("x %4u, y %4u: %6u\n", i/output_components, y, result); + if(result_max < result) + { + // FIXME +#if 1 + if(2 * result_max < result) // && offset + offsets[result_x / 8] >= checkpoint_offset) + stop=1; +#endif + result_max=result; + result_x=i/output_components; + result_y=y; + } + /* 12 is a magic value */ +#if 1 + else if(2 * result < result_max && result_max > 12 * row_stride) // && offset + offsets[result_x / 8] >= checkpoint_offset) + stop=1; +#endif +#if 1 + else if(y > output_scanline_max) + { + stop=1; + } +#endif + if(stop==1 + && is_line_cut(output_scanline, output_width, output_components, frame, y)) + { + const uint64_t offset_rel1=offsets[result_y / 8]; + const uint64_t offset_rel2=offsets[result_y / 8 + 1]; +#ifdef DEBUG_JPEG + log_info("x %4u, y %4u: %6u, result=%u, output_scanline_max=%u\n", + result_x, result_y, result_max, result, output_scanline_max); +#endif + if(offset_rel1 < offset_rel2) + return jpg_xy_to_offset(handle, result_x, result_y, +// offset_rel1, offset_rel2, offset, blocksize); + offset_rel1, offset_rel2, offset, 512); + return offset + offset_rel2; + } + } + result -= abs(2 * frame[pos] - frame[pos - row_stride] - frame[pos + row_stride]); + result += abs(2 * frame[pos_new] - frame[pos_new - row_stride] - frame[pos_new + row_stride]); + } + } + return 0; +} + +static uint64_t jpg_check_thumb(FILE *infile, const uint64_t offset, const unsigned int blocksize, const uint64_t checkpoint_offset, const unsigned int flags) +{ + static struct my_error_mgr jerr; + static unsigned int offsets[JPG_MAX_OFFSETS]; + static struct jpeg_session_struct jpeg_session; + jpeg_init_session(&jpeg_session); + jpeg_session.flags=flags; + jpeg_session.handle=infile; + jpeg_session.offset=offset; + jpeg_session.blocksize=blocksize; + jpeg_session.cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.output_message = &my_output_message; + jerr.pub.error_exit = &my_error_exit; + jerr.pub.emit_message= &my_emit_message; +#ifdef DEBUG_JPEG + jerr.pub.trace_level= 3; +#endif + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object and return. + */ + uint64_t offset_error; + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + offset_error=jpeg_session.offset + src->file_size - src->pub.bytes_in_buffer; + if(jpeg_session.frame!=NULL && jpeg_session.flags!=0) + { + const uint64_t tmp=jpg_find_error(&jpeg_session, &offsets[0], checkpoint_offset); +// log_info("jpg_check_thumb jpeg corrupted near %llu\n", (long long unsigned)offset_error); + if(tmp !=0 && offset_error > tmp) + offset_error=tmp; +// log_info("jpg_check_thumb find_error estimation %llu\n", (long long unsigned)offset_error); + } + jpeg_session_delete(&jpeg_session); + return offset_error; + } + memset(offsets, 0, sizeof(offsets)); + jpeg_session_start(&jpeg_session); + jpeg_session.frame = (unsigned char*)MALLOC((jpeg_session.output_height+1) * jpeg_session.row_stride); + /* 0x100/2=0x80, medium value */ + memset(jpeg_session.frame, 0x80, jpeg_session.row_stride * (jpeg_session.cinfo.output_height+1)); + while (jpeg_session.cinfo.output_scanline < jpeg_session.cinfo.output_height) + { + JSAMPROW row_pointer[1]; + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + src->offset_ok=src->file_size - src->pub.bytes_in_buffer; + if(jpeg_session.cinfo.output_scanline/8 < JPG_MAX_OFFSETS && offsets[jpeg_session.cinfo.output_scanline/8]==0) + offsets[jpeg_session.cinfo.output_scanline/8]=src->file_size - src->pub.bytes_in_buffer; + // Calculate where this line needs to go. + row_pointer[0] = (unsigned char *)jpeg_session.frame + jpeg_session.cinfo.output_scanline * jpeg_session.row_stride; + (void)jpeg_read_scanlines(&jpeg_session.cinfo, row_pointer, 1); + } + (void) jpeg_finish_decompress(&jpeg_session.cinfo); + jpeg_session_delete(&jpeg_session); + return 0; +} + +static void jpg_check_picture(file_recovery_t *file_recovery) +{ + static struct my_error_mgr jerr; + static unsigned int offsets[JPG_MAX_OFFSETS]; + uint64_t jpeg_size=0; + static struct jpeg_session_struct jpeg_session; + static int jpeg_session_initialised=0; + if(file_recovery->checkpoint_status==0) + { + if(jpeg_session_initialised==1) + jpeg_session_delete(&jpeg_session); + jpeg_init_session(&jpeg_session); + jpeg_session.flags=file_recovery->flags; + jpeg_session_initialised=1; + jpeg_session.blocksize=file_recovery->blocksize; + } + jpeg_session.handle=file_recovery->handle; + jpeg_session.cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.output_message = &my_output_message; + jerr.pub.error_exit = &my_error_exit; + jerr.pub.emit_message= &my_emit_message; +#ifdef DEBUG_JPEG + jerr.pub.trace_level= 3; +#endif + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object and return. + */ + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + jpeg_size=src->file_size; + if(src->pub.bytes_in_buffer >= 4) + jpeg_size-=src->pub.bytes_in_buffer; + if(jpeg_size>0) + file_recovery->offset_error=jpeg_size; + if(file_recovery->offset_ok < src->offset_ok) + file_recovery->offset_ok=src->offset_ok; +#ifdef DEBUG_JPEG + log_error("JPG error, ok at %llu - bad at %llu\n", + (long long unsigned)file_recovery->offset_ok, + (long long unsigned)file_recovery->offset_error); +#endif + if(jpeg_session.frame!=NULL && jpeg_session.flags!=0) + { + const uint64_t offset_error=jpg_find_error(&jpeg_session, &offsets[0], file_recovery->checkpoint_offset); + if(offset_error !=0 && file_recovery->offset_error > offset_error) + file_recovery->offset_error=offset_error; +#ifdef DEBUG_JPEG + log_error("JPG error, ok at %llu - bad at %llu (jpg_find_error)\n", + (long long unsigned)file_recovery->offset_ok, + (long long unsigned)file_recovery->offset_error); +#endif + } + jpeg_session_delete(&jpeg_session); + return; + } + memset(offsets, 0, sizeof(offsets)); + jpeg_session_start(&jpeg_session); + { + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + src->file_size_max=file_recovery->file_size; + } + /* Image is very big, skip some tests */ + if((uint64_t)jpeg_session.output_height * jpeg_session.row_stride > 500 * 1024 * 1024 || + jpeg_session.output_height<9) + jpeg_session.flags=0; + /* 0x100/2=0x80, medium value */ + if(jpeg_session.flags==0) + { + jpeg_session.frame = (unsigned char *)MALLOC(jpeg_session.row_stride); + memset(jpeg_session.frame, 0x80, jpeg_session.row_stride); + } + else + { + /* FIXME out of bound read access in libjpeg-turbo */ + jpeg_session.frame = (unsigned char *)MALLOC((jpeg_session.output_height+1) * jpeg_session.row_stride); + memset(jpeg_session.frame, 0x80, (jpeg_session.cinfo.output_height+1) * jpeg_session.row_stride); + } + while (jpeg_session.cinfo.output_scanline < jpeg_session.cinfo.output_height) + { + JSAMPROW row_pointer[1]; + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + src->offset_ok=src->file_size - src->pub.bytes_in_buffer; + if(jpeg_session.cinfo.output_scanline/8 < JPG_MAX_OFFSETS && offsets[jpeg_session.cinfo.output_scanline/8]==0) + { + offsets[jpeg_session.cinfo.output_scanline/8]=src->file_size - src->pub.bytes_in_buffer; + } + // Calculate where this line needs to go. + if(jpeg_session.flags==0) + row_pointer[0] = jpeg_session.frame; + else + row_pointer[0] = (unsigned char *)jpeg_session.frame + jpeg_session.cinfo.output_scanline * jpeg_session.row_stride; + (void)jpeg_read_scanlines(&jpeg_session.cinfo, row_pointer, 1); + } + { + my_source_mgr * src; + src = (my_source_mgr *) jpeg_session.cinfo.src; + jpeg_size=src->file_size - src->pub.bytes_in_buffer; + } + (void) jpeg_finish_decompress(&jpeg_session.cinfo); + jpeg_session_delete(&jpeg_session); + jpeg_session_initialised=0; + file_recovery->checkpoint_status=0; + if(jpeg_size<=0) + return; + if(file_recovery->calculated_file_size>0) + file_recovery->file_size=file_recovery->calculated_file_size; + else + { + static const unsigned char jpg_footer[2]= { 0xff,0xd9}; + file_recovery->file_size=jpeg_size; + file_search_footer(file_recovery, jpg_footer, sizeof(jpg_footer), 0); + } +} +#endif + +static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int i, const unsigned int size) +{ + unsigned int j=i+4; + /* DHT must not be shorter than 18 bytes, 1+16+1 */ + /* DHT should not be longer than 1088 bytes, 4*(1+16+255) */ + if(size<18) + return 2; + /*@ loop assigns j; */ + while(j < buffer_size && j < i+size) + { + const unsigned int tc=buffer[j]>>4; + const unsigned int n=buffer[j] & 0x0f; + unsigned int l; + unsigned int sum=0; + /* Table class: 0 = DC table or lossless table, 1 = AC table */ + if(tc > 1) + return 2; + /* Must be between 0 and 3 Huffman table */ + if(n > 3) + return 2; + j++; + /*@ + @ loop invariant 0 <= l <= 16; + @ loop invariant sum <= l*255; + @ loop assigns l,sum; + @ loop variant 16-l; + @*/ + for(l=0; l < 16; l++) + if(j+l < buffer_size) + sum+=buffer[j+l]; + if(sum>255) + return 2; + j+=16; + j+=sum; + } + if(j > i+size) + return 2; + return 0; +} + +struct sof_header +{ + uint16_t marker; + uint16_t length; /* 8 + 3 * nbr */ + unsigned char precision; /* 2-16 8 for SOF0 */ + uint16_t height; /* 0-65535 */ + uint16_t width; /* 1-65535 */ + unsigned char nbr; /* 1-255 */ +#if 0 + unsigned char data[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(buffer + (0..buffer_size-1)); + @ assigns \nothing; + @*/ +static int jpg_check_sof0(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int i) +{ + if(i+4 > buffer_size) + return 0; + { + const struct sof_header *h=(const struct sof_header *)&buffer[i]; + const unsigned int length=be16(h->length); + if(length < sizeof(struct sof_header)-2) + return 1; + } + if(i+2+8 > buffer_size) + return 0; + { + const struct sof_header *h=(const struct sof_header *)&buffer[i]; + const unsigned int length=be16(h->length); + if(h->precision!=8 || be16(h->width)==0 || h->nbr==0) + return 1; + if(length < 8+h->nbr*3) + return 1; + } +// if(i+2+be16(h->length) > buffer_size) +// return 0; + return 0; +} + +/*@ + @ requires \valid_read(file_recovery); + @ requires \valid(file_recovery->handle); + @ requires 0 < file_recovery->blocksize <= 1048576; + @ requires file_recovery->offset_error <= (1<<63) - 1; + @ requires separation: \separated(file_recovery, file_recovery->handle, &errno); + @ ensures \valid(file_recovery->handle); + @ assigns *file_recovery->handle, errno; + @ assigns Frama_C_entropy_source; + @ assigns file_recovery->extra; + @*/ +static void jpg_search_marker(file_recovery_t *file_recovery) +{ + FILE* infile=file_recovery->handle; + char sbuffer[40*8192]; + size_t nbytes; + const uint64_t offset_error=file_recovery->offset_error; + uint64_t offset_test=offset_error; + uint64_t offset; + /*@ assert offset_test == offset_error; */ + if(file_recovery->blocksize==0) + return ; + offset=offset_test / file_recovery->blocksize * file_recovery->blocksize; + if(my_fseek(infile, offset, SEEK_SET) < 0) + return ; + /*@ assert offset_test == offset_error; */ + /*@ + @ loop invariant offset_test >= offset_error; + @ loop assigns nbytes, sbuffer[ 0 .. sizeof(sbuffer)-1]; + @ loop assigns *infile, errno; + @ loop assigns Frama_C_entropy_source; + @ loop assigns offset, offset_test; + @ loop assigns file_recovery->extra; + @*/ + while((nbytes=fread(&sbuffer, 1, sizeof(sbuffer), infile))>0) + { + unsigned int i; + const unsigned char *buffer=(const unsigned char *)sbuffer; + /*@ assert 0 < nbytes <= sizeof(sbuffer); */ + if(offset_test > 0x80000000) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&sbuffer, sizeof(sbuffer)); +#endif + /*@ assert offset_test >= offset_error; */ + offset=offset_test / file_recovery->blocksize * file_recovery->blocksize; + i=offset_test % file_recovery->blocksize; + /*@ assert offset + i == offset_test; */ + /*@ assert i == offset_test - offset; */ + /*@ assert offset_test >= offset_error; */ + /*@ + @ loop invariant offset + i >= offset_test; + @ loop invariant offset_test >= offset_error; + @ loop invariant 0 <= i < nbytes + file_recovery->blocksize; + @ loop assigns i,file_recovery->extra; + @*/ + while(i+1= offset_test; */ + /*@ assert offset_test >= offset_error; */ + if(buffer[i]==0xff && + (buffer[i+1]==0xd8 || /* SOI */ + buffer[i+1]==0xdb || /* DQT */ + (buffer[i+1]>=0xc0 && buffer[i+1]<=0xcf) || /* SOF0 - SOF15, 0xc4=DHT */ + buffer[i+1]==0xda || /* SOS: Start Of Scan */ + buffer[i+1]==0xdd || /* DRI */ + (buffer[i+1]>=0xe0 && buffer[i+1]<=0xef) || /* APP0 - APP15 */ + buffer[i+1]==0xfe) /* COM */ + ) + { + file_recovery->extra=tmp - offset_error; +#ifndef __FRAMAC__ + if(file_recovery->extra % file_recovery->blocksize != 0) + { + log_info("jpg_search_marker %s extra=%llu\n", + file_recovery->filename, + (long long unsigned)file_recovery->extra); + } +#endif + return ; + } + i+=file_recovery->blocksize; + } + offset_test += nbytes; + } + return ; +} + +/*@ + @ requires valid_file_recovery(file_recovery); + @ requires \valid_read(buffer + (0 .. nbytes-1)); + @ requires thumb_offset < nbytes; + @ requires thumb_size > 0; + @ requires thumb_offset + thumb_size <= nbytes; + @ assigns errno; + @*/ +static void jpg_save_thumbnail(const file_recovery_t *file_recovery, const char *buffer, const uint64_t nbytes, const uint64_t thumb_offset, const unsigned int thumb_size) +{ + char thumbname[2048]; + char *sep; + /*@ assert sizeof(thumbname) == sizeof(file_recovery->filename); */ + /*@ assert valid_read_string((char *)&file_recovery->filename); */ + memcpy(thumbname,file_recovery->filename, sizeof(thumbname)); + thumbname[sizeof(thumbname)-1]='\0'; + /*@ assert valid_read_string(&thumbname[0]); */ + sep=strrchr(thumbname,'/'); + if(sep!=NULL +#ifndef __FRAMAC__ + && *(sep+1)=='f' +#endif + ) + { + FILE *out; +#ifndef __FRAMAC__ + *(sep+1)='t'; +#endif +#ifndef __FRAMAC__ + if((out=fopen(thumbname,"wb"))!=NULL) + { + /*@ assert \valid_read(buffer + (0 .. nbytes - 1)); */ + /*@ assert 0 <= thumb_offset < nbytes; */ + /*@ assert \valid_read(buffer + (thumb_offset .. nbytes - 1)); */ + /*@ assert \valid_read(buffer + thumb_offset + (0 .. nbytes - 1 - thumb_offset)); */ + /*@ ghost const char *thumb_char=&buffer[thumb_offset]; */ + /*@ assert \valid_read(thumb_char + (0 .. nbytes - thumb_offset - 1)); */ + /*@ assert 0 < thumb_size <= nbytes - thumb_offset; */ + /*@ ghost uint64_t tmp_size=nbytes - thumb_offset; */ + /*@ assert 0 < thumb_size <= tmp_size; */ + /*@ assert \valid_read(thumb_char + (0 .. tmp_size - 1)); */ + /*@ assert \valid_read(thumb_char + (0 .. thumb_size - 1)); */ + if(fwrite(&buffer[thumb_offset], thumb_size, 1, out) < 1) + { +#ifndef __FRAMAC__ + log_error("Can't write to %s: %s\n", thumbname, strerror(errno)); +#endif + } + fclose(out); + if(file_recovery->time!=0 && file_recovery->time!=(time_t)-1) + set_date(thumbname, file_recovery->time, file_recovery->time); + } + else + { +#ifndef __FRAMAC__ + log_error("fopen %s failed\n", thumbname); +#endif + } +#endif + } +} + +/*@ + @ requires \valid(file_recovery); + @ requires \valid(file_recovery->handle); + @ requires \valid(thumb_offset_ptr); + @ requires valid_read_string((char *)&file_recovery->filename); + @ requires file_recovery->blocksize > 0; + @ requires nbytes > 4; + @ requires \valid_read(buffer + (0 .. nbytes-1)); + @ requires \initialized(&file_recovery->time); + @ requires separation: \separated(file_recovery, file_recovery->handle, buffer+(..), thumb_offset_ptr, &errno); + @ ensures \valid(file_recovery->handle); + @ assigns *file_recovery->handle, errno; + @ assigns Frama_C_entropy_source; + @ assigns file_recovery->extra; + @ assigns file_recovery->time; + @ assigns file_recovery->offset_error; + @ assigns file_recovery->offset_ok; + @ assigns *thumb_offset_ptr; + @*/ +static int jpg_check_app1(file_recovery_t *file_recovery, const unsigned int extract_thumb, const unsigned char *buffer, const unsigned int i, const unsigned int offset, const unsigned int size, const uint64_t nbytes, uint64_t *thumb_offset_ptr) +{ /* APP1 Exif information */ + const unsigned int tiff_offset=i+2+8; + const unsigned char *potential_error=NULL; + const unsigned char *tiff; + unsigned int thumb_size=0; + unsigned int tiff_size; + uint64_t thumb_offset; + *thumb_offset_ptr=0; + if(tiff_offset >= nbytes || size <= 8) + return 1; + /*@ assert tiff_offset < nbytes; */ + /*@ assert size > 8; */ + tiff_size=size-0x08; + if(nbytes - tiff_offset < tiff_size) + { + tiff_size=nbytes - tiff_offset; + /*@ assert tiff_offset + tiff_size == nbytes; */ + } + else + { + /*@ assert tiff_offset + tiff_size <= nbytes; */ + } + /*@ assert tiff_offset + tiff_size <= nbytes; */ + if(tiff_size= sizeof(TIFFHeader); */ + /*@ assert \valid_read(buffer + (0 .. tiff_offset+tiff_size-1)); */ + /*@ assert \valid_read((buffer + tiff_offset) + (0 .. tiff_size-1)); */ + tiff=&buffer[tiff_offset]; + /*@ assert \valid_read(tiff+ (0 .. tiff_size-1)); */ + if(file_recovery->time==0) + { + /*@ assert \valid_read(tiff+ (0 .. tiff_size-1)); */ + file_recovery->time=get_date_from_tiff_header(tiff, tiff_size); + } + thumb_offset=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFOFFSET, &potential_error); + if(potential_error!=NULL) + { + file_recovery->offset_error=potential_error-buffer; + return 0; + } + if(thumb_offset==0) + return 1; + /*@ assert 0 < thumb_offset; */ + thumb_offset+=tiff_offset; + thumb_size=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFBYTECOUNT, &potential_error); + if(potential_error!=NULL) + { + file_recovery->offset_error=potential_error-buffer; + return 0; + } + if(thumb_size==0) + return 1; + /*@ assert 0 < thumb_size; */ + *thumb_offset_ptr=thumb_offset; + if(file_recovery->offset_okoffset_ok=i; + if(thumb_offset + 6 >= nbytes) + return 1; + /*@ assert 0 < thumb_offset < nbytes - 6; */ + /*@ assert thumb_offset < nbytes; */ + { + unsigned int j=thumb_offset+2; + unsigned int thumb_sos_found=0; +#ifdef DEBUG_JPEG + unsigned int j_old=j; +#endif + if(buffer[thumb_offset]!=0xff) + { + file_recovery->offset_error=thumb_offset; + jpg_search_marker(file_recovery); + return 0; + } + if(buffer[thumb_offset+1]!=0xd8) + { + file_recovery->offset_error=thumb_offset+1; + return 0; + } + /*@ assert j == thumb_offset + 2; */ + /*@ assert j < nbytes - 4; */ + /*@ + @ loop invariant 0 < thumb_size; + @ loop invariant 0 < thumb_offset < nbytes - 1; + @ loop assigns j, thumb_sos_found; + @ loop assigns errno, *file_recovery->handle,Frama_C_entropy_source; + @ loop assigns file_recovery->offset_ok; + @ loop assigns file_recovery->offset_error; + @ loop assigns file_recovery->extra; + @*/ + while(j+4offset_error=j; +#ifdef DEBUG_JPEG + log_info("%s thumb no marker at 0x%x\n", file_recovery->filename, j); + log_error("%s Error between %u and %u\n", file_recovery->filename, j_old, j); +#endif + jpg_search_marker(file_recovery); + return 0; + } + if(buffer[j+1]==0xff) + { + /* See B.1.1.2 Markers in http://www.w3.org/Graphics/JPEG/itu-t81.pdf*/ + j++; + continue; + } +#ifdef DEBUG_JPEG + log_info("%s thumb marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j); +#endif + if(buffer[j+1]==0xda) /* Thumb SOS: Start Of Scan */ + { + thumb_sos_found=1; + } + else if(buffer[j+1]==0xc4) /* DHT */ + { + if(jpg_check_dht(buffer, nbytes, j, 2+(buffer[j+2]<<8)+buffer[j+3])!=0) + { + file_recovery->offset_error=j+2; + return 0; + } + } + else if(buffer[j+1]==0xdb || /* DQT */ + buffer[j+1]==0xc0 || /* SOF0 */ + buffer[j+1]==0xdd) /* DRI */ + { + } + else if((buffer[j+1]>=0xc0 && buffer[j+1]<=0xcf) || /* SOF0 - SOF15 */ + (buffer[j+1]>=0xe0 && buffer[j+1]<=0xef) || /* APP0 - APP15 */ + buffer[j+1]==0xfe) /* COM */ + { + /* Unusual marker, bug ? */ + } + else + { +#ifndef __FRAMAC__ + log_info("%s thumb unknown marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j); +#endif + file_recovery->offset_error=j; + return 0; + } + if(file_recovery->offset_okoffset_ok=j; +#ifdef DEBUG_JPEG + j_old=j; +#endif + { + const unsigned int tmp=(buffer[j+2]<<8)+buffer[j+3]; + /*@ assert 0 <= tmp <= 65535; */ + j+=2U+tmp; + } + } + if(thumb_sos_found==0) + return 1; + } + if(extract_thumb==0) + return 1; + /* APP1 must be followed by a valid marker, this avoids many corrupted thumbnails */ + if(offset >= nbytes || buffer[offset]!=0xff) + return 1; + if(thumb_offset+thumb_size > nbytes) + return 1; + /*@ assert thumb_offset + thumb_size <= nbytes; */ + /*@ assert 0 < thumb_size; */ + /*@ assert thumb_offset < nbytes; */ + jpg_save_thumbnail(file_recovery, (const char *)buffer, nbytes, thumb_offset, thumb_size); + return 1; +} + +/*@ + @ requires \valid(file_recovery); + @ requires \valid(file_recovery->handle); + @ requires file_recovery->blocksize > 0; + @ requires \initialized(&file_recovery->time); + @ requires valid_read_string((char *)&file_recovery->filename); + @ requires separation: \separated(file_recovery, file_recovery->handle, &errno, &Frama_C_entropy_source); + @ assigns errno; + @ assigns file_recovery->extra; + @ assigns *file_recovery->handle; + @ assigns file_recovery->offset_error; + @ assigns file_recovery->offset_ok; + @ assigns file_recovery->time; + @ assigns Frama_C_entropy_source; + */ +static uint64_t jpg_check_structure(file_recovery_t *file_recovery, const unsigned int extract_thumb) +{ + char sbuffer[40*8192]; + uint64_t thumb_offset=0; + size_t nbytes; + unsigned int offset; + const unsigned char *buffer=(const unsigned char*)&sbuffer; + file_recovery->extra=0; + if(my_fseek(file_recovery->handle, 0, SEEK_SET) < 0) + return 0; + nbytes=fread(&sbuffer, 1, sizeof(sbuffer), file_recovery->handle); +#if defined(__FRAMAC__) + Frama_C_make_unknown(sbuffer, sizeof(sbuffer)); +#endif + if(nbytes <= 0) + return 0; + /*@ assert nbytes > 0; */ + file_recovery->offset_error=0; + /*@ loop assigns offset, file_recovery->offset_error; */ + for(offset=file_recovery->blocksize; offset + 30 < nbytes && file_recovery->offset_error==0; offset+=file_recovery->blocksize) + { + if(buffer[offset]==0xff && buffer[offset+1]==0xd8 && buffer[offset+2]==0xff && + ((buffer[offset+3]==0xe1 && memcmp(&buffer[offset+6], "http://ns.adobe.com/xap/", 24)!=0) + || buffer[offset+3]==0xec)) + { + file_recovery->offset_error=offset; + } + } + offset=2; + /*@ + @ loop assigns errno; + @ loop assigns file_recovery->extra; + @ loop assigns *file_recovery->handle; + @ loop assigns file_recovery->offset_error; + @ loop assigns file_recovery->offset_ok; + @ loop assigns file_recovery->time; + @ loop assigns Frama_C_entropy_source; + @ loop assigns offset; + @ loop assigns thumb_offset; + @*/ + while(offset + 4 < nbytes && buffer[offset]==0xff && is_marker_valid(buffer[offset+1]) && (file_recovery->offset_error==0 || offset < file_recovery->offset_error)) + { + /*@ assert offset + 4 < nbytes; */ + const unsigned int i=offset; + /*@ assert i == offset ; */ + /*@ assert i + 4 < nbytes; */ + /*@ assert i < nbytes; */ + const unsigned int size=(buffer[i+2]<<8)+buffer[i+3]; + if(buffer[i+1]==0xff) + { + /* See B.1.1.2 Markers in http://www.w3.org/Graphics/JPEG/itu-t81.pdf*/ + offset++; + continue; + } +#if defined(DEBUG_JPEG) + log_info("%s marker ff%02x at 0x%x\n", file_recovery->filename, buffer[i+1], i); +#endif + offset+=(uint64_t)2+size; + if(buffer[i+1]==0xe1) + { /* APP1 Exif information */ + if(jpg_check_app1(file_recovery, extract_thumb, buffer, i, offset, size, nbytes, &thumb_offset)==0) + return 0; + } + else if(buffer[i+1]==0xc4) /* DHT */ + { + if(jpg_check_dht(buffer, nbytes, i, 2+size)!=0) + { + file_recovery->offset_error=i+2; + return thumb_offset; + } + } + if(file_recovery->offset_okoffset_ok=i+1; + } + if(offset < nbytes && buffer[offset]!=0xff) + { +#if defined(DEBUG_JPEG) + log_info("%s no marker at 0x%x\n", file_recovery->filename, offset); +#endif + file_recovery->offset_error=offset; + jpg_search_marker(file_recovery); + return thumb_offset; + } + if(offset + 4 < nbytes) + { + if(buffer[offset+1]==0xda) /* SOS: Start Of Scan */ + file_recovery->offset_ok=offset+1; + else + file_recovery->offset_error=offset+1; + return thumb_offset; + } + if(offset > nbytes && nbytes < sizeof(buffer)) + { + file_recovery->offset_error=nbytes; + return thumb_offset; + } + return thumb_offset; +} + +/*@ + @ requires file_recovery->file_check == &file_check_mpo || file_recovery->file_check == &file_check_jpg; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns errno; + @ assigns file_recovery->calculated_file_size; + @ assigns file_recovery->extra; + @ assigns file_recovery->file_size; + @ assigns file_recovery->flags; + @ assigns *file_recovery->handle; + @ assigns file_recovery->offset_error; + @ assigns file_recovery->offset_ok; + @ assigns file_recovery->time; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_jpg(file_recovery_t *file_recovery) +{ + uint64_t thumb_offset; + static uint64_t thumb_error=0; + if(file_recovery->calculated_file_size<=2) + file_recovery->calculated_file_size=0; + /* FIXME REMOVE ME */ + file_recovery->flags=1; + file_recovery->file_size=0; + if(file_recovery->calculated_file_size==0) + file_recovery->offset_error=0; +#ifdef DEBUG_JPEG + log_info("file_check_jpg %s calculated_file_size=%llu, error at %llu\n", file_recovery->filename, + (long long unsigned)file_recovery->calculated_file_size, + (long long unsigned)file_recovery->offset_error); +#endif + if(file_recovery->offset_error!=0) + return ; + thumb_offset=jpg_check_structure(file_recovery, 1); +#ifdef DEBUG_JPEG + log_info("jpg_check_structure error at %llu\n", (long long unsigned)file_recovery->offset_error); +#endif +#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) + if(thumb_offset!=0 && + (file_recovery->checkpoint_status==0 || thumb_error!=0) && + (file_recovery->offset_error==0 || thumb_offset < file_recovery->offset_error)) + { +#ifdef DEBUG_JPEG + log_info("jpg_check_thumb\n"); +#endif + thumb_error=jpg_check_thumb(file_recovery->handle, thumb_offset, file_recovery->blocksize, file_recovery->checkpoint_offset, file_recovery->flags); + if(thumb_error!=0) + { +#ifdef DEBUG_JPEG + log_info("%s thumb corrupted at %llu, previous error at %llu\n", + file_recovery->filename, (long long unsigned)thumb_error, + (long long unsigned)file_recovery->offset_error); +#endif + if(file_recovery->offset_error==0 || file_recovery->offset_error > thumb_error) + { +#ifdef DEBUG_JPEG + log_info("Thumb usefull, error at %llu\n", (long long unsigned)thumb_error); +#endif + file_recovery->offset_error = thumb_error; + } + } + } +#endif + if(file_recovery->offset_error!=0) + return ; +#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) + jpg_check_picture(file_recovery); +#else + file_recovery->file_size=file_recovery->calculated_file_size; +#endif +#if 0 + /* FIXME REMOVE ME */ + if(file_recovery->offset_error!=0) + { + file_recovery->file_size=file_recovery->offset_error; + file_recovery->offset_error=0; + fseek(file_recovery->handle, file_recovery->file_size, SEEK_SET); + fwrite(jpg_footer, sizeof(jpg_footer), 1, file_recovery->handle); + file_recovery->file_size+=2; + return ; + } +#endif +} + +#if !defined(HAVE_LIBJPEG) || !defined(HAVE_JPEGLIB_H) +/*@ + @ requires \valid(file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_continue(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + file_recovery->calculated_file_size+=buffer_size/2; + return DC_CONTINUE; +} +#endif + +/*@ + @ requires file_recovery->data_check == &data_check_jpg2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == \null || file_recovery->data_check == &data_check_continue; + @ ensures file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; + @ assigns file_recovery->calculated_file_size; + @ assigns file_recovery->data_check; + @ assigns file_recovery->offset_error; + @*/ +static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop invariant file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; + @ loop assigns file_recovery->calculated_file_size; + @ loop assigns file_recovery->data_check; + @ loop assigns file_recovery->offset_error; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 > file_recovery->file_size && + file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 1; */ + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + if(buffer[i]==0xFF) + { + if(buffer[i+1]==0xd9) + { + /* JPEG_EOI */ + file_recovery->calculated_file_size+=2; + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + /*@ assert file_recovery->calculated_file_size >= 2; */ + /*@ assert file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; */ + return DC_STOP; + } + else if(buffer[i+1] >= 0xd0 && buffer[i+1] <= 0xd7) + { + /* JPEG_RST0 .. JPEG_RST7 markers */ +#if 0 + if((buffer[i+1]==0xd0 && old_marker!=0 && old_marker!=0xd7) || + (buffer[i+1]!=0xd0 && old_marker+1 != buffer[i+1])) + { +#ifdef DEBUG_JPEG + log_info("Rejected due to JPEG_RST marker\n"); +#endif + file_recovery->calculated_file_size++; + return DC_STOP; + } + /* TODO: store old_marker in file_recovery */ + old_marker=buffer[i+1]; +#endif + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + } + else if(buffer[i+1] == 0xda || buffer[i+1] == 0xc4) + { + /* SOS and DHT may be embedded by progressive jpg */ +#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) + file_recovery->data_check=NULL; + file_recovery->calculated_file_size=0; +#else + file_recovery->data_check=data_check_continue; + file_recovery->calculated_file_size=file_recovery->file_size + buffer_size/2; +#endif + /*@ assert file_recovery->data_check == \null || file_recovery->data_check == &data_check_continue; */ + /*@ assert file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; */ + return DC_CONTINUE; + } + else if(buffer[i+1]!=0x00) + { +#ifdef DEBUG_JPEG + log_info("%s data_check_jpg2 marker 0x%02x at 0x%llx\n", file_recovery->filename, buffer[i+1], + (long long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->offset_error=file_recovery->calculated_file_size; + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + /*@ assert file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; */ + return DC_STOP; + } + } + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + file_recovery->calculated_file_size++; + } + /*@ assert file_recovery->data_check == &data_check_jpg2; */ + /*@ assert file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0; */ + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 8; + @ requires file_recovery->data_check == &data_check_jpg; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == &data_check_jpg || file_recovery->data_check == &data_check_size || file_recovery->data_check == \null || file_recovery->data_check == &data_check_continue; + @ ensures file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2; + @ assigns file_recovery->calculated_file_size; + @ assigns file_recovery->data_check; + @ assigns file_recovery->file_check; + @ assigns file_recovery->offset_error; + @*/ +/* FIXME requires file_recovery->file_size == 0 || file_recovery->calculated_file_size >= file_recovery->file_size - 4; */ +/* FIXME ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4); */ +static data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /* Skip the SOI */ + if(file_recovery->calculated_file_size<2) + file_recovery->calculated_file_size=2; + /*@ assert file_recovery->calculated_file_size >= 2; */ + /*@ assert file_recovery->data_check == &data_check_jpg; */ + /* Search SOS */ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @ loop assigns file_recovery->data_check; + @ loop assigns file_recovery->file_check; + @ loop assigns file_recovery->offset_error; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + /*@ assert file_recovery->data_check == &data_check_jpg; */ + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + if(buffer[i]==0xFF && buffer[i+1]==0xFF) + file_recovery->calculated_file_size++; + else if(buffer[i]==0xFF) + { + const unsigned int size=(buffer[i+2]<<8)+buffer[i+3]; + const uint64_t old_calculated_file_size=file_recovery->calculated_file_size; +#ifdef DEBUG_JPEG + log_info("data_check_jpg %02x%02x at %llu, next expected at %llu\n", buffer[i], buffer[i+1], + (long long unsigned)file_recovery->calculated_file_size, + (long long unsigned)file_recovery->calculated_file_size+2+size); +#endif + file_recovery->calculated_file_size+=(uint64_t)2+size; + if(buffer[i+1]==0xc0) /* SOF0 */ + { + if(jpg_check_sof0(buffer, buffer_size, i)!=0) + { + /*@ assert file_recovery->data_check == &data_check_jpg; */ + return DC_STOP; + } + } + else if(buffer[i+1]==0xc4) /* DHT */ + { + if(jpg_check_dht(buffer, buffer_size, i, 2+size)!=0) + { + /*@ assert file_recovery->data_check == &data_check_jpg; */ + return DC_STOP; + } + } + else if(buffer[i+1]==0xda) /* SOS: Start Of Scan */ + { + data_check_t tmp; + file_recovery->data_check=&data_check_jpg2; + /*@ assert file_recovery->calculated_file_size >= 2; */ + tmp=data_check_jpg2(buffer, buffer_size, file_recovery); + /*@ assert file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == \null || file_recovery->data_check == &data_check_continue; */ + /*@ assert file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2; */ + return tmp; + } + else if(buffer[i+1]==0xe2) /* APP2 Exif information */ + { + if(i+8 < buffer_size && + buffer[i+4]=='M' && buffer[i+5]=='P' && buffer[i+6]=='F' && buffer[i+7]==0) + { + const uint64_t offset=old_calculated_file_size+8; + if(i>=buffer_size/2) + { + /* Restore previous value */ + file_recovery->calculated_file_size=old_calculated_file_size; + /*@ assert file_recovery->data_check == &data_check_jpg; */ + return DC_CONTINUE; + } + /*@ assert 0 <= i < buffer_size / 2 ; */ + if( i + size <= buffer_size) + { + /*@ assert i + size <= buffer_size; */ + /*@ assert size <= buffer_size - i; */ + if(size >= 16) + { + /*@ assert 16 <= size <= 65535; */ + /*@ assert \valid_read(buffer + (0 .. buffer_size-1)); */ + /*@ assert \valid_read(buffer + (0 .. i+size-1)); */ + /*@ assert \valid_read((buffer + i ) + (0 .. size-1)); */ + /*@ assert \valid_read((buffer + i + 8) + (0 .. size-8-1)); */ + const unsigned char *mpo=buffer + i + 8; + const unsigned int size_mpo=size-8; + /*@ assert \valid_read(mpo + (0 .. size-8-1)); */ + /*@ assert \valid_read(mpo + (0 .. size_mpo-1)); */ + const uint64_t calculated_file_size=check_mpo(mpo, offset, size_mpo); + if(calculated_file_size > 0) + { + /* Multi-picture format */ + file_recovery->calculated_file_size=calculated_file_size; + file_recovery->data_check=&data_check_size; + file_recovery->file_check=&file_check_mpo; + /*@ assert file_recovery->data_check == &data_check_size; */ + return DC_CONTINUE; + } + } + } + else + { + const unsigned int size_test=buffer_size-i; + /*@ assert size_test == buffer_size - i; */ + if(size_test >= 16) + { + /*@ assert 16 <= size_test; */ + const uint64_t calculated_file_size=check_mpo(buffer+i+8, offset, size_test-8); + if(calculated_file_size > 0) + { + /* Multi-picture format */ + file_recovery->calculated_file_size=calculated_file_size; + file_recovery->data_check=&data_check_size; + file_recovery->file_check=&file_check_mpo; + /*@ assert file_recovery->data_check == &data_check_size; */ + return DC_CONTINUE; + } + } + } + } + } + } + else + { +#if 0 + log_info("data_check_jpg %02x at %llu\n", buffer[i], + (long long unsigned)file_recovery->calculated_file_size); +#endif + /*@ assert file_recovery->data_check == &data_check_jpg; */ + return DC_STOP; + } + } + /*@ assert file_recovery->data_check == &data_check_jpg; */ + /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */ + /*X TODO assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */ + return DC_CONTINUE; +} + +const char*td_jpeg_version(void) +{ +#if defined(HAVE_LIBJPEG) +#ifdef LIBJPEG_TURBO_VERSION +#define td_xstr(s) td_str(s) +#define td_str(s) #s + static char buffer[32]; + sprintf(buffer,"libjpeg-turbo-%s", "" td_xstr(LIBJPEG_TURBO_VERSION)); + return buffer; +#elif defined(JPEG_LIB_VERSION) + static char buffer[32]; + sprintf(buffer,"%d", JPEG_LIB_VERSION); + return buffer; +#else + return "yes"; +#endif +#else + return "none"; +#endif +} + + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_jpg(file_stat_t *file_stat) +{ + static const unsigned char jpg_header[3]= { 0xff,0xd8,0xff}; + register_header_check(0, jpg_header, sizeof(jpg_header), &header_check_jpg, file_stat); +} +#endif + +#if defined(MAIN_jpg) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.jpg"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.offset_ok=0; + file_recovery_new.checkpoint_status=0; + file_recovery_new.location.start=0; + file_recovery_new.offset_error=0; + file_recovery_new.time=0; + + file_stats.file_hint=&file_hint_jpg; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_jpg(&file_stats); + if(header_check_jpg(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.file_check == file_check_jpg; */ + /*@ assert file_recovery_new.extension == file_hint_jpg.extension; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.offset_ok == 0; */ + /*@ assert valid_read_string((char *)&fn); */ + /*@ assert \initialized(&file_recovery_new.time); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert file_recovery_new.offset_ok == 0; */ + file_recovery_new.file_stat=&file_stats; + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_jpg; */ + /*@ assert file_recovery_new.file_size == 0; */; + res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + /*@ assert file_recovery_new.data_check == &data_check_jpg2 ==> file_recovery_new.calculated_file_size >= 2; */ + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + /*@ assert file_recovery_new.data_check == &data_check_jpg || file_recovery_new.data_check == &data_check_jpg2 || file_recovery_new.data_check == &data_check_size || file_recovery_new.data_check == NULL; */ + if(file_recovery_new.data_check == &data_check_jpg) + res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + else if(file_recovery_new.data_check == &data_check_jpg2) + res_data_check=data_check_jpg2(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + else if(file_recovery_new.data_check == &data_check_size) + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + /*@ assert file_recovery_new.data_check == &data_check_jpg || file_recovery_new.data_check == &data_check_jpg2 || file_recovery_new.data_check == &data_check_size || file_recovery_new.data_check == NULL; */ + if(file_recovery_new.data_check == &data_check_jpg) + res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + else if(file_recovery_new.data_check == &data_check_jpg2) + res_data_check=data_check_jpg2(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + else if(file_recovery_new.data_check == &data_check_size) + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + } + } + } + /*@ assert file_recovery_new.offset_ok == 0; */ + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_jpg(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert file_recovery_new.offset_ok == 0; */ + /*@ assert file_recovery_new.file_check == file_check_jpg || file_recovery_new.file_check == file_check_mpo; */ + if(file_recovery_new.file_check == file_check_jpg) + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_jpg(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + else + { + /*@ assert file_recovery_new.file_check == file_check_mpo; */ + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_mpo(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_jpg.h b/subprojects/lib/src/file_jpg.h new file mode 100644 index 0000000..d2093a8 --- /dev/null +++ b/subprojects/lib/src/file_jpg.h @@ -0,0 +1,33 @@ +/* + + File: file_jpg.h + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_JPG_H +#define _FILE_JPG_H +#ifdef __cplusplus +extern "C" { +#endif + +const char*td_jpeg_version(void); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_jsonlz4.c b/subprojects/lib/src/file_jsonlz4.c new file mode 100644 index 0000000..abb995f --- /dev/null +++ b/subprojects/lib/src/file_jsonlz4.c @@ -0,0 +1,72 @@ +/* + + File: file_jsonlz4.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jsonlz4) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_jsonlz4(file_stat_t *file_stat); + +const file_hint_t file_hint_jsonlz4= { + .extension="jsonlz4", + .description="Mozilla bookmarks", + .max_filesize=PHOTOREC_MAX_SIZE_32, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_jsonlz4 +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_jsonlz4, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_jsonlz4(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint32_t *uncompressed_size=(const uint32_t *)&buffer[8]; + const unsigned int size=le32(*uncompressed_size); + if(size==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_jsonlz4.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size_max; + return 1; +} + +static void register_header_check_jsonlz4(file_stat_t *file_stat) +{ + register_header_check(0, "mozLz40", 8, &header_check_jsonlz4, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_kdb.c b/subprojects/lib/src/file_kdb.c new file mode 100644 index 0000000..f9295c3 --- /dev/null +++ b/subprojects/lib/src/file_kdb.c @@ -0,0 +1,65 @@ +/* + + File: file_kdb.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_kdb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_kdb(file_stat_t *file_stat); + +const file_hint_t file_hint_kdb= { + .extension="kdb", + .description="KeePassX", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_kdb +}; + +/*@ + @ requires separation: \separated(&file_hint_kdb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_kdb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_kdb.extension; + file_recovery_new->min_filesize=124; + return 1; +} + +static void register_header_check_kdb(file_stat_t *file_stat) +{ + static const unsigned char kdb_header[8]= {0x03, 0xd9, 0xa2, 0x9a, 0x65, 0xfb, 0x4b, 0xb5}; + register_header_check(0, kdb_header,sizeof(kdb_header), &header_check_kdb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_kdbx.c b/subprojects/lib/src/file_kdbx.c new file mode 100644 index 0000000..930c7f8 --- /dev/null +++ b/subprojects/lib/src/file_kdbx.c @@ -0,0 +1,65 @@ +/* + + File: file_kdbx.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_kdbx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_kdbx(file_stat_t *file_stat); + +const file_hint_t file_hint_kdbx= { + .extension="kdbx", + .description="KeePassX", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_kdbx +}; + +/*@ + @ requires separation: \separated(&file_hint_kdbx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_kdbx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_kdbx.extension; + file_recovery_new->min_filesize=124; + return 1; +} + +static void register_header_check_kdbx(file_stat_t *file_stat) +{ + static const unsigned char kdbx_header[8]= {0x03, 0xd9, 0xa2, 0x9a, 0x67, 0xfb, 0x4b, 0xb5}; + register_header_check(0, kdbx_header,sizeof(kdbx_header), &header_check_kdbx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_key.c b/subprojects/lib/src/file_key.c new file mode 100644 index 0000000..d1cfbd9 --- /dev/null +++ b/subprojects/lib/src/file_key.c @@ -0,0 +1,66 @@ +/* + + File: file_key.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_key) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_key(file_stat_t *file_stat); + +const file_hint_t file_hint_key= { + .extension="key", + .description="Synology AES key", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_key +}; + +/*@ + @ requires separation: \separated(&file_hint_key, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_key(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_key.extension; + file_recovery_new->calculated_file_size=32; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_key(file_stat_t *file_stat) +{ + register_header_check(0, "323382b3c4f1c6d2", 16, &header_check_key, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ldf.c b/subprojects/lib/src/file_ldf.c new file mode 100644 index 0000000..8279010 --- /dev/null +++ b/subprojects/lib/src/file_ldf.c @@ -0,0 +1,74 @@ +/* + + File: file_ldf.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ldf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ldf(file_stat_t *file_stat); + +const file_hint_t file_hint_ldf= { + .extension="ldf", + .description="Microsoft SQL Server Log Data File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ldf +}; + +/*@ + @ requires buffer_size >= 0x1c; + @ requires separation: \separated(&file_hint_ldf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ldf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0x00]==0x01 && buffer[0x01]==0x0f && buffer[0x02]==0x00 && buffer[0x03]==0x00 && + buffer[0x08]==0x00 && buffer[0x09]==0x00 && buffer[0x0a]==0x00 && buffer[0x0b]==0x00 && + buffer[0x0c]==0x00 && buffer[0x0d]==0x00 && buffer[0x0e]==0x00 && buffer[0x0f]==0x00 && + buffer[0x10]==0x00 && buffer[0x11]==0x00 && buffer[0x12]==0x00 && buffer[0x13]==0x00 && + buffer[0x14]==0x00 && buffer[0x15]==0x00 && buffer[0x16]==0x02 && buffer[0x17]==0x00 && + buffer[0x18]==0x63 && buffer[0x19]==0x00 && buffer[0x1A]==0x00 && buffer[0x1B]==0x00) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ldf.extension; + return 1; + } + return 0; +} + +static void register_header_check_ldf(file_stat_t *file_stat) +{ + static const unsigned char ldf_header[4]= { 0x01, 0x0f, 0x00, 0x00 }; + register_header_check(0, ldf_header,sizeof(ldf_header), &header_check_ldf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_list.c b/subprojects/lib/src/file_list.c new file mode 100644 index 0000000..0e0ea87 --- /dev/null +++ b/subprojects/lib/src/file_list.c @@ -0,0 +1,1426 @@ +/* + + File: file_list.c + + Copyright (C) 1998-2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include "types.h" +#include "filegen.h" + +extern const file_hint_t file_hint_1cd; +extern const file_hint_t file_hint_3dm; +extern const file_hint_t file_hint_3ds; +extern const file_hint_t file_hint_7z; +extern const file_hint_t file_hint_DB; +extern const file_hint_t file_hint_a; +extern const file_hint_t file_hint_abr; +extern const file_hint_t file_hint_acb; +extern const file_hint_t file_hint_accdb; +extern const file_hint_t file_hint_ace; +extern const file_hint_t file_hint_addressbook; +extern const file_hint_t file_hint_ado; +extern const file_hint_t file_hint_afdesign; +extern const file_hint_t file_hint_ahn; +extern const file_hint_t file_hint_aif; +extern const file_hint_t file_hint_all; +extern const file_hint_t file_hint_als; +extern const file_hint_t file_hint_amd; +extern const file_hint_t file_hint_amr; +extern const file_hint_t file_hint_apa; +extern const file_hint_t file_hint_ape; +extern const file_hint_t file_hint_apple; +extern const file_hint_t file_hint_ari; +extern const file_hint_t file_hint_arj; +extern const file_hint_t file_hint_asf; +extern const file_hint_t file_hint_asl; +extern const file_hint_t file_hint_asm; +extern const file_hint_t file_hint_atd; +extern const file_hint_t file_hint_au; +extern const file_hint_t file_hint_axp; +extern const file_hint_t file_hint_axx; +extern const file_hint_t file_hint_bac; +extern const file_hint_t file_hint_bdm; +extern const file_hint_t file_hint_berkeley; +extern const file_hint_t file_hint_bfa; +extern const file_hint_t file_hint_bim; +extern const file_hint_t file_hint_bin; +extern const file_hint_t file_hint_binvox; +extern const file_hint_t file_hint_bkf; +extern const file_hint_t file_hint_blend; +extern const file_hint_t file_hint_bmp; +extern const file_hint_t file_hint_bpg; +extern const file_hint_t file_hint_bvr; +extern const file_hint_t file_hint_bz2; +extern const file_hint_t file_hint_c4d; +extern const file_hint_t file_hint_cab; +extern const file_hint_t file_hint_caf; +extern const file_hint_t file_hint_cam; +extern const file_hint_t file_hint_catdrawing; +extern const file_hint_t file_hint_cdt; +extern const file_hint_t file_hint_che; +extern const file_hint_t file_hint_chm; +extern const file_hint_t file_hint_class; +extern const file_hint_t file_hint_clip; +extern const file_hint_t file_hint_cm; +extern const file_hint_t file_hint_compress; +extern const file_hint_t file_hint_cow; +extern const file_hint_t file_hint_cpi; +extern const file_hint_t file_hint_crw; +extern const file_hint_t file_hint_csh; +extern const file_hint_t file_hint_ctg; +extern const file_hint_t file_hint_cwk; +extern const file_hint_t file_hint_d2s; +extern const file_hint_t file_hint_dad; +extern const file_hint_t file_hint_dar; +extern const file_hint_t file_hint_dat; +extern const file_hint_t file_hint_dbf; +extern const file_hint_t file_hint_dbn; +extern const file_hint_t file_hint_dcm; +extern const file_hint_t file_hint_ddf; +extern const file_hint_t file_hint_dex; +extern const file_hint_t file_hint_dim; +extern const file_hint_t file_hint_dir; +extern const file_hint_t file_hint_djv; +extern const file_hint_t file_hint_dmp; +extern const file_hint_t file_hint_doc; +extern const file_hint_t file_hint_dpx; +extern const file_hint_t file_hint_drw; +extern const file_hint_t file_hint_drw2; +extern const file_hint_t file_hint_ds2; +extern const file_hint_t file_hint_ds_store; +extern const file_hint_t file_hint_dsc; +extern const file_hint_t file_hint_dss; +extern const file_hint_t file_hint_dst; +extern const file_hint_t file_hint_dta; +extern const file_hint_t file_hint_dump; +extern const file_hint_t file_hint_dv; +extern const file_hint_t file_hint_dvi; +extern const file_hint_t file_hint_dvr; +extern const file_hint_t file_hint_dwg; +extern const file_hint_t file_hint_dxf; +extern const file_hint_t file_hint_e01; +extern const file_hint_t file_hint_ecryptfs; +extern const file_hint_t file_hint_edb; +extern const file_hint_t file_hint_elf; +extern const file_hint_t file_hint_emf; +extern const file_hint_t file_hint_ess; +extern const file_hint_t file_hint_evt; +extern const file_hint_t file_hint_evtx; +extern const file_hint_t file_hint_exe; +extern const file_hint_t file_hint_exr; +extern const file_hint_t file_hint_exs; +extern const file_hint_t file_hint_ext2_sb; +extern const file_hint_t file_hint_ext2_fs; +extern const file_hint_t file_hint_fat; +extern const file_hint_t file_hint_fbf; +extern const file_hint_t file_hint_fbk; +extern const file_hint_t file_hint_fcp; +extern const file_hint_t file_hint_fcs; +extern const file_hint_t file_hint_fdb; +extern const file_hint_t file_hint_fds; +extern const file_hint_t file_hint_fh10; +extern const file_hint_t file_hint_fh5; +extern const file_hint_t file_hint_filevault; +extern const file_hint_t file_hint_fits; +extern const file_hint_t file_hint_fit; +extern const file_hint_t file_hint_flac; +extern const file_hint_t file_hint_fasttxt; +extern const file_hint_t file_hint_flp; +extern const file_hint_t file_hint_flv; +extern const file_hint_t file_hint_fm; +extern const file_hint_t file_hint_fob; +extern const file_hint_t file_hint_fos; +extern const file_hint_t file_hint_fp5; +extern const file_hint_t file_hint_fp7; +extern const file_hint_t file_hint_freeway; +extern const file_hint_t file_hint_frm; +extern const file_hint_t file_hint_fs; +extern const file_hint_t file_hint_fwd; +extern const file_hint_t file_hint_gam; +extern const file_hint_t file_hint_gct; +extern const file_hint_t file_hint_gho; +extern const file_hint_t file_hint_gi; +extern const file_hint_t file_hint_gif; +extern const file_hint_t file_hint_gm6; +extern const file_hint_t file_hint_gp2; +extern const file_hint_t file_hint_gp5; +extern const file_hint_t file_hint_gpg; +extern const file_hint_t file_hint_gpx; +extern const file_hint_t file_hint_gsm; +extern const file_hint_t file_hint_gz; +extern const file_hint_t file_hint_hdf; +extern const file_hint_t file_hint_hdr; +extern const file_hint_t file_hint_hds; +extern const file_hint_t file_hint_hfsp; +extern const file_hint_t file_hint_hm; +extern const file_hint_t file_hint_hr9; +extern const file_hint_t file_hint_http; +extern const file_hint_t file_hint_ibd; +extern const file_hint_t file_hint_icc; +extern const file_hint_t file_hint_icns; +extern const file_hint_t file_hint_ico; +extern const file_hint_t file_hint_idx; +extern const file_hint_t file_hint_ifo; +extern const file_hint_t file_hint_imb; +extern const file_hint_t file_hint_indd; +extern const file_hint_t file_hint_info; +extern const file_hint_t file_hint_iso; +extern const file_hint_t file_hint_it; +extern const file_hint_t file_hint_itunes; +extern const file_hint_t file_hint_jks; +extern const file_hint_t file_hint_jpg; +extern const file_hint_t file_hint_jsonlz4; +extern const file_hint_t file_hint_kdb; +extern const file_hint_t file_hint_kdbx; +extern const file_hint_t file_hint_key; +extern const file_hint_t file_hint_ldf; +extern const file_hint_t file_hint_lit; +extern const file_hint_t file_hint_logic; +extern const file_hint_t file_hint_lnk; +extern const file_hint_t file_hint_lso; +extern const file_hint_t file_hint_luks; +extern const file_hint_t file_hint_lxo; +extern const file_hint_t file_hint_lzh; +extern const file_hint_t file_hint_lzo; +extern const file_hint_t file_hint_m2ts; +extern const file_hint_t file_hint_mat; +extern const file_hint_t file_hint_max; +extern const file_hint_t file_hint_mb; +extern const file_hint_t file_hint_mcd; +extern const file_hint_t file_hint_mdb; +extern const file_hint_t file_hint_mdf; +extern const file_hint_t file_hint_mdp; +extern const file_hint_t file_hint_mfa; +extern const file_hint_t file_hint_mfg; +extern const file_hint_t file_hint_mft; +extern const file_hint_t file_hint_mid; +extern const file_hint_t file_hint_mig; +extern const file_hint_t file_hint_mk5; +extern const file_hint_t file_hint_mkv; +extern const file_hint_t file_hint_mlv; +extern const file_hint_t file_hint_mobi; +extern const file_hint_t file_hint_mov; +extern const file_hint_t file_hint_mov_mdat; +extern const file_hint_t file_hint_mp3; +extern const file_hint_t file_hint_mpg; +extern const file_hint_t file_hint_mpl; +extern const file_hint_t file_hint_mrw; +extern const file_hint_t file_hint_msa; +extern const file_hint_t file_hint_mus; +extern const file_hint_t file_hint_mxf; +extern const file_hint_t file_hint_myo; +extern const file_hint_t file_hint_mysql; +extern const file_hint_t file_hint_nd2; +extern const file_hint_t file_hint_nds; +extern const file_hint_t file_hint_nes; +extern const file_hint_t file_hint_njx; +extern const file_hint_t file_hint_nk2; +extern const file_hint_t file_hint_nsf; +extern const file_hint_t file_hint_oci; +extern const file_hint_t file_hint_ogg; +extern const file_hint_t file_hint_one; +extern const file_hint_t file_hint_orf; +extern const file_hint_t file_hint_paf; +extern const file_hint_t file_hint_pap; +extern const file_hint_t file_hint_par2; +extern const file_hint_t file_hint_pcap; +extern const file_hint_t file_hint_pcb; +extern const file_hint_t file_hint_pct; +extern const file_hint_t file_hint_pcx; +extern const file_hint_t file_hint_pdb; +extern const file_hint_t file_hint_pdf; +extern const file_hint_t file_hint_pds; +extern const file_hint_t file_hint_pf; +extern const file_hint_t file_hint_pfx; +extern const file_hint_t file_hint_pgdump; +extern const file_hint_t file_hint_plist; +extern const file_hint_t file_hint_plr; +extern const file_hint_t file_hint_plt; +extern const file_hint_t file_hint_png; +extern const file_hint_t file_hint_pnm; +extern const file_hint_t file_hint_prc; +extern const file_hint_t file_hint_prd; +extern const file_hint_t file_hint_prt; +extern const file_hint_t file_hint_ps; +extern const file_hint_t file_hint_psb; +extern const file_hint_t file_hint_psd; +extern const file_hint_t file_hint_psf; +extern const file_hint_t file_hint_psp; +extern const file_hint_t file_hint_pst; +extern const file_hint_t file_hint_ptb; +extern const file_hint_t file_hint_ptf; +extern const file_hint_t file_hint_pyc; +extern const file_hint_t file_hint_pzf; +extern const file_hint_t file_hint_pzh; +extern const file_hint_t file_hint_qbb; +extern const file_hint_t file_hint_qdf; +extern const file_hint_t file_hint_qkt; +extern const file_hint_t file_hint_qxd; +extern const file_hint_t file_hint_r3d; +extern const file_hint_t file_hint_ra; +extern const file_hint_t file_hint_raf; +extern const file_hint_t file_hint_rar; +extern const file_hint_t file_hint_raw; +extern const file_hint_t file_hint_rdc; +extern const file_hint_t file_hint_reg; +extern const file_hint_t file_hint_res; +extern const file_hint_t file_hint_rfp; +extern const file_hint_t file_hint_riff; +extern const file_hint_t file_hint_rlv; +extern const file_hint_t file_hint_rm; +extern const file_hint_t file_hint_rns; +extern const file_hint_t file_hint_rpm; +extern const file_hint_t file_hint_rw2; +extern const file_hint_t file_hint_rx2; +extern const file_hint_t file_hint_save; +extern const file_hint_t file_hint_sdsk; +extern const file_hint_t file_hint_ses; +extern const file_hint_t file_hint_sgcta; +extern const file_hint_t file_hint_shn; +extern const file_hint_t file_hint_sib; +extern const file_hint_t file_hint_sig; +extern const file_hint_t file_hint_sit; +extern const file_hint_t file_hint_skd; +extern const file_hint_t file_hint_skp; +extern const file_hint_t file_hint_snag; +extern const file_hint_t file_hint_snz; +extern const file_hint_t file_hint_sp3; +extern const file_hint_t file_hint_spe; +extern const file_hint_t file_hint_spf; +extern const file_hint_t file_hint_spss; +extern const file_hint_t file_hint_sqlite; +extern const file_hint_t file_hint_sqm; +extern const file_hint_t file_hint_steuer2014; +extern const file_hint_t file_hint_stl; +extern const file_hint_t file_hint_studio; +extern const file_hint_t file_hint_stuffit; +extern const file_hint_t file_hint_swf; +extern const file_hint_t file_hint_tar; +extern const file_hint_t file_hint_tax; +extern const file_hint_t file_hint_tg; +extern const file_hint_t file_hint_tib; +extern const file_hint_t file_hint_tiff; +extern const file_hint_t file_hint_tivo; +extern const file_hint_t file_hint_torrent; +extern const file_hint_t file_hint_tph; +extern const file_hint_t file_hint_tpl; +extern const file_hint_t file_hint_ts; +extern const file_hint_t file_hint_ttf; +extern const file_hint_t file_hint_txt; +extern const file_hint_t file_hint_tz; +extern const file_hint_t file_hint_v2i; +extern const file_hint_t file_hint_vault; +extern const file_hint_t file_hint_vdi; +extern const file_hint_t file_hint_vdj; +extern const file_hint_t file_hint_veg; +extern const file_hint_t file_hint_vfb; +extern const file_hint_t file_hint_vib; +extern const file_hint_t file_hint_vmdk; +extern const file_hint_t file_hint_vmg; +extern const file_hint_t file_hint_wad; +extern const file_hint_t file_hint_wallet; +extern const file_hint_t file_hint_wdp; +extern const file_hint_t file_hint_wee; +extern const file_hint_t file_hint_wim; +extern const file_hint_t file_hint_win; +extern const file_hint_t file_hint_wks; +extern const file_hint_t file_hint_wld; +extern const file_hint_t file_hint_wmf; +extern const file_hint_t file_hint_wnk; +extern const file_hint_t file_hint_woff; +extern const file_hint_t file_hint_wpb; +extern const file_hint_t file_hint_wpd; +extern const file_hint_t file_hint_wtv; +extern const file_hint_t file_hint_wv; +extern const file_hint_t file_hint_x3f; +extern const file_hint_t file_hint_x3i; +extern const file_hint_t file_hint_x4a; +extern const file_hint_t file_hint_xar; +extern const file_hint_t file_hint_xcf; +extern const file_hint_t file_hint_xfi; +extern const file_hint_t file_hint_xfs; +extern const file_hint_t file_hint_xm; +extern const file_hint_t file_hint_xml; +extern const file_hint_t file_hint_xsv; +extern const file_hint_t file_hint_xpt; +extern const file_hint_t file_hint_xv; +extern const file_hint_t file_hint_xz; +extern const file_hint_t file_hint_z2d; +extern const file_hint_t file_hint_zcode; +extern const file_hint_t file_hint_zip; +extern const file_hint_t file_hint_zpr; + +file_enable_t array_file_enable[]= +{ +#if ((!defined(SINGLE_FORMAT) && !defined(__FRAMAC__)) || defined(SINGLE_FORMAT_sig)) + { .enable=0, .file_hint=&file_hint_sig }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_1cd) + { .enable=0, .file_hint=&file_hint_1cd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_3dm) + { .enable=0, .file_hint=&file_hint_3dm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_3ds) + { .enable=0, .file_hint=&file_hint_3ds }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_7z) + { .enable=0, .file_hint=&file_hint_7z }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_DB) + { .enable=0, .file_hint=&file_hint_DB }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_a) + { .enable=0, .file_hint=&file_hint_a }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_abr) + { .enable=0, .file_hint=&file_hint_abr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_acb) + { .enable=0, .file_hint=&file_hint_acb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdb) + { .enable=0, .file_hint=&file_hint_accdb}, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ace) + { .enable=0, .file_hint=&file_hint_ace }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_addressbook) + { .enable=0, .file_hint=&file_hint_addressbook}, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ado) + { .enable=0, .file_hint=&file_hint_ado }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_afdesign) + { .enable=0, .file_hint=&file_hint_afdesign }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ahn) + { .enable=0, .file_hint=&file_hint_ahn }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_aif) + { .enable=0, .file_hint=&file_hint_aif }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_all) + { .enable=0, .file_hint=&file_hint_all }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_als) + { .enable=0, .file_hint=&file_hint_als }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_amd) + { .enable=0, .file_hint=&file_hint_amd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_amr) + { .enable=0, .file_hint=&file_hint_amr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_apa) + { .enable=0, .file_hint=&file_hint_apa }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ape) + { .enable=0, .file_hint=&file_hint_ape }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_apple) + { .enable=0, .file_hint=&file_hint_apple }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ari) + { .enable=0, .file_hint=&file_hint_ari }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_arj) + { .enable=0, .file_hint=&file_hint_arj }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asf) + { .enable=0, .file_hint=&file_hint_asf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asl) + { .enable=0, .file_hint=&file_hint_asl }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_asm) + { .enable=0, .file_hint=&file_hint_asm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_atd) + { .enable=0, .file_hint=&file_hint_atd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_au) + { .enable=0, .file_hint=&file_hint_au }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_axp) + { .enable=0, .file_hint=&file_hint_axp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_axx) + { .enable=0, .file_hint=&file_hint_axx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bac) + { .enable=0, .file_hint=&file_hint_bac }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bdm) + { .enable=0, .file_hint=&file_hint_bdm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_berkeley) + { .enable=0, .file_hint=&file_hint_berkeley }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bfa) + { .enable=0, .file_hint=&file_hint_bfa }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bim) + { .enable=0, .file_hint=&file_hint_bim }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bin) + { .enable=0, .file_hint=&file_hint_bin }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_binvox) + { .enable=0, .file_hint=&file_hint_binvox }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bkf) + { .enable=0, .file_hint=&file_hint_bkf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_blend) + { .enable=0, .file_hint=&file_hint_blend }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bmp) + { .enable=0, .file_hint=&file_hint_bmp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bpg) + { .enable=0, .file_hint=&file_hint_bpg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bvr) + { .enable=0, .file_hint=&file_hint_bvr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_bz2) + { .enable=0, .file_hint=&file_hint_bz2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_c4d) + { .enable=0, .file_hint=&file_hint_c4d }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cab) + { .enable=0, .file_hint=&file_hint_cab }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_caf) + { .enable=0, .file_hint=&file_hint_caf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cam) + { .enable=0, .file_hint=&file_hint_cam }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_catdrawing) + { .enable=0, .file_hint=&file_hint_catdrawing }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cdt) + { .enable=0, .file_hint=&file_hint_cdt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_che) + { .enable=0, .file_hint=&file_hint_che }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_chm) + { .enable=0, .file_hint=&file_hint_chm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_class) + { .enable=0, .file_hint=&file_hint_class }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_clip) + { .enable=0, .file_hint=&file_hint_clip }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cm) + { .enable=0, .file_hint=&file_hint_cm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_compress) + { .enable=0, .file_hint=&file_hint_compress }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cow) + { .enable=0, .file_hint=&file_hint_cow }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cpi) + { .enable=0, .file_hint=&file_hint_cpi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_crw) + { .enable=0, .file_hint=&file_hint_crw }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_csh) + { .enable=0, .file_hint=&file_hint_csh }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ctg) + { .enable=0, .file_hint=&file_hint_ctg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_cwk) + { .enable=0, .file_hint=&file_hint_cwk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_d2s) + { .enable=0, .file_hint=&file_hint_d2s }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dad) + { .enable=0, .file_hint=&file_hint_dad }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dar) + { .enable=0, .file_hint=&file_hint_dar }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dat) + { .enable=0, .file_hint=&file_hint_dat }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dbf) + { .enable=0, .file_hint=&file_hint_dbf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dbn) + { .enable=0, .file_hint=&file_hint_dbn }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dcm) + { .enable=0, .file_hint=&file_hint_dcm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ddf) + { .enable=0, .file_hint=&file_hint_ddf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dex) + { .enable=0, .file_hint=&file_hint_dex }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dim) + { .enable=0, .file_hint=&file_hint_dim }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dir) + { .enable=0, .file_hint=&file_hint_dir }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_djv) + { .enable=0, .file_hint=&file_hint_djv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dmp) + { .enable=0, .file_hint=&file_hint_dmp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_drw) + { .enable=0, .file_hint=&file_hint_drw }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_drw2) + { .enable=0, .file_hint=&file_hint_drw2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_doc) + { .enable=0, .file_hint=&file_hint_doc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dpx) + { .enable=0, .file_hint=&file_hint_dpx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ds2) + { .enable=0, .file_hint=&file_hint_ds2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ds_store) + { .enable=0, .file_hint=&file_hint_ds_store }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dsc) + { .enable=0, .file_hint=&file_hint_dsc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dss) + { .enable=0, .file_hint=&file_hint_dss }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dst) + { .enable=0, .file_hint=&file_hint_dst }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dta) + { .enable=0, .file_hint=&file_hint_dta }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dump) + { .enable=0, .file_hint=&file_hint_dump }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dv) + { .enable=0, .file_hint=&file_hint_dv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dvi) + { .enable=0, .file_hint=&file_hint_dvi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dvr) + { .enable=0, .file_hint=&file_hint_dvr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dwg) + { .enable=0, .file_hint=&file_hint_dwg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_dxf) + { .enable=0, .file_hint=&file_hint_dxf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_e01) + { .enable=0, .file_hint=&file_hint_e01 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ecryptfs) + { .enable=0, .file_hint=&file_hint_ecryptfs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_edb) + { .enable=0, .file_hint=&file_hint_edb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_elf) + { .enable=0, .file_hint=&file_hint_elf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_emf) + { .enable=0, .file_hint=&file_hint_emf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ess) + { .enable=0, .file_hint=&file_hint_ess }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_evt) + { .enable=0, .file_hint=&file_hint_evt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_evtx) + { .enable=0, .file_hint=&file_hint_evtx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exe) + { .enable=0, .file_hint=&file_hint_exe }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exr) + { .enable=0, .file_hint=&file_hint_exr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_exs) + { .enable=0, .file_hint=&file_hint_exs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ext2_sb) + { .enable=0, .file_hint=&file_hint_ext2_sb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ext2_fs) + { .enable=0, .file_hint=&file_hint_ext2_fs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fat) + { .enable=0, .file_hint=&file_hint_fat }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fbf) + { .enable=0, .file_hint=&file_hint_fbf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fbk) + { .enable=0, .file_hint=&file_hint_fbk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fcp) + { .enable=0, .file_hint=&file_hint_fcp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fcs) + { .enable=0, .file_hint=&file_hint_fcs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fdb) + { .enable=0, .file_hint=&file_hint_fdb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fds) + { .enable=0, .file_hint=&file_hint_fds }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fh10) + { .enable=0, .file_hint=&file_hint_fh10 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fh5) + { .enable=0, .file_hint=&file_hint_fh5 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_filevault) + { .enable=0, .file_hint=&file_hint_filevault }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fits) + { .enable=0, .file_hint=&file_hint_fits }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fit) + { .enable=0, .file_hint=&file_hint_fit }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flac) + { .enable=0, .file_hint=&file_hint_flac }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flp) + { .enable=0, .file_hint=&file_hint_flp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_flv) + { .enable=0, .file_hint=&file_hint_flv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fm) + { .enable=0, .file_hint=&file_hint_fm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fob) + { .enable=0, .file_hint=&file_hint_fob }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fos) + { .enable=0, .file_hint=&file_hint_fos }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fp5) + { .enable=0, .file_hint=&file_hint_fp5 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fp7) + { .enable=0, .file_hint=&file_hint_fp7 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_freeway) + { .enable=0, .file_hint=&file_hint_freeway }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_frm) + { .enable=0, .file_hint=&file_hint_frm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fs) + { .enable=0, .file_hint=&file_hint_fs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_fwd) + { .enable=0, .file_hint=&file_hint_fwd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gam) + { .enable=0, .file_hint=&file_hint_gam }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gct) + { .enable=0, .file_hint=&file_hint_gct }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gho) + { .enable=0, .file_hint=&file_hint_gho }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gi) + { .enable=0, .file_hint=&file_hint_gi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gif) + { .enable=0, .file_hint=&file_hint_gif }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gm6) + { .enable=0, .file_hint=&file_hint_gm6 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gp2) + { .enable=0, .file_hint=&file_hint_gp2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gp5) + { .enable=0, .file_hint=&file_hint_gp5 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gpg) + { .enable=0, .file_hint=&file_hint_gpg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gpx) + { .enable=0, .file_hint=&file_hint_gpx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gsm) + { .enable=0, .file_hint=&file_hint_gsm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_gz) + { .enable=0, .file_hint=&file_hint_gz }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hdf) + { .enable=0, .file_hint=&file_hint_hdf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hdr) + { .enable=0, .file_hint=&file_hint_hdr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hds) + { .enable=0, .file_hint=&file_hint_hds }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hfsp) + { .enable=0, .file_hint=&file_hint_hfsp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hm) + { .enable=0, .file_hint=&file_hint_hm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_hr9) + { .enable=0, .file_hint=&file_hint_hr9 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_http) + { .enable=0, .file_hint=&file_hint_http }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ibd) + { .enable=0, .file_hint=&file_hint_ibd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_icc) + { .enable=0, .file_hint=&file_hint_icc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_icns) + { .enable=0, .file_hint=&file_hint_icns }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ico) + { .enable=0, .file_hint=&file_hint_ico }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_idx) + { .enable=0, .file_hint=&file_hint_idx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ifo) + { .enable=0, .file_hint=&file_hint_ifo }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_imb) + { .enable=0, .file_hint=&file_hint_imb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_indd) + { .enable=0, .file_hint=&file_hint_indd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_info) + { .enable=0, .file_hint=&file_hint_info }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_iso) + { .enable=0, .file_hint=&file_hint_iso }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_it) + { .enable=0, .file_hint=&file_hint_it }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_itunes) + { .enable=0, .file_hint=&file_hint_itunes }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jks) + { .enable=0, .file_hint=&file_hint_jks }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) + { .enable=0, .file_hint=&file_hint_jpg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jsonlz4) + { .enable=0, .file_hint=&file_hint_jsonlz4 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_kdb) + { .enable=0, .file_hint=&file_hint_kdb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_kdbx) + { .enable=0, .file_hint=&file_hint_kdbx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_key) + { .enable=0, .file_hint=&file_hint_key }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ldf) + { .enable=0, .file_hint=&file_hint_ldf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lit) + { .enable=0, .file_hint=&file_hint_lit }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_logic) + { .enable=0, .file_hint=&file_hint_logic}, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lnk) + { .enable=0, .file_hint=&file_hint_lnk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lso) + { .enable=0, .file_hint=&file_hint_lso }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_luks) + { .enable=0, .file_hint=&file_hint_luks }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lxo) + { .enable=0, .file_hint=&file_hint_lxo }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lzh) + { .enable=0, .file_hint=&file_hint_lzh }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lzo) + { .enable=0, .file_hint=&file_hint_lzo }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_m2ts) + { .enable=0, .file_hint=&file_hint_m2ts }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mat) + { .enable=0, .file_hint=&file_hint_mat }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_max) + { .enable=0, .file_hint=&file_hint_max }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mb) + { .enable=0, .file_hint=&file_hint_mb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mcd) + { .enable=0, .file_hint=&file_hint_mcd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdb) + { .enable=0, .file_hint=&file_hint_mdb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdf) + { .enable=0, .file_hint=&file_hint_mdf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdp) + { .enable=0, .file_hint=&file_hint_mdp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mfa) + { .enable=0, .file_hint=&file_hint_mfa }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mfg) + { .enable=0, .file_hint=&file_hint_mfg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mft) + { .enable=0, .file_hint=&file_hint_mft }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mid) + { .enable=0, .file_hint=&file_hint_mid }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mig) + { .enable=0, .file_hint=&file_hint_mig }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mk5) + { .enable=0, .file_hint=&file_hint_mk5 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mkv) + { .enable=0, .file_hint=&file_hint_mkv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mlv) + { .enable=0, .file_hint=&file_hint_mlv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mobi) + { .enable=0, .file_hint=&file_hint_mobi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mov_mdat) + { .enable=0, .file_hint=&file_hint_mov_mdat }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mov) + { .enable=0, .file_hint=&file_hint_mov }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mp3) + { .enable=0, .file_hint=&file_hint_mp3 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mpg) + { .enable=0, .file_hint=&file_hint_mpg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mpl) + { .enable=0, .file_hint=&file_hint_mpl }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mrw) + { .enable=0, .file_hint=&file_hint_mrw }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_msa) + { .enable=0, .file_hint=&file_hint_msa }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mus) + { .enable=0, .file_hint=&file_hint_mus }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_myo) + { .enable=0, .file_hint=&file_hint_myo }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mysql) + { .enable=0, .file_hint=&file_hint_mysql }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mxf) + { .enable=0, .file_hint=&file_hint_mxf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nd2) + { .enable=0, .file_hint=&file_hint_nd2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nds) + { .enable=0, .file_hint=&file_hint_nds }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nes) + { .enable=0, .file_hint=&file_hint_nes }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_njx) + { .enable=0, .file_hint=&file_hint_njx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nk2) + { .enable=0, .file_hint=&file_hint_nk2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nsf) + { .enable=0, .file_hint=&file_hint_nsf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_oci) + { .enable=0, .file_hint=&file_hint_oci }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ogg) + { .enable=0, .file_hint=&file_hint_ogg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_one) + { .enable=0, .file_hint=&file_hint_one }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_orf) + { .enable=0, .file_hint=&file_hint_orf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_paf) + { .enable=0, .file_hint=&file_hint_paf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pap) + { .enable=0, .file_hint=&file_hint_pap }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_par2) + { .enable=0, .file_hint=&file_hint_par2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcap) + { .enable=0, .file_hint=&file_hint_pcap }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcb) + { .enable=0, .file_hint=&file_hint_pcb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pct) + { .enable=0, .file_hint=&file_hint_pct }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcx) + { .enable=0, .file_hint=&file_hint_pcx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pdb) + { .enable=0, .file_hint=&file_hint_pdb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pdf) + { .enable=0, .file_hint=&file_hint_pdf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pds) + { .enable=0, .file_hint=&file_hint_pds }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pf) + { .enable=0, .file_hint=&file_hint_pf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pfx) + { .enable=0, .file_hint=&file_hint_pfx }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pgdump) + { .enable=0, .file_hint=&file_hint_pgdump }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plist) + { .enable=0, .file_hint=&file_hint_plist }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plr) + { .enable=0, .file_hint=&file_hint_plr }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plt) + { .enable=0, .file_hint=&file_hint_plt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_png) + { .enable=0, .file_hint=&file_hint_png }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pnm) + { .enable=0, .file_hint=&file_hint_pnm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prc) + { .enable=0, .file_hint=&file_hint_prc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prd) + { .enable=0, .file_hint=&file_hint_prd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prt) + { .enable=0, .file_hint=&file_hint_prt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ps) + { .enable=0, .file_hint=&file_hint_ps }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psb) + { .enable=0, .file_hint=&file_hint_psb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psd) + { .enable=0, .file_hint=&file_hint_psd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psf) + { .enable=0, .file_hint=&file_hint_psf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psp) + { .enable=0, .file_hint=&file_hint_psp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pst) + { .enable=0, .file_hint=&file_hint_pst }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ptb) + { .enable=0, .file_hint=&file_hint_ptb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ptf) + { .enable=0, .file_hint=&file_hint_ptf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pyc) + { .enable=0, .file_hint=&file_hint_pyc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pzf) + { .enable=0, .file_hint=&file_hint_pzf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pzh) + { .enable=0, .file_hint=&file_hint_pzh }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qbb) + { .enable=0, .file_hint=&file_hint_qbb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qdf) + { .enable=0, .file_hint=&file_hint_qdf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qkt) + { .enable=0, .file_hint=&file_hint_qkt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qxd) + { .enable=0, .file_hint=&file_hint_qxd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_r3d) + { .enable=0, .file_hint=&file_hint_r3d }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ra) + { .enable=0, .file_hint=&file_hint_ra }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_raf) + { .enable=0, .file_hint=&file_hint_raf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rar) + { .enable=0, .file_hint=&file_hint_rar }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_raw) + { .enable=0, .file_hint=&file_hint_raw }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rdc) + { .enable=0, .file_hint=&file_hint_rdc }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_reg) + { .enable=0, .file_hint=&file_hint_reg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_res) + { .enable=0, .file_hint=&file_hint_res }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rfp) + { .enable=0, .file_hint=&file_hint_rfp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_riff) + { .enable=0, .file_hint=&file_hint_riff }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rlv) + { .enable=0, .file_hint=&file_hint_rlv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rm) + { .enable=0, .file_hint=&file_hint_rm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rns) + { .enable=0, .file_hint=&file_hint_rns }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rpm) + { .enable=0, .file_hint=&file_hint_rpm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rw2) + { .enable=0, .file_hint=&file_hint_rw2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rx2) + { .enable=0, .file_hint=&file_hint_rx2 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_save) + { .enable=0, .file_hint=&file_hint_save }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sdsk) + { .enable=0, .file_hint=&file_hint_sdsk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ses) + { .enable=0, .file_hint=&file_hint_ses }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sgcta) + { .enable=0, .file_hint=&file_hint_sgcta }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shn) + { .enable=0, .file_hint=&file_hint_shn }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sib) + { .enable=0, .file_hint=&file_hint_sib }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sit) + { .enable=0, .file_hint=&file_hint_sit }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_skd) + { .enable=0, .file_hint=&file_hint_skd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_skp) + { .enable=0, .file_hint=&file_hint_skp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_snag) + { .enable=0, .file_hint=&file_hint_snag }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_txt) + { .enable=0, .file_hint=&file_hint_snz }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sp3) + { .enable=0, .file_hint=&file_hint_sp3 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spe) + { .enable=0, .file_hint=&file_hint_spe }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spf) + { .enable=0, .file_hint=&file_hint_spf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spss) + { .enable=0, .file_hint=&file_hint_spss }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sqlite) + { .enable=0, .file_hint=&file_hint_sqlite }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sqm) + { .enable=0, .file_hint=&file_hint_sqm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_steuer2014) + { .enable=0, .file_hint=&file_hint_steuer2014 }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_stl) + { .enable=0, .file_hint=&file_hint_stl }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_studio) + { .enable=0, .file_hint=&file_hint_studio }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_stuffit) + { .enable=0, .file_hint=&file_hint_stuffit }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_swf) + { .enable=0, .file_hint=&file_hint_swf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tar) + { .enable=0, .file_hint=&file_hint_tar }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tax) + { .enable=0, .file_hint=&file_hint_tax }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tg) + { .enable=0, .file_hint=&file_hint_tg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tib) + { .enable=0, .file_hint=&file_hint_tib }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tiff) + { .enable=0, .file_hint=&file_hint_tiff }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tivo) + { .enable=0, .file_hint=&file_hint_tivo }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_torrent) + { .enable=0, .file_hint=&file_hint_torrent }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tph) + { .enable=0, .file_hint=&file_hint_tph }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tpl) + { .enable=0, .file_hint=&file_hint_tpl }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_m2ts) + { .enable=0, .file_hint=&file_hint_ts }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ttf) + { .enable=0, .file_hint=&file_hint_ttf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_txt) + { .enable=0, .file_hint=&file_hint_fasttxt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_txt) + { .enable=0, .file_hint=&file_hint_txt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tz) + { .enable=0, .file_hint=&file_hint_tz }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_v2i) + { .enable=0, .file_hint=&file_hint_v2i }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vault) + { .enable=0, .file_hint=&file_hint_vault }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vdj) + { .enable=0, .file_hint=&file_hint_vdj }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vfb) + { .enable=0, .file_hint=&file_hint_vfb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vdi) + { .enable=0, .file_hint=&file_hint_vdi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_veg) + { .enable=0, .file_hint=&file_hint_veg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vib) + { .enable=0, .file_hint=&file_hint_vib }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vmdk) + { .enable=0, .file_hint=&file_hint_vmdk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_vmg) + { .enable=0, .file_hint=&file_hint_vmg }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wad) + { .enable=0, .file_hint=&file_hint_wad }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wallet) + { .enable=0, .file_hint=&file_hint_wallet }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wdp) + { .enable=0, .file_hint=&file_hint_wdp }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wee) + { .enable=0, .file_hint=&file_hint_wee }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wim) + { .enable=0, .file_hint=&file_hint_wim }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_win) + { .enable=0, .file_hint=&file_hint_win }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wks) + { .enable=0, .file_hint=&file_hint_wks }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wld) + { .enable=0, .file_hint=&file_hint_wld }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wmf) + { .enable=0, .file_hint=&file_hint_wmf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wnk) + { .enable=0, .file_hint=&file_hint_wnk }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_woff) + { .enable=0, .file_hint=&file_hint_woff }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wpb) + { .enable=0, .file_hint=&file_hint_wpb }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wpd) + { .enable=0, .file_hint=&file_hint_wpd }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wtv) + { .enable=0, .file_hint=&file_hint_wtv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_wv) + { .enable=0, .file_hint=&file_hint_wv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_x3f) + { .enable=0, .file_hint=&file_hint_x3f }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_x3i) + { .enable=0, .file_hint=&file_hint_x3i }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_x4a) + { .enable=0, .file_hint=&file_hint_x4a }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xar) + { .enable=0, .file_hint=&file_hint_xar }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xcf) + { .enable=0, .file_hint=&file_hint_xcf }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xfi) + { .enable=0, .file_hint=&file_hint_xfi }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xfs) + { .enable=0, .file_hint=&file_hint_xfs }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xm) + { .enable=0, .file_hint=&file_hint_xm }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xml) + { .enable=0, .file_hint=&file_hint_xml }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xsv) + { .enable=0, .file_hint=&file_hint_xsv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xpt) + { .enable=0, .file_hint=&file_hint_xpt }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xv) + { .enable=0, .file_hint=&file_hint_xv }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_xz) + { .enable=0, .file_hint=&file_hint_xz }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_z2d) + { .enable=0, .file_hint=&file_hint_z2d }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_zcode) + { .enable=0, .file_hint=&file_hint_zcode }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_zip) + { .enable=0, .file_hint=&file_hint_zip }, +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_zpr) + { .enable=0, .file_hint=&file_hint_zpr }, +#endif + { .enable=0, .file_hint=NULL } +}; + +#ifdef SINGLE_FORMAT +#ifdef __OPTIMIZE__ +#define __compiletime_error(message) __attribute__((__error__(message))) +# define __compiletime_assert(condition, msg, prefix, suffix) \ + do { \ + extern void prefix ## suffix(void) __compiletime_error(msg); \ + if (!(condition)) \ + prefix ## suffix(); \ + } while (0) + +#define _compiletime_assert(condition, msg, prefix, suffix) \ + __compiletime_assert(condition, msg, prefix, suffix) + +#define compiletime_assert(condition, msg) \ + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + +static void check_array_file_enable(void) +{ + compiletime_assert(sizeof(file_enable_t) != sizeof(array_file_enable), "No file format has been enabled"); +} +#endif +#endif diff --git a/subprojects/lib/src/file_lit.c b/subprojects/lib/src/file_lit.c new file mode 100644 index 0000000..949ed97 --- /dev/null +++ b/subprojects/lib/src/file_lit.c @@ -0,0 +1,68 @@ +/* + + File: file_lit.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lit) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lit(file_stat_t *file_stat); + +const file_hint_t file_hint_lit= { + .extension="lit", + .description="Microsoft ITOL/ITLS", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lit +}; + +/*@ + @ requires separation: \separated(&file_hint_lit, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lit(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* TODO: file may be a chm (MS Help) or .lit e-book */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lit.extension; + return 1; +} + +static void register_header_check_lit(file_stat_t *file_stat) +{ + static const unsigned char lit_header[12]= { + 'I' , 'T' , 'O' , 'L' , 'I' , 'T' , 'L' , 'S' , + 0x01, 0x00, 0x00, 0x00 + }; + register_header_check(0, lit_header, sizeof(lit_header), &header_check_lit, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_lnk.c b/subprojects/lib/src/file_lnk.c new file mode 100644 index 0000000..267b4f5 --- /dev/null +++ b/subprojects/lib/src/file_lnk.c @@ -0,0 +1,258 @@ +/* + + File: file_lnk.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lnk) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_LNK +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lnk(file_stat_t *file_stat); + +const file_hint_t file_hint_lnk= { + .extension="lnk", + .description="MS Windows Link", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lnk +}; + + +static const unsigned char lnk_reserved[10]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +struct lnk_header_s { + uint32_t magic; /* 0h Always 0000004Ch ‘L’ */ + char guid[16]; /* 4h GUID of shortcut files */ + uint32_t flags; /* 14h */ + uint32_t file_attributes; /* 18h */ + uint64_t ctime; /* 1Ch */ + uint64_t atime; /* 24h */ + uint64_t mtime; /* 2Ch */ + uint32_t file_length; /* 34h */ + uint32_t icon_number; /* 38h */ + uint32_t showWnd_value; /* 3Ch */ + uint32_t hot_key; /* 40h */ + uint64_t always_zero; /* 44h */ +} __attribute__ ((gcc_struct, __packed__)); + +/* These constants comes from winedump/lnk.c */ +#define SLDF_HAS_ID_LIST 1 +#define SLDF_HAS_LINK_INFO 2 +#define SLDF_HAS_NAME 4 +#define SLDF_HAS_RELPATH 8 +#define SLDF_HAS_WORKINGDIR 0x10 +#define SLDF_HAS_ARGS 0x20 +#define SLDF_HAS_ICONLOCATION 0x40 +#define SLDF_UNICODE 0x80 +#define SLDF_HAS_LOGO3ID 0x800 +#define SLDF_HAS_DARWINID 0x1000 + +/*@ + @ requires buffer_size > 0x4c; + @ requires \valid_read(buffer + (0 .. buffer_size-1)); + @ assigns \nothing; + @*/ +static unsigned int lnk_get_size(const unsigned char *buffer, const unsigned int buffer_size) +{ + const struct lnk_header_s* lnk_head=(const struct lnk_header_s*)buffer; + const uint32_t flags=le32(lnk_head->flags); + unsigned int i=0x4c; /* .LNK File Header */ + /* avoid out of bound read access */ + if(i >= buffer_size - 4) + return 0; + if((flags&SLDF_HAS_ID_LIST)!=0) + { /* The Shell Item Id List */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + const unsigned int len=le16(*ptr); +#ifdef DEBUG_LNK + log_debug("LNK Shell Item Id List at 0x%04x=%04x\n", + i, len); +#endif + i+=2; + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 4) + return 0; + if((flags&SLDF_HAS_LINK_INFO)!=0) + { /* File location info */ + const uint32_t *ptr=(const uint32_t *)&buffer[i]; + const unsigned int len=le32(*ptr); +#ifdef DEBUG_LNK + log_debug("LNK File location info at 0x%04x %u bytes\n", i, len); +#endif + /* Discard too big files, avoid overflow */ + if(len >= 0x10000000) + return 0; + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + if((flags&SLDF_HAS_NAME)!=0) + { /* Description string */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + unsigned int len=le16(*ptr); + if((flags& SLDF_UNICODE)!=0) + len*=2; + i+=2; +#ifdef DEBUG_LNK + log_debug("LNK description string at 0x%04x %u bytes\n", i, len); +#endif + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + if((flags&SLDF_HAS_RELPATH)!=0) + { /* Relative path */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + unsigned int len=le16(*ptr); + if((flags& SLDF_UNICODE)!=0) + len*=2; + i+=2; +#ifdef DEBUG_LNK + log_debug("LNK relative path at 0x%04x=%04x\n", i, len); +#endif + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + if((flags&SLDF_HAS_WORKINGDIR)!=0) + { /* Working directory */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + unsigned int len=le16(*ptr); + if((flags& SLDF_UNICODE)!=0) + len*=2; + i+=2; +#ifdef DEBUG_LNK + log_debug("LNK Working directory at 0x%04x %u bytes\n", i, len); +#endif + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + if((flags&SLDF_HAS_ARGS)!=0) + { /* Command line string */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + unsigned int len=le16(*ptr); + if((flags& SLDF_UNICODE)!=0) + len*=2; + i+=2; +#ifdef DEBUG_LNK + log_debug("LNK Command line string at 0x%04x %u bytes\n", i, len); +#endif + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + if((flags&SLDF_HAS_ICONLOCATION)!=0) + { /* Icon filename string */ + const uint16_t *ptr=(const uint16_t *)&buffer[i]; + unsigned int len=le16(*ptr); + if((flags& SLDF_UNICODE)!=0) + len*=2; + i+=2; +#ifdef DEBUG_LNK + log_debug("LNK Icon filename string at 0x%04x=%04x\n", i, len); +#endif + i+=len; + } + /* avoid out of bound read access */ + if(i >= buffer_size - 2) + return 0; + /*@ + @ loop invariant i < buffer_size-2; + @ loop assigns i; + @*/ + while(1) + { + /* avoid out of bound read access */ + const uint16_t *ptr; + unsigned int len; + ptr=(const uint16_t *)&buffer[i]; + /*@ assert \valid_read(ptr); */ + len=le16(*ptr); +#ifdef DEBUG_LNK + log_debug("LNK 0x%04x - %u bytes\n", i, len); +#endif + if(len == 0) + { +#ifdef DEBUG_LNK + log_debug("LNK size %u (0x%04x)\n", i, i); +#endif + return i; + } + i+=2; + if(i >= buffer_size - 2) + return 0; + } +} + +/*@ + @ requires buffer_size >= 0x4c; + @ requires separation: \separated(&file_hint_lnk, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lnk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int len; + if(memcmp(&buffer[0x42], lnk_reserved, sizeof(lnk_reserved))!=0) + return 0; + len=lnk_get_size(buffer, buffer_size); + if(len < 0x4c || len > 1048576) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lnk.extension; + file_recovery_new->calculated_file_size=len; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + // file_recovery_new->time=td_ntfs2utc(le64(lnk_head->ctime)); + return 1; +} + +static void register_header_check_lnk(file_stat_t *file_stat) +{ + static const unsigned char lnk_header[20]= { + 'L', 0x00, 0x00, 0x00, /* magic */ + 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 /* GUID */ + }; + register_header_check(0, lnk_header,sizeof(lnk_header), &header_check_lnk, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_logic.c b/subprojects/lib/src/file_logic.c new file mode 100644 index 0000000..51ba021 --- /dev/null +++ b/subprojects/lib/src/file_logic.c @@ -0,0 +1,66 @@ +/* + + File: file_logic.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_logic) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_logic(file_stat_t *file_stat); + +const file_hint_t file_hint_logic= { + .extension="logic", + .description="Apple Logic Studio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_logic +}; + +/*@ + @ requires separation: \separated(&file_hint_logic, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_logic(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_logic.extension; + return 1; +} + +static void register_header_check_logic(file_stat_t *file_stat) +{ + static const unsigned char logic_header[12]= { + 0xab, 0xc0, 0x47, 0x13, 0x05, 0x17, 0x00, 0x15, 0x00, 0x04, 0x00, 0x24 + }; + register_header_check(0, logic_header,sizeof(logic_header), &header_check_logic, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_lso.c b/subprojects/lib/src/file_lso.c new file mode 100644 index 0000000..0a6d5e5 --- /dev/null +++ b/subprojects/lib/src/file_lso.c @@ -0,0 +1,81 @@ +/* + + File: file_lso.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lso) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lso(file_stat_t *file_stat); + +const file_hint_t file_hint_lso= { + .extension="lso", + .description="Logic Platinum File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lso +}; + +/*@ + @ requires file_recovery->file_check == &file_check_lso; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_lso(file_recovery_t *file_recovery) +{ + const unsigned char lso_footer[6]= {0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F}; + file_search_footer(file_recovery, lso_footer, sizeof(lso_footer), 0x46); +} + +/*@ + @ requires separation: \separated(&file_hint_lso, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lso(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lso.extension; + file_recovery_new->file_check=&file_check_lso; + return 1; +} + +static void register_header_check_lso(file_stat_t *file_stat) +{ + static const unsigned char lso_header[14]= { + 0x13, 'G' , 0xc0, 0xab, 0x17, 0x05, 0x15, 0x00, + 0x03, 0x00, 0x24, 0x00, 0x24, 0x00 + }; + register_header_check(0, lso_header, sizeof(lso_header), &header_check_lso, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_luks.c b/subprojects/lib/src/file_luks.c new file mode 100644 index 0000000..773553d --- /dev/null +++ b/subprojects/lib/src/file_luks.c @@ -0,0 +1,77 @@ +/* + + File: file_luks.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_luks) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "luks_struct.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_luks(file_stat_t *file_stat); + +const file_hint_t file_hint_luks= { + .extension="luks", + .description="LUKS encrypted file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_luks +}; + +/*@ + @ requires buffer_size >= sizeof(struct luks_phdr); + @ requires separation: \separated(&file_hint_luks, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_luks(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct luks_phdr *hdr=(const struct luks_phdr *)buffer; + const unsigned int version=be16(hdr->version); + if(version<1 || version>2) + return 0; + if(!isalpha(hdr->cipherName[0])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_luks.extension; + file_recovery_new->min_filesize=512; + return 1; +} + +static void register_header_check_luks(file_stat_t *file_stat) +{ + static const unsigned char luks_header[6]= { + 'L' , 'U' , 'K' , 'S' , 0xba, 0xbe + }; + register_header_check(0, luks_header, sizeof(luks_header), &header_check_luks, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_lxo.c b/subprojects/lib/src/file_lxo.c new file mode 100644 index 0000000..4d84ce3 --- /dev/null +++ b/subprojects/lib/src/file_lxo.c @@ -0,0 +1,95 @@ +/* + + File: file_lxo.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lxo) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lxo(file_stat_t *file_stat); + +const file_hint_t file_hint_lxo= { + .extension="lxo", + .description="lxo/lwo 3d model", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lxo +}; + +struct lxo_header +{ + char magic[4]; + uint32_t size; + char type[3]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct lxo_header); + @ requires separation: \separated(&file_hint_lxo, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lxo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct lxo_header *header=(const struct lxo_header *)buffer; + const uint64_t size=(uint64_t)be32(header->size) + 8; + if(size < sizeof(struct lxo_header)) + return 0; + if(buffer[8]=='L' && buffer[9]=='X' && buffer[10]=='O') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lxo.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->data_check=&data_check_size; + return 1; + } + if(buffer[8]=='L' && buffer[9]=='W' && buffer[10]=='O') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="lwo"; + file_recovery_new->calculated_file_size=size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->data_check=&data_check_size; + return 1; + } + return 0; +} + +static void register_header_check_lxo(file_stat_t *file_stat) +{ + static const unsigned char lxo_header[4]= { + 'F' , 'O' , 'R' , 'M' + }; + register_header_check(0, lxo_header, sizeof(lxo_header), &header_check_lxo, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_lzh.c b/subprojects/lib/src/file_lzh.c new file mode 100644 index 0000000..175b2d4 --- /dev/null +++ b/subprojects/lib/src/file_lzh.c @@ -0,0 +1,187 @@ +/* + + File: file_lzh.c + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lzh) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lzh(file_stat_t *file_stat); + +const file_hint_t file_hint_lzh= { + .extension="lzh", + .description="lzh/LArc archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lzh +}; + +struct lzh_level0 +{ + uint8_t header_size; + uint8_t header_crc; + uint8_t method_id[5]; + uint32_t comp_size; + uint32_t uncomp_size; + uint32_t file_time; + uint8_t attrib; + uint8_t level; + uint8_t filename_len; + /* Size should be 0, be carefull when using sizeof to decrement */ +#ifndef __FRAMAC__ + uint8_t filename[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +struct lzh_level1 +{ + uint8_t header_size; + uint8_t header_crc; + uint8_t method_id[5]; + uint32_t comp_size; + uint32_t uncomp_size; + uint32_t file_time; + uint8_t reserved_20; + uint8_t level; + uint8_t filename_len; +#ifndef __FRAMAC__ + uint8_t filename[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +struct lzh_level2 +{ + uint16_t header_size; + uint8_t method_id[5]; + uint32_t comp_size; + uint32_t uncomp_size; + uint32_t file_time_unix; + uint8_t reserved; + uint8_t level; + uint16_t file_crc; + uint8_t os_id; + uint16_t next_header_size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename==&file_rename_level0; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_level0(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + size_t buffer_size; + unsigned int i; + const struct lzh_level0 *hdr=(const struct lzh_level0 *)&buffer; + const char *fn=(const char *)hdr + sizeof(struct lzh_level0); + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size < sizeof(struct lzh_level0)) + return; + if(buffer_size < sizeof(struct lzh_level0) + hdr->filename_len) + return; + /*@ assert sizeof(struct lzh_level0) + hdr->filename_len <= buffer_size; */ + /*@ + @ loop invariant 0 <= i <= hdr->filename_len; + @ loop variant i; + @*/ + for(i=0; i< hdr->filename_len && fn[i]!=0 && fn[i]!='.'; i++); + /*@ assert 0 <= i <= hdr->filename_len; */ + file_rename(file_recovery, fn, i, 0, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct lzh_level0); + @ requires buffer_size >= sizeof(struct lzh_level1); + @ requires separation: \separated(&file_hint_lzh, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lzh(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + switch(buffer[20]) + { + /* Level 0 */ + case 0: + { + const struct lzh_level0 *hdr=(const struct lzh_level0 *)buffer; + if(hdr->header_size!=22+hdr->filename_len) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lzh.extension; + file_recovery_new->file_rename=&file_rename_level0; + return 1; + } + /* Level 1 */ + case 1: + { + const struct lzh_level1 *hdr=(const struct lzh_level1 *)buffer; + if(hdr->reserved_20!=0x20) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lzh.extension; + return 1; + } + /* Level 2 */ + case 2: + { + // const struct lzh_level2 *hdr=(const struct lzh_level2 *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lzh.extension; + return 1; + } + } + return 0; +} + +static void register_header_check_lzh(file_stat_t *file_stat) +{ + register_header_check(2, "-lh0-", 5, &header_check_lzh, file_stat); +#ifndef __FRAMAC__ + register_header_check(2, "-lh1-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh2-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh3-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh4-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh5-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh6-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lh7-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lhd-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lzs-", 5, &header_check_lzh, file_stat); + register_header_check(2, "-lz4-", 5, &header_check_lzh, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_lzo.c b/subprojects/lib/src/file_lzo.c new file mode 100644 index 0000000..0a98390 --- /dev/null +++ b/subprojects/lib/src/file_lzo.c @@ -0,0 +1,67 @@ +/* + + File: file_lzo.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_lzo) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_lzo(file_stat_t *file_stat); + +const file_hint_t file_hint_lzo= { + .extension="lzo", + .description="lzo archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_lzo +}; + +/*@ + @ requires separation: \separated(&file_hint_lzo, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_lzo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_lzo.extension; + return 1; +} + +static void register_header_check_lzo(file_stat_t *file_stat) +{ + static const unsigned char lzo_header[9]= { + 0x89, 'L', 'Z', 'O', 0x00, 0x0d, 0x0a, 0x1a, + 0x0a + }; + register_header_check(0, lzo_header, sizeof(lzo_header), &header_check_lzo, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_m2ts.c b/subprojects/lib/src/file_m2ts.c new file mode 100644 index 0000000..99d1b23 --- /dev/null +++ b/subprojects/lib/src/file_m2ts.c @@ -0,0 +1,263 @@ +/* + + File: file_m2ts.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_m2ts) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_m2ts(file_stat_t *file_stat); +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ts(file_stat_t *file_stat); + +const file_hint_t file_hint_m2ts= { + .extension="m2ts", + .description="Blu-ray MPEG-2", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_m2ts +}; + +const file_hint_t file_hint_ts= { + .extension="ts", + .description="MPEG transport stream (TS)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_ts +}; + +static const unsigned char hdmv_header[4] = { 'H','D','M','V'}; +static const unsigned char hdpr_header[4] = { 'H','D','P','R'}; +static const unsigned char tshv_header[4] = { 'T','S','H','V'}; +static const unsigned char sdvs_header[4] = { 'S','D','V','S'}; + +/*@ + @ requires file_recovery->data_check==&data_check_ts_192; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_ts_192(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 5 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 5; */ + if(buffer[i+4]!=0x47) /* TS_SYNC_BYTE */ + return DC_STOP; + file_recovery->calculated_file_size+=192; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_ts_188; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_ts_188(file_recovery_t *file_recovery) +{ + FILE *file; + unsigned char buffer[188]; + char buffer_pid[32]; + unsigned int pid; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(my_fseek(file, 0, SEEK_SET) < 0 || + fread(&buffer, sizeof(buffer), 1, file) != 1) + { + fclose(file); + return ; + } + fclose(file); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + pid=((buffer[1]<<8)|buffer[2])&0x1fff; + sprintf(buffer_pid, "pid_%u", pid); +#if defined(__FRAMAC__) + buffer_pid[sizeof(buffer_pid)-1]='\0'; +#endif + file_rename(file_recovery, (const unsigned char*)buffer_pid, strlen(buffer_pid), 0, NULL, 1); +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_ts_192; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_ts_192(file_recovery_t *file_recovery) +{ + FILE *file; + unsigned char buffer[192]; + char buffer_pid[32]; + unsigned int pid; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(my_fseek(file, 0, SEEK_SET) < 0 || + fread(&buffer, sizeof(buffer), 1, file) != 1) + { + fclose(file); + return ; + } + fclose(file); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + pid=((buffer[5]<<8)|buffer[6])&0x1fff; + sprintf(buffer_pid, "pid_%u", pid); +#if defined(__FRAMAC__) + buffer_pid[sizeof(buffer_pid)-1]='\0'; +#endif + file_rename(file_recovery, (const unsigned char*)buffer_pid, strlen(buffer_pid), 0, NULL, 1); +} + +/*@ + @ requires buffer_size >= 0xe8 + 4; + @ requires separation: \separated(&file_hint_m2ts, &file_hint_ts, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_m2ts(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i; + /* BDAV MPEG-2 transport stream */ + /* Each frame is 192 byte long and begins by a TS_SYNC_BYTE */ + /*@ loop assigns i; */ + for(i=4; ifile_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_m2ts && + file_recovery->data_check==&data_check_ts_192) + { + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + if( memcmp(&buffer[0xd7], &buffer[0xe8], 4)==0) + { + if( memcmp(&buffer[0xd7], hdmv_header, sizeof(hdmv_header))==0 || + memcmp(&buffer[0xd7], hdpr_header, sizeof(hdpr_header))==0) + { +#ifdef DJGPP + file_recovery_new->extension="m2t"; +#else + file_recovery_new->extension=file_hint_m2ts.extension; +#endif + } + else if( memcmp(&buffer[0xd7], sdvs_header, sizeof(sdvs_header))==0) + file_recovery_new->extension="tod"; + else + file_recovery_new->extension="ts"; + } + else + file_recovery_new->extension="ts"; + file_recovery_new->file_rename=&file_rename_ts_192; + file_recovery_new->min_filesize=192; + if(file_recovery_new->blocksize < 5) + return 1; + file_recovery_new->calculated_file_size=0; + file_recovery_new->data_check=&data_check_ts_192; + file_recovery_new->file_check=&file_check_size_max; + return 1; +} + +/*@ + @ requires file_recovery->data_check==&data_check_ts_188; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_ts_188(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size; */ + if(buffer[i]!=0x47) /* TS_SYNC_BYTE */ + return DC_STOP; + file_recovery->calculated_file_size+=188; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 0x18b+sizeof(tshv_header); + @ requires separation: \separated(&file_hint_m2ts, &file_hint_ts, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_m2t(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int i; + if(file_recovery->file_stat!=NULL && + file_recovery->data_check==&data_check_ts_188 && + file_recovery->calculated_file_size == file_recovery->file_size) + return 0; + /* Each frame is 188 byte long and begins by a TS_SYNC_BYTE */ + /*@ loop assigns i; */ + for(i=0; iextension="m2t"; + else + file_recovery_new->extension="ts"; + file_recovery_new->min_filesize=188; + file_recovery_new->calculated_file_size=0; + file_recovery_new->data_check=&data_check_ts_188; + file_recovery_new->file_check=&file_check_size_max; + file_recovery_new->file_rename=&file_rename_ts_188; + return 1; +} + +static void register_header_check_m2ts(file_stat_t *file_stat) +{ + register_header_check(0xd7, hdmv_header, sizeof(hdmv_header), &header_check_m2ts, file_stat); + register_header_check(0xd7, hdpr_header, sizeof(hdpr_header), &header_check_m2ts, file_stat); + register_header_check(0xd7, sdvs_header, sizeof(sdvs_header), &header_check_m2ts, file_stat); + register_header_check(0x18b, tshv_header, sizeof(tshv_header), &header_check_m2t, file_stat); +} + +static void register_header_check_ts(file_stat_t *file_stat) +{ + register_header_check(0, "G", 1, &header_check_m2t, file_stat); + register_header_check(4, "G", 1, &header_check_m2ts, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mat.c b/subprojects/lib/src/file_mat.c new file mode 100644 index 0000000..b02ba68 --- /dev/null +++ b/subprojects/lib/src/file_mat.c @@ -0,0 +1,72 @@ +/* + + File: file_mat.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mat) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mat(file_stat_t *file_stat); + +const file_hint_t file_hint_mat= { + .extension="mat", + .description="Matlab", + .max_filesize=10*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mat +}; + +/*@ + @ requires buffer_size >= 0x80; + @ requires separation: \separated(&file_hint_mat, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char mat_le[4]={0x00, 0x01, 'I', 'M'}; + const unsigned char mat_be[4]={0x01, 0x00, 'M', 'I'}; + if(memcmp(&buffer[0x7c], mat_le, sizeof(mat_le))==0 || + memcmp(&buffer[0x7c], mat_be, sizeof(mat_be))==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mat.extension; + return 1; + } + return 0; +} + +static void register_header_check_mat(file_stat_t *file_stat) +{ + static const unsigned char mat_header[7]= {'M', 'A', 'T', 'L', 'A', 'B', ' '}; + register_header_check(0, mat_header,sizeof(mat_header), &header_check_mat, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_max.c b/subprojects/lib/src/file_max.c new file mode 100644 index 0000000..92aae29 --- /dev/null +++ b/subprojects/lib/src/file_max.c @@ -0,0 +1,65 @@ +/* + + File: file_max.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_max) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_max(file_stat_t *file_stat); + +const file_hint_t file_hint_max= { + .extension="max", + .description="PaperPort", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_max +}; + +/*@ + @ requires separation: \separated(&file_hint_max, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_max(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_max.extension; + return 1; +} + +static void register_header_check_max(file_stat_t *file_stat) +{ + register_header_check(0, "ViGFk", 5, &header_check_max, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mb.c b/subprojects/lib/src/file_mb.c new file mode 100644 index 0000000..130026d --- /dev/null +++ b/subprojects/lib/src/file_mb.c @@ -0,0 +1,99 @@ +/* + + File: file_mb.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mb(file_stat_t *file_stat); + +const file_hint_t file_hint_mb= { + .extension="mb", + .description="Maya", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mb +}; + +struct maya_header +{ + char magic[4]; + uint32_t size; + char magic2[8]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct maya_header); + @ requires separation: \separated(&file_hint_mb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct maya_header *hdr=(const struct maya_header *)buffer; + const unsigned int size=be32(hdr->size); + if(memcmp(buffer,"FOR4",4)!=0 || size < 8) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mb.extension; + file_recovery_new->min_filesize=16; + file_recovery_new->calculated_file_size=(uint64_t)size+8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires buffer_size >= 4; + @ requires separation: \separated(&file_hint_mb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(buffer,"FOR4",4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="mp"; + file_recovery_new->min_filesize=16; + return 1; +} + +static void register_header_check_mb(file_stat_t *file_stat) +{ + register_header_check(8, "MayaFOR4", 8, &header_check_mb, file_stat); + register_header_check(8, "MAYAFOR4", 8, &header_check_mb, file_stat); + register_header_check(8, "MPLEFOR4", 8, &header_check_mp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mcd.c b/subprojects/lib/src/file_mcd.c new file mode 100644 index 0000000..49b9344 --- /dev/null +++ b/subprojects/lib/src/file_mcd.c @@ -0,0 +1,66 @@ +/* + + File: file_mcd.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mcd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mcd(file_stat_t *file_stat); + +const file_hint_t file_hint_mcd= { + .extension="mcd", + .description="VectorWorks", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mcd +}; + +/*@ + @ requires buffer_size >= 2; + @ requires separation: \separated(&file_hint_mcd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mcd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]!=0x00 || buffer[1]!=0x00) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mcd.extension; + return 1; +} + +static void register_header_check_mcd(file_stat_t *file_stat) +{ + static const unsigned char mcd_header[11]= { 'V', 'e','c','t','o','r','W','o','r','k','s'}; + register_header_check(0x0e, mcd_header,sizeof(mcd_header), &header_check_mcd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mdb.c b/subprojects/lib/src/file_mdb.c new file mode 100644 index 0000000..e43e2ce --- /dev/null +++ b/subprojects/lib/src/file_mdb.c @@ -0,0 +1,94 @@ +/* + + File: file_mdb.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mdb(file_stat_t *file_stat); +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_accdb(file_stat_t *file_stat); + +const file_hint_t file_hint_mdb= { + .extension="mdb", + .description="Access Data Base", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mdb +}; + +const file_hint_t file_hint_accdb= { + .extension="accdb", + .description="Access Data Base", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_accdb +}; + +/*@ + @ requires separation: \separated(&file_hint_accdb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_accdb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_accdb.extension; + return 1; +} + +/*@ + @ requires separation: \separated(&file_hint_accdb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mdb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mdb.extension; + return 1; +} + +static void register_header_check_mdb(file_stat_t *file_stat) +{ + static const unsigned char mdb_header[]= { 0x00, 0x01, 0x00, 0x00, 'S', 't', 'a', 'n', 'd','a','r','d',' ','J','e','t',' ', 'D','B', 0x00}; + register_header_check(0, mdb_header,sizeof(mdb_header), &header_check_mdb, file_stat); +} + +static void register_header_check_accdb(file_stat_t *file_stat) +{ + static const unsigned char accdb_header[]= { 0x00, 0x01, 0x00, 0x00, 'S', 't', 'a', 'n', 'd','a','r','d',' ','A','C','E',' ', 'D','B', 0x00}; + register_header_check(0, accdb_header,sizeof(accdb_header), &header_check_accdb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mdf.c b/subprojects/lib/src/file_mdf.c new file mode 100644 index 0000000..4b4ddcb --- /dev/null +++ b/subprojects/lib/src/file_mdf.c @@ -0,0 +1,75 @@ +/* + + File: file_mdf.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mdf(file_stat_t *file_stat); + +const file_hint_t file_hint_mdf= { + .extension="mdf", + .description="Microsoft SQL Server Master Database File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mdf +}; + +/*@ + @ requires buffer_size >= 0x1c; + @ requires separation: \separated(&file_hint_mdf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mdf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0x00]==0x01 && buffer[0x01]==0x0f && buffer[0x02]==0x00 && buffer[0x03]==0x00 && + buffer[0x08]==0x00 && buffer[0x09]==0x00 && buffer[0x0a]==0x00 && buffer[0x0b]==0x00 && + buffer[0x0c]==0x00 && buffer[0x0d]==0x00 && buffer[0x0e]==0x00 && buffer[0x0f]==0x00 && + buffer[0x10]==0x00 && buffer[0x11]==0x00 && buffer[0x12]==0x00 && buffer[0x13]==0x00 && + buffer[0x14]==0x00 && buffer[0x15]==0x00 && buffer[0x16]==0x01 && buffer[0x17]==0x00 && + buffer[0x18]==0x63 && buffer[0x19]==0x00 && buffer[0x1A]==0x00 && buffer[0x1B]==0x00) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mdf.extension; + return 1; + } + return 0; +} + +static void register_header_check_mdf(file_stat_t *file_stat) +{ + static const unsigned char mdf_header[4]= { 0x01, 0x0f, 0x00, 0x00 }; + register_header_check(0, mdf_header,sizeof(mdf_header), &header_check_mdf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mdp.c b/subprojects/lib/src/file_mdp.c new file mode 100644 index 0000000..6b7a995 --- /dev/null +++ b/subprojects/lib/src/file_mdp.c @@ -0,0 +1,77 @@ +/* + + File: file_mdp.c + + Copyright (C) 2020 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mdp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mdp(file_stat_t *file_stat); + +const file_hint_t file_hint_mdp= { + .extension="mdp", + .description="MediBang Paint Pro", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mdp +}; + +struct mdp_header +{ + char magic[8]; + uint32_t val0; /* 0 in the sample files I have */ + uint32_t val1; + uint32_t val2; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct mdp_header); + @ requires separation: \separated(&file_hint_mdp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mdp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct mdp_header *header=(const struct mdp_header *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mdp.extension; + file_recovery_new->calculated_file_size=(uint64_t)le32(header->val1) + le32(header->val2) + 20; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_mdp(file_stat_t *file_stat) +{ + register_header_check(0, "mdipack", 8, &header_check_mdp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mfa.c b/subprojects/lib/src/file_mfa.c new file mode 100644 index 0000000..66e4846 --- /dev/null +++ b/subprojects/lib/src/file_mfa.c @@ -0,0 +1,77 @@ +/* + + File: file_mfa.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mfa) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mfa(file_stat_t *file_stat); + +const file_hint_t file_hint_mfa= { + .extension="mfa", + .description="The Games Factory Multimedia Fusion Files", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mfa +}; + +/*@ + @ requires file_recovery->file_check == &file_check_mfa; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_mfa(file_recovery_t *file_recovery) +{ + const unsigned char mfa_footer[5]= {'!','D','N','E', '!'}; + file_search_footer(file_recovery, mfa_footer, sizeof(mfa_footer), 0x84); +} + +/*@ + @ requires separation: \separated(&file_hint_mfa, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mfa(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_mfa; + file_recovery_new->extension=file_hint_mfa.extension; + return 1; +} + +static void register_header_check_mfa(file_stat_t *file_stat) +{ + static const unsigned char mfa_header[8]= { 'M', 'M', 'F', '2', 0x04, 0x00, 0x00, 0x00}; + register_header_check(0, mfa_header,sizeof(mfa_header), &header_check_mfa, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mfg.c b/subprojects/lib/src/file_mfg.c new file mode 100644 index 0000000..fb81c0f --- /dev/null +++ b/subprojects/lib/src/file_mfg.c @@ -0,0 +1,84 @@ +/* + + File: file_mfg.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mfg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mfg(file_stat_t *file_stat); + +const file_hint_t file_hint_mfg= { + .extension="mfg", + .description="Pro/ENGINEER Manufacturing", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mfg +}; + +/*@ + @ requires file_recovery->file_check == &file_check_mfg; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @ + @*/ +static void file_check_mfg(file_recovery_t *file_recovery) +{ + const unsigned char mfg_footer[11]= { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C'}; + file_search_footer(file_recovery, mfg_footer, sizeof(mfg_footer), 1); +} + +/*@ + @ requires separation: \separated(&file_hint_mfg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mfg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_mfg; + file_recovery_new->extension=file_hint_mfg.extension; + return 1; +} + +static void register_header_check_mfg(file_stat_t *file_stat) +{ + static const unsigned char mfg_header[16]= { + '#', 'U', 'G', 'C', ':', '2', ' ', 'M', + 'F', 'G', '_', 'A', 'S', 'S', 'E', 'M'}; + + register_header_check(0, mfg_header,sizeof(mfg_header), &header_check_mfg, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mft.c b/subprojects/lib/src/file_mft.c new file mode 100644 index 0000000..e4d82a2 --- /dev/null +++ b/subprojects/lib/src/file_mft.c @@ -0,0 +1,111 @@ +/* + + File: file_mft.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mft) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "ntfs_struct.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mft(file_stat_t *file_stat); + +const file_hint_t file_hint_mft= { + .extension="mft", + .description="NTFS MFT record", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=0, + .enable_by_default=1, + .register_header_check=®ister_header_check_mft +}; + +/*@ + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_mft(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + char buffer_cluster[32]; + FILE *file; + int buffer_size; + const struct ntfs_mft_record *record=(const struct ntfs_mft_record *)&buffer; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size<54) + return; +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + /*@ assert \initialized(buffer + (0 .. sizeof(buffer)-1)); */ + sprintf(buffer_cluster, "record_%u", (unsigned int)le32(record->mft_record_number)); +#if defined(__FRAMAC__) + buffer_cluster[sizeof(buffer_cluster)-1]='\0'; +#endif + file_rename(file_recovery, buffer_cluster, strlen(buffer_cluster), 0, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct ntfs_mft_record); + @ requires separation: \separated(&file_hint_mft, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mft(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ntfs_mft_record *mft_rec=(const struct ntfs_mft_record *)buffer; + const unsigned int usa_ofs = le16(mft_rec->usa_ofs); + const unsigned int usa_count = le16(mft_rec->usa_count); + const unsigned int attrs_offset = le16(mft_rec->attrs_offset); + const unsigned int bytes_in_use = le32(mft_rec->bytes_in_use); + const unsigned int bytes_allocated = le32(mft_rec->bytes_allocated); + if(!(memcmp(buffer,"FILE",4)==0 && + usa_ofs+usa_count <= attrs_offset && + 42 <= attrs_offset && + attrs_offset%8==0 && + attrs_offset < bytes_in_use && + bytes_in_use <= bytes_allocated)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mft.extension; + file_recovery_new->calculated_file_size=td_max(file_recovery_new->blocksize, bytes_allocated); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_mft; + return 1; +} + +static void register_header_check_mft(file_stat_t *file_stat) +{ + register_header_check(0, "FILE", 4, &header_check_mft, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mid.c b/subprojects/lib/src/file_mid.c new file mode 100644 index 0000000..e707cca --- /dev/null +++ b/subprojects/lib/src/file_mid.c @@ -0,0 +1,162 @@ +/* + + File: file_mid.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mid) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mid(file_stat_t *file_stat); + +const file_hint_t file_hint_mid= { + .extension="mid", + .description="MIDI Musical Instrument Digital Interface", + .max_filesize=50*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mid +}; + +/* See http://www.sonicspot.com/guide/midifiles.html for more information about MIDI file format */ + +struct midi_header +{ + char magic[4]; + uint32_t len; /* = 6 */ + uint16_t format; + uint16_t tracks; + int16_t time_division; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_midi; + @ requires separation: \separated(file_recovery, file_recovery->handle, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns errno; + @ assigns file_recovery->calculated_file_size; + @ assigns file_recovery->file_size; + @ assigns *file_recovery->handle; + @ assigns file_recovery->time; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_midi(file_recovery_t *file_recovery) +{ + const uint64_t fs_org=file_recovery->file_size; + struct midi_header hdr; + unsigned int i; + unsigned int tracks; + uint64_t fs=4+4+6; + file_recovery->file_size=0; + if(my_fseek(file_recovery->handle, 0, SEEK_SET) < 0 || + fread(&hdr, sizeof(hdr), 1, file_recovery->handle) != 1) + return ; + tracks=be16(hdr.tracks); + /*@ + @ loop assigns i, *file_recovery->handle, fs; + @ loop assigns errno, Frama_C_entropy_source; + @*/ + for(i=0; ihandle, fs, SEEK_SET) < 0 || + fread(&track, 8, 1, file_recovery->handle) != 1 || + memcmp(&track.magic[0], "MTrk", 4)!=0) + return ; + fs+=(uint64_t)8+be32(track.len); + } + if(fs_org < fs) + return ; + file_recovery->file_size=fs; +} + +/*@ + @ requires buffer_size >= 2 && (buffer_size&1)==0; + @ requires \valid(file_recovery); + @ requires \valid_read(buffer + ( 0 .. buffer_size-1)); + @ requires file_recovery->data_check == &data_check_midi; + @ requires separation: \separated(buffer+(..), file_recovery); + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_midi(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + const struct midi_header *hdr=(const struct midi_header*)&buffer[i]; + const uint64_t len=be32(hdr->len); +#ifdef DEBUG_MIDI + log_info("data_check_midi 0x%08llx len=%llu\n", (long long unsigned)file_recovery->calculated_file_size, (long long unsigned)len); +#endif + if(memcmp(&hdr->magic[0], "MTrk", 4)!=0) + return DC_STOP; + file_recovery->calculated_file_size+=(uint64_t)8+len; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct midi_header); + @ requires separation: \separated(&file_hint_mid, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mid(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct midi_header *hdr=(const struct midi_header *)buffer; + if(be16(hdr->format) > 2 || be16(hdr->tracks) == 0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mid.extension; + file_recovery_new->file_check=&file_check_midi; + if(file_recovery_new->blocksize < 8) + return 1; + file_recovery_new->calculated_file_size=4+4+6; + file_recovery_new->data_check=&data_check_midi; + return 1; +} + +static void register_header_check_mid(file_stat_t *file_stat) +{ + static const unsigned char mid_header[8] = { 'M','T','h','d', 0, 0, 0, 0x6}; + register_header_check(0, mid_header,sizeof(mid_header), &header_check_mid, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mig.c b/subprojects/lib/src/file_mig.c new file mode 100644 index 0000000..1930788 --- /dev/null +++ b/subprojects/lib/src/file_mig.c @@ -0,0 +1,140 @@ +/* + + File: file_mig.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mig) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_MIG +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mig(file_stat_t *file_stat); + +const file_hint_t file_hint_mig= { + .extension="mig", + .description="Windows Migration Backup", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mig +}; + +struct MIG_HDR +{ + uint32_t magic; + uint32_t fn_size; + uint32_t s_size; + uint32_t unk1; + uint32_t unk2; + uint32_t unk3; +#ifndef __FRAMAC__ + unsigned char fn[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_mig; + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_mig(file_recovery_t *file_recovery) +{ + uint64_t offset=0x34; + file_recovery->file_size=0; + /*@ + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source; + @ loop assigns offset; + @*/ + while(1) + { + char buffer[sizeof(struct MIG_HDR)]; + const struct MIG_HDR *h=(const struct MIG_HDR *)&buffer; + size_t res; + if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0) + { +#ifdef DEBUG_MIG + log_info("0x%lx fseek failed\n", (long unsigned)offset); +#endif + return ; + } + res=fread(&buffer, 1, sizeof(buffer), file_recovery->handle); + if(res < 8) + { +#ifdef DEBUG_MIG + log_info("0x%lx not enough data\n", (long unsigned)offset); +#endif + return ; + } + /* STRM=stream */ + if(res < sizeof(buffer) || le32(h->magic)!=0x5354524d || offset >= PHOTOREC_MAX_FILE_SIZE) + { +#ifdef DEBUG_MIG + log_info("0x%lx no magic %x\n", (long unsigned)offset, le32(h->magic)); +#endif + file_recovery->file_size=offset+8; + return ; + } +#ifdef DEBUG_MIG + log_info("0x%lx magic s_size=0x%u\n", (long unsigned)offset, le32(h->s_size)); +#endif + offset+=sizeof(buffer)+le32(h->s_size); + } +} + +/*@ + @ requires buffer_size > 0x38; + @ requires separation: \separated(&file_hint_mig, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mig(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x34], "MRTS", 4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mig.extension; + file_recovery_new->file_check=&file_check_mig; + return 1; +} + +static void register_header_check_mig(file_stat_t *file_stat) +{ + static const unsigned char mig_header[8]= { + '1' , 'g' , 'i' , 'M' , 0x02, 0x00, 0x00, 0x00 + }; + register_header_check(0, mig_header, sizeof(mig_header), &header_check_mig, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mk5.c b/subprojects/lib/src/file_mk5.c new file mode 100644 index 0000000..9d549bc --- /dev/null +++ b/subprojects/lib/src/file_mk5.c @@ -0,0 +1,67 @@ +/* + + File: file_mk5.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mk5) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mk5(file_stat_t *file_stat); + +const file_hint_t file_hint_mk5= { + .extension="mk5", + .description="Custom CAD-CAM", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mk5 +}; + +/*@ + @ requires buffer_size >= 0x20; + @ requires separation: \separated(&file_hint_mk5, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mk5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char mk5_header2[4]= { 0x00, 0x40, 0x1c, 0x46 }; + if(memcmp(buffer+0x1c,mk5_header2,sizeof(mk5_header2))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mk5.extension; + return 1; +} + +static void register_header_check_mk5(file_stat_t *file_stat) +{ + static const unsigned char mk5_header[4]= { 0x36, 0xff, 0xff, 0xff }; + register_header_check(0, mk5_header,sizeof(mk5_header), &header_check_mk5, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mkv.c b/subprojects/lib/src/file_mkv.c new file mode 100644 index 0000000..4375362 --- /dev/null +++ b/subprojects/lib/src/file_mkv.c @@ -0,0 +1,270 @@ +/* + + File: file_mkv.c + + Copyright (C) 1998-2007,2011 Christophe GRENIER + Copyright (C) 2011 Nick Schrader + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mkv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_MKV +#include "log.h" +#endif + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mkv(file_stat_t *file_stat); + +const file_hint_t file_hint_mkv= { + .extension="mkv", + .description="Matroska", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mkv +}; + +/*@ + @ requires \valid_read(p + (0 .. p_size-1)); + @ requires \valid(uint64); + @ requires \separated(p + (..), uint64); + @ ensures -1 == \result || (1 <= \result <= 8); + @ ensures -1 != \result ==> \initialized(uint64); + @ ensures -1 != \result ==> *uint64 <= 0xfeffffffffffffff; + @ assigns *uint64; + @*/ +static int EBML_read_unsigned(const unsigned char *p, const unsigned int p_size, uint64_t *uint64) +{ + unsigned char test_bit = 0x80; + unsigned int i, bytes = 1; + const unsigned char c=*p; + uint64_t val; + if(p_size==0 || c== 0x00) + return -1; + /*@ assert c != 0; */ + /*@ + @ loop invariant test_bit > 0; + @ loop invariant test_bit == (0x100 >> bytes); + @ loop assigns test_bit, bytes; + @ loop unroll 8; + @*/ + while((c & test_bit) != test_bit) + { + /*@ assert c < test_bit; */ + test_bit >>= 1; + bytes++; + } + /*@ assert (c & test_bit) == test_bit; */ + /*@ assert 1 <= bytes <= 8; */ + /*@ assert c >= test_bit; */ + if(p_size < bytes) + return -1; + /*@ assert bytes <= p_size; */ + val = c - test_bit; //eliminate first bit, val < 0x80 + /*@ assert val <= 0xfe; */ + /*@ + @ loop assigns i, val; + @ loop unroll 8; + @ loop variant bytes-i; + @*/ + for(i=1; i 0; + @ requires \valid_read(buffer + (0 .. buffer_size-1)); + @ requires \valid_read(EBML_Header + (0 .. EBML_size-1)); + @ assigns \result; + @*/ +static int EBML_find(const unsigned char *buffer, const unsigned int buffer_size, const unsigned char *EBML_Header, const unsigned int EBML_size) +{ + unsigned int offset=0; + /*@ + @ loop assigns offset; + @*/ + while(offset < buffer_size) + { + uint64_t uint64=0; + int bytes; + bytes = EBML_read_unsigned(&buffer[offset], buffer_size-offset, &uint64); +#ifdef DEBUG_MKV + log_info("EBML_find %02x%02x bytes=%d\n", buffer[offset], buffer[offset+1], bytes); +#endif + if(bytes <= 0) + return -1; + if((unsigned int)bytes == EBML_size && memcmp(&buffer[offset], EBML_Header, EBML_size)==0) + { + return offset+bytes; + } + offset += bytes; + if(offset >= buffer_size) + return -1; + bytes = EBML_read_unsigned(&buffer[offset], buffer_size-offset, &uint64); + if(bytes <= 0 || uint64 > buffer_size) + return -1; + offset += bytes; + offset += uint64; + } + return -1; +} + +/*@ + @ requires \valid_read(p + (0 .. p_size-1)); + @ requires \valid(strlength); + @ requires \separated(p + (..), strlength); + @ ensures -1 == \result || (1 <= \result <= 8); + @ ensures -1 != \result ==> \initialized(strlength); + @ ensures -1 != \result ==> *strlength <= 0xfeffffffffffffff; + @ ensures -1 != \result ==> \result + *strlength <= p_size; + @ assigns *strlength, \result; + @*/ +static int EBML_read_string(const unsigned char *p, const unsigned int p_size, uint64_t *strlength) +{ + int bytes; + *strlength = 0; + bytes = EBML_read_unsigned(p, p_size, strlength); +#ifdef DEBUG_MKV + log_info("EBML_read_string bytes=%d strlength=%llu\n", bytes, (long long unsigned)*strlength); +#endif + if(bytes <= 0) + return -1; + /*@ assert 1 <= bytes <= 8; */ + /*@ assert *strlength <= 0xfeffffffffffffff; */ + if(bytes + *strlength > p_size) + return -1; + /*@ assert bytes + *strlength <= p_size; */ + return bytes; +} + +static const unsigned char EBML_header[4]= { 0x1a,0x45,0xdf,0xa3}; + +/*@ + @ requires separation: \separated(&file_hint_mkv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mkv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(buffer,EBML_header,sizeof(EBML_header))!=0) + return 0; + { + const unsigned char EBML_DocType[2]= { 0x42,0x82}; + const unsigned char EBML_Segment[4]= { 0x18,0x53,0x80,0x67}; + uint64_t segment_size=0; + uint64_t header_data_size=0; + const unsigned char *p; + unsigned int header_data_offset; + unsigned int segment_offset; + unsigned int segment_data_offset; + uint64_t strlength = 0; + int bytes; + int len; + int offset_doctype; + + if((len=EBML_read_unsigned(buffer+sizeof(EBML_header), + buffer_size-sizeof(EBML_header), &header_data_size)) < 0) + return 0; + header_data_offset = sizeof(EBML_header) + len; + if(header_data_offset >= buffer_size) + return 0; +#ifdef DEBUG_MKV + log_info("header_data_offset %llu\n", (long long unsigned) header_data_offset); + log_info("header_data_size %llu\n", (long long unsigned) header_data_size); +#endif + if(header_data_size >= buffer_size) + return 0; + segment_offset = header_data_offset + header_data_size; +#ifdef DEBUG_MKV + log_info("segment_offset %llu\n", (long long unsigned) segment_offset); +#endif + if(segment_offset +sizeof(EBML_Segment) >= buffer_size) + return 0; + if(memcmp(&buffer[segment_offset], EBML_Segment, sizeof(EBML_Segment)) != 0) + return 0; + p=&buffer[segment_offset+sizeof(EBML_Segment)]; + if((len=EBML_read_unsigned(p, buffer_size-(p-buffer), &segment_size)) < 0) + return 0; + segment_data_offset=segment_offset+sizeof(EBML_Segment)+len; + /* Check if size is unkown */ + if(segment_size == (1ULL << (7 * len)) - 1) + segment_size=0; +#ifdef DEBUG_MKV + log_info("segment_data_offset %llu\n", (long long unsigned) segment_data_offset); + log_info("segment size %llu\n", (long long unsigned) segment_size); +#endif + /* get EBML_DocType, it will be used to set the file extension */ + offset_doctype=EBML_find(&buffer[header_data_offset], header_data_size, EBML_DocType, sizeof(EBML_DocType)); +#ifdef DEBUG_MKV + log_info("offset_doctype = %u\n", offset_doctype); +#endif + if(offset_doctype < 0 || header_data_size <= (uint64_t)offset_doctype) + return 0; + /*@ assert header_data_size > offset_doctype; */ + p = &buffer[header_data_offset+offset_doctype]; + bytes = EBML_read_string(&buffer[header_data_offset+offset_doctype], header_data_size-offset_doctype, &strlength); + if (bytes < 0) + return 0; + reset_file_recovery(file_recovery_new); + if( (strlength == 8 && memcmp(p+bytes,"matroska", 8)==0) || + (strlength == 9 && memcmp(p+bytes,"matroska", 9)==0)) + file_recovery_new->extension=file_hint_mkv.extension; + else if((strlength == 4 && memcmp(p+bytes,"webm", 4)==0) || + ( strlength == 5 && memcmp(p+bytes,"webm", 5)==0)) + file_recovery_new->extension="webm"; + else + file_recovery_new->extension="ebml"; + if(segment_size > 0) + { + file_recovery_new->calculated_file_size = segment_data_offset + segment_size; +#ifdef DEBUG_MKV + log_info("file size %llu\n", (long long unsigned) file_recovery_new->calculated_file_size); +#endif + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + } + return 1; +} + +static void register_header_check_mkv(file_stat_t *file_stat) +{ + register_header_check(0, EBML_header,sizeof(EBML_header), &header_check_mkv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mlv.c b/subprojects/lib/src/file_mlv.c new file mode 100644 index 0000000..3a166e5 --- /dev/null +++ b/subprojects/lib/src/file_mlv.c @@ -0,0 +1,226 @@ +/* + + File: file_mlv.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mlv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mlv(file_stat_t *file_stat); + +const file_hint_t file_hint_mlv= { + .extension="mlv", + .description="Magic Lantern Video", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mlv +}; + +/* See https://bitbucket.org/hudson/magic-lantern/src/tip/modules/mlv_rec/mlv.h?at=unified */ +typedef struct { + uint8_t fileMagic[4]; /* Magic Lantern Video file header */ + uint32_t blockSize; /* size of the whole header */ + uint8_t versionString[8]; /* null-terminated C-string of the exact revision of this format */ + uint64_t fileGuid; /* UID of the file (group) generated using hw counter, time of day and PRNG */ + uint16_t fileNum; /* the ID within fileCount this file has (0 to fileCount-1) */ + uint16_t fileCount; /* how many files belong to this group (splitting or parallel) */ + uint32_t fileFlags; /* 1=out-of-order data, 2=dropped frames, 4=single image mode, 8=stopped due to error */ + uint16_t videoClass; /* 0=none, 1=RAW, 2=YUV, 3=JPEG, 4=H.264 */ + uint16_t audioClass; /* 0=none, 1=WAV */ + uint32_t videoFrameCount; /* number of video frames in this file. set to 0 on start, updated when finished. */ + uint32_t audioFrameCount; /* number of audio frames in this file. set to 0 on start, updated when finished. */ + uint32_t sourceFpsNom; /* configured fps in 1/s multiplied by sourceFpsDenom */ + uint32_t sourceFpsDenom; /* denominator for fps. usually set to 1000, but may be 1001 for NTSC */ +} __attribute__ ((gcc_struct, __packed__)) mlv_file_hdr_t; + +typedef struct { + uint8_t blockType[4]; + uint32_t blockSize; + uint64_t timestamp; +} __attribute__ ((gcc_struct, __packed__)) mlv_hdr_t; + +/*@ + @ requires \valid_read(hdr->blockType + (0 .. 3)); + @ assigns \nothing; + @*/ +static int is_valid_type(const mlv_hdr_t *hdr) +{ + unsigned int i; + /*@ loop assigns i; */ + for(i=0; i<4; i++) + { + const uint8_t c=hdr->blockType[i]; + if(!((c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z'))) + return 0; + } + return 1; +} + +/*@ + @ requires fr->data_check==&data_check_mlv; + @ requires valid_data_check_param(buffer, buffer_size, fr); + @ ensures valid_data_check_result(\result, fr); + @ assigns fr->calculated_file_size; + @*/ +static data_check_t data_check_mlv(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *fr) +{ + /*@ + @ loop assigns fr->calculated_file_size; + @*/ + while(fr->calculated_file_size + buffer_size/2 >= fr->file_size && + fr->calculated_file_size + 8 < fr->file_size + buffer_size/2) + { + const unsigned int i=fr->calculated_file_size + buffer_size/2 - fr->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + const mlv_hdr_t *hdr=(const mlv_hdr_t *)&buffer[i]; + if(le32(hdr->blockSize)<0x10 || !is_valid_type(hdr)) + return DC_STOP; + fr->calculated_file_size+=le32(hdr->blockSize); + } + if(fr->calculated_file_size >= PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_check == &file_check_mlv; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_mlv(file_recovery_t *file_recovery) +{ + uint64_t fs=0; + /*@ + @ loop assigns *file_recovery->handle, errno, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source, fs; + @*/ + while(fs < 0x8000000000000000) + { + char buffer[sizeof(mlv_hdr_t)]; + const mlv_hdr_t *hdr=(const mlv_hdr_t *)&buffer; + if(my_fseek(file_recovery->handle, fs, SEEK_SET)<0 || + fread(&buffer, sizeof(buffer), 1, file_recovery->handle)!=1) + { + file_recovery->file_size=(fs <= file_recovery->blocksize ? 0 : fs); + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + if(le32(hdr->blockSize)<0x10 || + !is_valid_type(hdr) || + fs + le32(hdr->blockSize) > file_recovery->file_size) + { + file_recovery->file_size=(fs <= file_recovery->blocksize ? 0 : fs); + return; + } + fs+=le32(hdr->blockSize); + } + file_recovery->file_size=0; +} + +/*@ + @ requires file_recovery->file_rename == &file_rename_mlv; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_mlv(file_recovery_t *file_recovery) +{ + FILE *file; + char buffer[sizeof(mlv_file_hdr_t)]; + const mlv_file_hdr_t *hdr=(const mlv_file_hdr_t *)&buffer; + char ext[16]; + const char *ext_ptr=(const char *)&ext; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(my_fseek(file, 0, SEEK_SET) < 0 || + fread(&buffer, sizeof(buffer), 1, file) != 1) + { + fclose(file); + return ; + } + fclose(file); + sprintf(ext, "M%02u", le16(hdr->fileNum)); +#if defined(__FRAMAC__) + ext[sizeof(ext)-1]='\0'; +#endif + /*@ assert valid_read_string(ext_ptr); */ + file_rename(file_recovery, NULL, 0, 0, ext_ptr, 1); +} + +/*@ + @ requires buffer_size >= sizeof(mlv_file_hdr_t); + @ requires separation: \separated(&file_hint_mlv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mlv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const mlv_file_hdr_t *hdr=(const mlv_file_hdr_t *)buffer; + if(le32(hdr->blockSize) < 0x34) + return 0; +#ifdef DEBUG_MLV + log_info("header_check_mlv fileCount=%u fileNum=%u\n", le16(hdr->fileCount), le16(hdr->fileNum)); +#endif + if(le16(hdr->fileCount)==0 && le16(hdr->fileNum) > 0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mlv.extension; + file_recovery_new->calculated_file_size=(uint64_t)le32(hdr->blockSize); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_mlv; + return 1; + } + if(le16(hdr->fileNum) > le16(hdr->fileCount)) + return 0; + if(le16(hdr->fileNum) >= le16(hdr->fileCount) && le16(hdr->fileCount)>0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mlv.extension; + file_recovery_new->file_check=&file_check_mlv; + if(file_recovery_new->blocksize > 0x10) + file_recovery_new->data_check=&data_check_mlv; + return 1; +} + +static void register_header_check_mlv(file_stat_t *file_stat) +{ + register_header_check(0, "MLVI", 4, &header_check_mlv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mobi.c b/subprojects/lib/src/file_mobi.c new file mode 100644 index 0000000..6c88892 --- /dev/null +++ b/subprojects/lib/src/file_mobi.c @@ -0,0 +1,86 @@ +/* + + File: file_mobi.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mobi) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mobi(file_stat_t *file_stat); + +const file_hint_t file_hint_mobi= { + .extension="mobi", + .description="Mobi e-book", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mobi +}; + +/*@ + @ requires file_recovery->file_check == &file_check_mobi; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_mobi(file_recovery_t *file_recovery) +{ + const unsigned char mobi_footer[58]= { + 'F' , 'L' , 'I' , 'S' , 0x00, 0x00, 0x00, 0x08, + 0x00, 'A' , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff, 'F' , 'C' , 'I' , 'S' , + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + file_search_footer(file_recovery, mobi_footer, sizeof(mobi_footer), 26); +} + +/*@ + @ requires separation: \separated(&file_hint_mobi, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mobi(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mobi.extension; + file_recovery_new->file_check=&file_check_mobi; + return 1; +} + +static void register_header_check_mobi(file_stat_t *file_stat) +{ + register_header_check(0x3c, "BOOKMOBI", 8, &header_check_mobi, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mov.c b/subprojects/lib/src/file_mov.c new file mode 100644 index 0000000..8568fc9 --- /dev/null +++ b/subprojects/lib/src/file_mov.c @@ -0,0 +1,638 @@ +/* + + File: file_mov.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mov) || defined(SINGLE_FORMAT_mov_mdat) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mov(file_stat_t *file_stat); +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mov_mdat(file_stat_t *file_stat); + +const file_hint_t file_hint_mov= { + .extension="mov", + .description="mov/mp4/3gp/3g2/jp2", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mov +}; + +const file_hint_t file_hint_mov_mdat= { + .extension="mov/mdat", + .description="Recover mdat atom as a separate file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_mov_mdat +}; + +static const char *extension_mp4="mp4"; +static const char *extension_m4a="m4a"; +static const char *extension_3gp="3gp"; +static const char *extension_3g2="3g2"; +static const char *extension_heic="heic"; +static const char *extension_jp2="jp2"; +static const char *extension_cr3="cr3"; + +struct atom_struct +{ + uint32_t size; + uint32_t type; +} __attribute__ ((gcc_struct, __packed__)); + +struct atom64_struct +{ + uint32_t size1; + uint32_t type; + uint64_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename == &file_rename_mov; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_mov(file_recovery_t *file_recovery) +{ + FILE *file; + unsigned char buffer[512]; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(fread(&buffer,sizeof(buffer),1,file)!=1) + { + fclose(file); + return ; + } + fclose(file); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + buffer[8]='\0'; + file_rename(file_recovery, buffer, sizeof(buffer), 4, NULL, 1); +} + +/*@ + @ requires \valid_read(atom + (0 .. 3)); + @ assigns \nothing; + @*/ +static inline int is_known_atom(const unsigned char *atom) +{ + if( (atom[0]=='c' && atom[1]=='m' && atom[2]=='o' && atom[3]=='v') || + (atom[0]=='c' && atom[1]=='m' && atom[2]=='v' && atom[3]=='d') || + (atom[0]=='d' && atom[1]=='c' && atom[2]=='o' && atom[3]=='m') || + (atom[0]=='f' && atom[1]=='r' && atom[2]=='e' && atom[3]=='a') || + (atom[0]=='f' && atom[1]=='r' && atom[2]=='e' && atom[3]=='e') || + (atom[0]=='f' && atom[1]=='t' && atom[2]=='y' && atom[3]=='p') || + (atom[0]=='j' && atom[1]=='p' && atom[2]=='2' && atom[3]=='h') || + (atom[0]=='m' && atom[1]=='d' && atom[2]=='i' && atom[3]=='a') || + (atom[0]=='m' && atom[1]=='e' && atom[2]=='t' && atom[3]=='a') || + (atom[0]=='m' && atom[1]=='o' && atom[2]=='o' && atom[3]=='v') || + (atom[0]=='P' && atom[1]=='I' && atom[2]=='C' && atom[3]=='T') || + (atom[0]=='p' && atom[1]=='n' && atom[2]=='o' && atom[3]=='t') || + (atom[0]=='s' && atom[1]=='k' && atom[2]=='i' && atom[3]=='p') || + (atom[0]=='s' && atom[1]=='t' && atom[2]=='b' && atom[3]=='l') || + (atom[0]=='t' && atom[1]=='h' && atom[2]=='u' && atom[3]=='m') || + (atom[0]=='t' && atom[1]=='r' && atom[2]=='a' && atom[3]=='k') || + (atom[0]=='u' && atom[1]=='u' && atom[2]=='i' && atom[3]=='d') || + (atom[0]=='w' && atom[1]=='i' && atom[2]=='d' && atom[3]=='e') ) + return 1; + return 0; +} + +/*@ + @ requires buffer_size >= 16; + @ requires file_recovery->data_check==&data_check_mov; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 8 ; */ + const struct atom_struct *atom=(const struct atom_struct*)&buffer[i]; + /*@ assert \valid_read(atom); */ + uint64_t atom_size=be32(atom->size); + if(atom_size==1) + { + const struct atom64_struct *atom64; + if(i + 16 > buffer_size) + { + return DC_CONTINUE; + } + /*@ assert i + 16 <= buffer_size; */ + atom64=(const struct atom64_struct*)&buffer[i]; + /*@ assert \valid_read(atom64); */ + atom_size=be64(atom64->size); + if(atom_size<16) + return DC_STOP; + /*@ assert atom_size >= 16; */ + } + else if(atom_size<8) + return DC_STOP; + /*@ assert atom_size >= 8; */ + if(atom_size >= 0x800000000000) + return DC_STOP; + /*@ assert 8 <= atom_size < 0x800000000000; */ +#ifdef DEBUG_MOV + log_trace("file_mov.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n", + file_recovery->filename, + buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7], + buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7], + (long long unsigned)atom_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t') + { + file_recovery->calculated_file_size+=atom_size; +#if 0 + if(i+8 == buffer_size) + { + return -((atom_size + buffer_size/2 - 1)/ (buffer_size/2)); + } +#endif + } + else if(is_known_atom(&buffer[i+4])) + { + file_recovery->calculated_file_size+=atom_size; + } + else + { +#ifndef __FRAMAC__ + if(!(buffer[i+4]==0 && buffer[i+5]==0 && buffer[i+6]==0 && buffer[i+7]==0)) + log_warning("file_mov.c: unknown atom 0x%02x%02x%02x%02x at %llu\n", + buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7], + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_STOP; + } + } +#ifdef DEBUG_MOV + log_trace("file_mov.c: new calculated_file_size %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null); + @ ensures (\result == 1) ==> (file_recovery_new->handle == \null); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mov.extension || + file_recovery_new->extension == extension_3g2 || + file_recovery_new->extension == extension_3gp || + file_recovery_new->extension == extension_cr3 || + file_recovery_new->extension == extension_heic || + file_recovery_new->extension == extension_jp2 || + file_recovery_new->extension == extension_m4a || + file_recovery_new->extension == extension_mp4); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension)); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_mov || file_recovery_new->file_rename == \null); + @ ensures (\result == 1 && file_recovery_new->extension == file_hint_mov.extension) ==> (file_recovery_new->file_rename == file_rename_mov); + @ ensures (\result == 1 && file_recovery_new->extension != file_hint_mov.extension) ==> (file_recovery_new->file_rename == \null); + @ ensures (\result == 1 && (file_recovery_new->extension == extension_jp2 || file_recovery_new->blocksize < 16)) ==> (file_recovery_new->data_check == \null && file_recovery_new->file_check == \null && file_recovery_new->file_rename == \null && file_recovery_new->min_filesize > 0); + @ ensures (\result == 1 && file_recovery_new->extension != extension_jp2 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->calculated_file_size > 0 && file_recovery_new->file_check == &file_check_size && file_recovery_new->data_check == &data_check_mov); + @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension); + @*/ +static int header_check_mov_aux(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t i=0; + while(i <= buffer_size-16) + { + /*@ assert i <= buffer_size - 16; */ + const struct atom_struct *atom=(const struct atom_struct*)&buffer[i]; + uint64_t calculated_file_size; + uint64_t atom_size=be32(atom->size); + if(atom_size==1) + { + const struct atom64_struct *atom64=(const struct atom64_struct*)&buffer[i]; + atom_size=be64(atom64->size); + if(atom_size<16) + return 0; + /*@ assert atom_size >= 16; */ + } + else if(atom_size<8) + return 0; + /*@ assert 8 <= atom_size; */ + if(atom_size >= 0x800000000000) + return 0; + /*@ assert 8 <= atom_size < 0x800000000000; */ + calculated_file_size=atom_size+i; + /* check for commun atom type */ + if(buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t') + { + if(atom_size != 20) + return 0; + /*@ assert atom_size == 20; */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mov.extension; + file_recovery_new->file_rename=&file_rename_mov; + if(file_recovery_new->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + if(buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e') + { + if(atom_size != 8) + return 0; + /*@ assert atom_size == 8; */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mov.extension; + file_recovery_new->file_rename=&file_rename_mov; + if(file_recovery_new->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + if(buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v') + { + if(atom_size > 256*256*256) + return 0; + /*@ assert atom_size <= 256*256*256; */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mov.extension; + file_recovery_new->file_rename=&file_rename_mov; + if(file_recovery_new->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + /* + if(i==0 && buffer[12]=='m' && buffer[13]=='v' && buffer[14]=='h' && buffer[15]=='d') + { + file_recovery_new->calculated_file_size=atom_size; + file_recovery_new->data_check=&data_check_size; + } + else + */ + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + if(buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p') + { + if(atom_size < 20 || (atom_size&3)!=0 || atom_size>256) + return 0; + /*@ assert 20 <= atom_size <= 256; */ + if(memcmp(&buffer[i+8], "isom", 4)==0 || + memcmp(&buffer[i+8], "mp41", 4)==0 || + memcmp(&buffer[i+8], "mp42", 4)==0 || + memcmp(&buffer[i+8], "mmp4", 4)==0 || + memcmp(&buffer[i+8], "M4B", 3)==0 || + memcmp(&buffer[i+8], "M4P", 3)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_mp4; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "M4A ", 4)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_m4a; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "3gp", 3)==0) + { + /* Video for 3G mobile phone (GSM) */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_3gp; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "3g2", 3)==0) + { + /* Video for 3G mobile phone (CDMA) */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_3g2; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "heic", 4)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_heic; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "jp2 ", 4)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_jp2; + file_recovery_new->min_filesize=calculated_file_size; + /* jP + ftyp "jp2 " + jp2h + jp2c (atom_size=0) => no data check */ + return 1; + } + else if(memcmp(&buffer[i+8], "qt ", 4)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mov.extension; + file_recovery_new->file_rename=&file_rename_mov; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + else if(memcmp(&buffer[i+8], "crx ", 4)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_cr3; + if(file_recovery->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + } + if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t') + { + if(memcmp(&buffer[i], "der.mdat\" anim=\"", 16)==0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + buffer[8]=='a' && isprint(buffer[0]) && isprint(buffer[1]) && isprint(buffer[2]) && isprint(buffer[3])) + { + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mov.extension; + file_recovery_new->file_rename=&file_rename_mov; + if(file_recovery_new->blocksize < 16) + { + file_recovery_new->min_filesize=calculated_file_size; + return 1; + } + file_recovery_new->data_check=&data_check_mov; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->calculated_file_size=calculated_file_size; + return 1; + } + if(atom_size > buffer_size) + return 0; + i+=atom_size; + } + return 0; +} + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mov.extension || + file_recovery_new->extension == extension_3g2 || + file_recovery_new->extension == extension_3gp || + file_recovery_new->extension == extension_cr3 || + file_recovery_new->extension == extension_heic || + file_recovery_new->extension == extension_jp2 || + file_recovery_new->extension == extension_m4a || + file_recovery_new->extension == extension_mp4); + @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension)); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_mov || file_recovery_new->file_rename == \null); + @ ensures (\result == 1 && file_recovery_new->extension == file_hint_mov.extension) ==> (file_recovery_new->file_rename == file_rename_mov); + @ ensures (\result == 1 && file_recovery_new->extension != file_hint_mov.extension) ==> (file_recovery_new->file_rename == \null); + @ ensures (\result == 1 && (file_recovery_new->extension == extension_jp2 || file_recovery_new->blocksize < 16)) ==> (file_recovery_new->data_check == \null && file_recovery_new->file_check == \null && file_recovery_new->file_rename == \null && file_recovery_new->min_filesize > 0); + @ ensures (\result == 1 && file_recovery_new->extension != extension_jp2 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->calculated_file_size > 0 && file_recovery_new->file_check == &file_check_size && file_recovery_new->data_check == &data_check_mov); + @*/ +static int header_check_mov(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mov && + file_recovery->calculated_file_size == file_recovery->file_size) + { /* PhotoRec is already trying to recover this mov file */ + header_ignored(file_recovery_new); + return 0; + } + return header_check_mov_aux(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mov_mdat(file_stat_t *file_stat) +{ + register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov_aux, file_stat); +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mov(file_stat_t *file_stat) +{ + register_header_check(4, (const unsigned char*)"cmov",4, &header_check_mov, file_stat); +#ifndef __FRAMAC__ + register_header_check(4, (const unsigned char*)"cmvd",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"dcom",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"free",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"ftyp",4, &header_check_mov_aux, file_stat); + register_header_check(4, (const unsigned char*)"jp2h",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"mdia",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"moov",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"PICT",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"pnot",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"skip",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"stbl",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"trak",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"wide",4, &header_check_mov, file_stat); + register_header_check(4, (const unsigned char*)"jP ",4, &header_check_mov, file_stat); +#endif +} +#endif + +#if defined(MAIN_mov) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.mov"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.offset_ok=0; + file_recovery_new.checkpoint_status=0; + file_recovery_new.location.start=0; + file_recovery_new.offset_error=0; + + file_stats.file_hint=&file_hint_mov; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_mov(&file_stats); + /*@ assert file_recovery_new.blocksize >= 16; */ + if(header_check_mov(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.blocksize >= 16; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.offset_ok == 0; */ + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string((char *)&file_recovery_new.filename); */ + /*@ assert file_recovery_new.offset_ok == 0; */ + file_recovery_new.file_stat=&file_stats; + if(file_recovery_new.data_check != NULL) + { + /*@ assert file_recovery_new.data_check == &data_check_mov; */ + /*@ assert file_recovery_new.file_check == file_check_size; */ + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.file_size == 0; */; + res_data_check=data_check_mov(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + /*@ assert file_recovery_new.calculated_file_size > file_recovery_new.file_size - 16; */ + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_mov(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + /*@ assert file_recovery_new.offset_ok == 0; */ + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_mov(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert file_recovery_new.offset_ok == 0; */ + if(file_recovery_new.file_check != NULL) + { + /*@ assert file_recovery_new.file_check == file_check_size; */ + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_rename_mov(&file_recovery_new); + return 0; +} +#endif diff --git a/subprojects/lib/src/file_mp3.c b/subprojects/lib/src/file_mp3.c new file mode 100644 index 0000000..d8a6f45 --- /dev/null +++ b/subprojects/lib/src/file_mp3.c @@ -0,0 +1,812 @@ +/* + + File: file_mp3.c + + Copyright (C) 1998-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mp3) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#if !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_mkv; +extern const file_hint_t file_hint_tiff; +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mp3(file_stat_t *file_stat); + +const file_hint_t file_hint_mp3= { + .extension="mp3", + .description="MP3 audio (MPEG ADTS, layer III, v1)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mp3 +}; + +#define MPEG_V25 0 +#define MPEG_V2 0x2 +#define MPEG_V1 0x3 +#define MPEG_L3 0x01 +#define MPEG_L2 0x02 +#define MPEG_L1 0x03 + +static const unsigned int sample_rate_table[4][4]={ + {11025, 12000, 8000, 0}, /* MPEG_V25 */ + { 0, 0, 0, 0}, + {22050, 24000, 16000, 0}, /* MPEG_V2 */ + {44100, 48000, 32000, 0} /* MPEG_V1 */ +}; +static const unsigned int bit_rate_table[4][4][16]= +{ + /* MPEG_V25 */ + /* MPEG_V_INVALID */ + { + /* MPEG_L_INVALID */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L3 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + /* MPEG_L2 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + /* MPEG_L1 */ + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0} + }, + { + /* MPEG_L_INVALID */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L3 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L2 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L1 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + /* MPEG_V2 */ + { + /* MPEG_L_INVALID */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L3 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + /* MPEG_L2 */ + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + /* MPEG_L1 */ + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0} + }, + /* MPEG_V1 */ + { + /* MPEG_L_INVALID */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* MPEG_L3 */ + { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}, + /* MPEG_L2 */ + { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + /* MPEG_L1 */ + { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 294, 416, 448, 0} + }, +}; + +/*@ + @ requires needle_size > 0; + @ requires haystack_size > 0; + @ requires \valid_read(needle+(0..needle_size-1)); + @ requires \valid_read(haystack+(0..haystack_size-1)); + @ ensures \result == 0 || needle_size <= \result <= haystack_size; + @ assigns \nothing; + @*/ +static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size) +{ + unsigned int i; + if(haystack_size < needle_size) + return 0; + /*@ assert haystack_size >= needle_size; */ + /*@ + @ loop assigns i; + @ loop invariant 0 <= i <= haystack_size - needle_size + 1; + @ loop variant haystack_size - needle_size - i; + @*/ + for(i=0; i <= haystack_size - needle_size; i++) + if(memcmp(&haystack[i],needle,needle_size)==0) + return (i+needle_size); + return 0; +} + +/*@ + @ requires 0 < buffer_size <= 10*1024*1024; + @ requires i <= buffer_size; + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ ensures \result <= buffer_size + 0x80; + @ assigns \nothing; + @*/ +static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size) +{ + /* + Check for MusicMatch Tag + http://freenet-homepage.de/StefanRypalla/stuff/musicmatch.txt + min size = 8192bytes + header is optional + structure : + header 256 bytes optional + image extension 4 bytes + image binary >= 4 bytes + unused 4 bytes + version info 256 bytes + audio meta-data >= 7868 bytes + In all versions of the MusicMatch format up to and including 3.00, + this section (audio meta-data) is always 7868 bytes in length. + All subsequent versions allowed three possible lengths for this section: 7936, 8004, and 8132 bytes. + data offsets 20 bytes + Footer 48 bytes (optional?!) + */ + const unsigned char mm_header[10]= {'1','8','2','7','3','6','4','5',0x00, 0x00}; + const unsigned char mm_pad_version_info[14] = {0x00,0x00,0x00,0x00,'1','8','2','7','3','6','4','5',0x00,0x00}; + const char mm_footer[]="Brava Software Inc."; + const char mm_footer_tag[]="TAG"; + unsigned int size=0; + if(i+sizeof(mm_header)>buffer_size) + return 0; + /*@ assert i + sizeof(mm_header) <= buffer_size; */ + if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header + { + size=256; + /* Don't check image extension */ + /* log_info("search_MMT: mm_header present\n"); */ + } + else + { + /* Check image extension */ + if( memcmp(&buffer[i]," ",4)!=0 && + memcmp(&buffer[i],"bmp ",4)!=0 && + memcmp(&buffer[i],"jpg ",4)!=0) + return 0; + /* log_info("search_MMT: image extension present\n"); */ + } + { + const unsigned int tmp=i+size; + const uint32_t *image_size_ptr; + uint32_t image_size; + if(tmp+8>buffer_size) + return 0; + /*@ assert tmp + 8 <= buffer_size; */ + image_size_ptr = (const uint32_t *)&buffer[tmp+4]; + image_size = le32(*image_size_ptr); + /* Check if the image size */ + if(image_size > buffer_size) + return 0; + /*@ assert image_size <= buffer_size; */ + /* Image binary */ + size+=8+image_size; + } + { + const unsigned int tmp=i+size; + /* check null padding + version_info */ + if(tmp+sizeof(mm_pad_version_info)>buffer_size) + { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */ + /* log_trace("search_MMT: partial MusicMatch Tag 1\n"); */ + return 0; + } + /*@ assert tmp + sizeof(mm_pad_version_info) <= buffer_size; */ + if(memcmp(&buffer[tmp], mm_pad_version_info, sizeof(mm_pad_version_info))!=0) + { + /* log_trace("search_MMT: mm_pad_version_info not present\n"); */ + return 0; + } + } + size+=4+256; /* padding + version_info */ + size+=20; /* data offset */ + { + const unsigned int tmp=i+size; + /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */ + if(tmp+8132+sizeof(mm_footer) > buffer_size) + { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */ + /* log_trace("search_MMT: partial MusicMatch 2\n"); */ + return 0; + } + /*@ assert tmp + 8132 + sizeof(mm_footer) <= buffer_size; */ + if( memcmp(&buffer[tmp+7868], mm_footer, sizeof(mm_footer)-1)==0 || + memcmp(&buffer[tmp+7868], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0) + size+=7868; + else if(memcmp(&buffer[tmp+7936], mm_footer, sizeof(mm_footer)-1)==0 || + memcmp(&buffer[tmp+7936], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0) + size+=7936; + else if(memcmp(&buffer[tmp+8004], mm_footer, sizeof(mm_footer)-1)==0 || + memcmp(&buffer[tmp+8004], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0) + size+=8004; + else if(memcmp(&buffer[tmp+8132], mm_footer, sizeof(mm_footer)-1)==0 || + memcmp(&buffer[tmp+8132], mm_footer_tag, sizeof(mm_footer_tag)-1)==0) + size+=8132; + else + { + /* log_trace("search_MMT: no mm_footer present\n"); */ + return 0; + } + } + { + const unsigned int tmp=i+size; + if(tmp + sizeof(mm_footer) > buffer_size) + return 0; + /*@ assert tmp + sizeof(mm_footer) <= buffer_size; */ + if(memcmp(&buffer[tmp],mm_footer, sizeof(mm_footer)-1)==0) + size+=48; /* footer */ + else + size+=0x80; /* TAG footer */ + } + /* log_trace("search_MMT: MMT found size=%u (0x%x)\n", size, size); */ + return size; +} + +/*@ + @ requires buffer_size >= 32; + @ requires file_recovery->data_check==&data_check_mp3; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ +#ifdef DEBUG_MP3 + log_info("data_check_mp3 file_size=%llu, calculated_file_size=%llu\n", + (long long unsigned)file_recovery->file_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 16 ; */ +#ifdef DEBUG_MP3 + log_info("data_check_mp3 start i=0x%x buffer_size=0x%x calculated_file_size=%lu file_size=%lu\n", + i, buffer_size, + (long unsigned)file_recovery->calculated_file_size, + (long unsigned)file_recovery->file_size); +#endif + if(buffer[i+0]==0xFF && ((buffer[i+1]&0xE0)==0xE0)) + { + const unsigned int mpeg_version =(buffer[i+1]>>3)&0x03; + const unsigned int mpeg_layer =(buffer[i+1]>>1)&0x03; + const unsigned int bit_rate_key =(buffer[i+2]>>4)&0x0F; + const unsigned int sampling_rate_key=(buffer[i+2]>>2)&0x03; + const unsigned int padding =(buffer[i+2]>>1)&0x01; + /*@ split mpeg_version; */ + const unsigned int sample_rate =sample_rate_table[mpeg_version][sampling_rate_key]; + /*@ assert sample_rate == 0 || 8000 <= sample_rate <= 48000; */ + const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key]; + unsigned int frameLengthInBytes=0; + if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1) + return DC_STOP; + /*@ assert 8000 <= sample_rate <= 48000; */ + /*@ assert 0 < bit_rate <= 448; */ + if(mpeg_layer==MPEG_L3) + { + if(mpeg_version==MPEG_V1) + frameLengthInBytes = 144000 * bit_rate / sample_rate + padding; + else + frameLengthInBytes = 72000 * bit_rate / sample_rate + padding; + } + else if(mpeg_layer==MPEG_L2) + frameLengthInBytes = 144000 * bit_rate / sample_rate + padding; + else + frameLengthInBytes = (12000 * bit_rate / sample_rate + padding)*4; + if(frameLengthInBytes<3) + return DC_STOP; + /*@ assert 3 <= frameLengthInBytes <= 8065; */ + file_recovery->calculated_file_size+=frameLengthInBytes; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else if(buffer[i]=='L' && buffer[i+1]=='Y' && buffer[i+2]=='R' && buffer[i+3]=='I' && buffer[i+4]=='C' && buffer[i+5]=='S' && buffer[i+6]=='B' && buffer[i+7]=='E' && buffer[i+8]=='G' && buffer[i+9]=='I' && buffer[i+10]=='N') + { + /* + Lyrics3 tag http://www.id3.org/Lyrics3 + Lyrics3 v2.00 tag http://www.id3.org/Lyrics3v2 + Lyrics Header : + 'LYRICSBEGIN' (both version) + Lyrics Footer : + 'LYRICSEND' Lyrics3 tags + 'LYRICS200' Lyrics3v2 Tags + The maximum length of the lyrics is 5100 bytes for Lyrics3 and 4096 bytes for Lyrics3 v2. + */ + unsigned int pos_lyrics=0; + if(i + 5100 > buffer_size) + return DC_STOP; + /*@ assert i + 5100 <= buffer_size; */ + if((pos_lyrics=pos_in_mem(&buffer[i], 4096, (const unsigned char*)"LYRICS200", 9)) != 0) + { + /*@ assert 0 < pos_lyrics <= 4096; */ + file_recovery->calculated_file_size+=pos_lyrics; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else if((pos_lyrics=pos_in_mem(&buffer[i], 5100, (const unsigned char*)"LYRICSEND", 9)) != 0) + { + /*@ assert 0 < pos_lyrics <= 5100; */ + file_recovery->calculated_file_size+=pos_lyrics; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else + { + /* + log_warning("End of Lyrics not found \n"); + */ + return DC_STOP; + } + } + else if(buffer[i]=='A' && buffer[i+1]=='P' && buffer[i+2]=='E' && buffer[i+3]=='T' && buffer[i+4]=='A' && buffer[i+5]=='G' && buffer[i+6]=='E' && buffer[i+7]=='X') + { /* APE Tagv2 (APE Tagv1 has no header) http://wiki.hydrogenaudio.org/index.php?title=APE_Tags_Header */ + const uint64_t ape_tag_size = (buffer[i+12] | (buffer[i+13]<<8) | (buffer[i+14]<<16) | ((uint64_t)buffer[i+15]<<24))+(uint64_t)32; + file_recovery->calculated_file_size+=ape_tag_size; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else if(buffer[i]=='T' && buffer[i+1]=='A' && buffer[i+2]=='G') + { /* http://www.id3.org/ID3v1 TAGv1 size = 128 bytes with header "TAG" */ + file_recovery->calculated_file_size+=128; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else if(buffer[i]=='I' && buffer[i+1]=='D' && buffer[i+2]=='3' && (buffer[i+3]==2 || buffer[i+3]==3 || buffer[i+3]==4) && buffer[i+4]==0) + { + unsigned int potential_frame_offset=0; + if(buffer[i+3]==4 && (buffer[i+5]&0x10)==0x10) + potential_frame_offset = 10; + potential_frame_offset+=((buffer[i+6]&0x7f)<<21) + ((buffer[i+7]&0x7f)<<14) + + ((buffer[i+8]&0x7f)<<7) + (buffer[i+9]&0x7f)+ 10; + file_recovery->calculated_file_size+=potential_frame_offset; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + else + { + const unsigned int MMT_size=search_MMT(buffer,i,buffer_size); + if(MMT_size==0) + return DC_STOP; + /*@ assert 0 < MMT_size <= buffer_size + 0x80; */ + /* + log_info("MusicMatch Tag found at offset 0x%x with size 0x%x \n", file_recovery->calculated_file_size, MMT_size); + */ + file_recovery->calculated_file_size+=MMT_size; + /*@ assert file_recovery->calculated_file_size > 0; */ + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 32; + @ requires file_recovery->data_check==&data_check_id3; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ ensures file_recovery->data_check==&data_check_id3 || file_recovery->data_check==&data_check_mp3; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 1 ; */ + if(buffer[i]==0) + { /* Padding is present */ + file_recovery->calculated_file_size++; + } + else + { /* no more padding or no padding */ + file_recovery->data_check=&data_check_mp3; + /*@ assert file_recovery->data_check==&data_check_mp3; */ + if(data_check_mp3(buffer, buffer_size, file_recovery)!=DC_CONTINUE) + return DC_STOP; + return DC_CONTINUE; + } + } + /*@ assert file_recovery->data_check==&data_check_id3; */ + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 10; + @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_id3); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null); + @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension)); + @ assigns *file_recovery_new; + @*/ +static int header_check_id3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3' && (buffer[3]==2 || buffer[3]==3 || buffer[3]==4) && buffer[4]==0) + { + unsigned int potential_frame_offset=0; + /* + * TODO Handle ID3 tag + * http://www.id3.org/id3v2-00 + * http://www.id3.org/id3v2.3.0 + */ + if(buffer[3]==4 && (buffer[5]&0x10)==0x10) /* a footer is present http://www.id3.org/id3v2.4.0-structure chap. 3.1 */ + potential_frame_offset = 10; + + potential_frame_offset+=((buffer[6]&0x7f)<<21) + ((buffer[7]&0x7f)<<14) + + ((buffer[8]&0x7f)<<7) + (buffer[9]&0x7f)+ 10; + + /* + log_info("ID3v2.%u found \n potential_frame_offset at 0x%x\n",buffer[3], potential_frame_offset); + */ + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=potential_frame_offset; + /*@ assert file_recovery_new->calculated_file_size > 0; */ + file_recovery_new->min_filesize=287; + file_recovery_new->data_check=&data_check_id3; + file_recovery_new->extension=file_hint_mp3.extension; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +/*@ + @ requires buffer_size >= 6; + @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287); + @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->data_check == &data_check_mp3); + @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->data_check == \null); + @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->file_check == \null); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null); + @*/ +static int header_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + unsigned int potential_frame_offset=0; + unsigned int nbr=0; + /* + A Frame sync 11 (length in bits) + B MPEG audio version (MPEG-1, 2, etc.) 2 + C MPEG layer (Layer I, II, III, etc.) 2 + D Protection (if on, then checksum follows header) 1 + AAAA AAAA AAAB BCCD + 1111 1111 1111 1010 = FA = MPEG-1 layer 3 + 1111 1111 1111 0010 = F2 = MPEG-2 layer 3 + 1111 1111 1110 0010 = E2 = MPEG-2.5 layer 3 + + http://www.dv.co.yu/mpgscript/mpeghdr.htm + */ + if(!(buffer[0]==0xFF && + ((buffer[1]&0xFE)==0xFA || + (buffer[1]&0xFE)==0xF2 || + (buffer[1]&0xFE)==0xE2))) + return 0; + /*@ assert nbr == 0; */ + /*@ + @ loop invariant 0 <= nbr <= potential_frame_offset <= 8192 + 8065; + @ loop assigns potential_frame_offset,nbr; + @ loop variant 8192 - potential_frame_offset; + @*/ + while(potential_frame_offset+1 < buffer_size && + potential_frame_offset+1 < 8192) + { + if(buffer[potential_frame_offset+0]!=0xFF) + return 0; + { + const unsigned int mpeg_version =(buffer[potential_frame_offset+1]>>3)&0x03; + const unsigned int mpeg_layer =(buffer[potential_frame_offset+1]>>1)&0x03; + const unsigned int bit_rate_key =(buffer[potential_frame_offset+2]>>4)&0x0F; + const unsigned int sampling_rate_key=(buffer[potential_frame_offset+2]>>2)&0x03; + const unsigned int padding =(buffer[potential_frame_offset+2]>>1)&0x01; + /*@ split mpeg_version; */ + const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key]; + const unsigned int sample_rate =sample_rate_table[mpeg_version][sampling_rate_key]; + unsigned int frameLengthInBytes=0; + if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1) + return 0; + /*@ assert 8000 <= sample_rate <= 48000; */ + /*@ assert 0 < bit_rate <= 448; */ + if(mpeg_layer==MPEG_L3) + { + if(mpeg_version==MPEG_V1) + frameLengthInBytes = 144000 * bit_rate / sample_rate + padding; + else + frameLengthInBytes = 72000 * bit_rate / sample_rate + padding; + } + else if(mpeg_layer==MPEG_L2) + frameLengthInBytes = 144000 * bit_rate / sample_rate + padding; + else + frameLengthInBytes = (12000 * bit_rate / sample_rate + padding)*4; +#ifdef DEBUG_MP3 + log_info("framesize: %u, layer: %u, bitrate: %u, padding: %u\n", + frameLengthInBytes, 4-mpeg_layer, bit_rate, padding); +#endif + if(frameLengthInBytes<3) + return 0; + /*@ assert 3 <= frameLengthInBytes <= 8065; */ + potential_frame_offset+=frameLengthInBytes; + /*@ assert potential_frame_offset > 0; */ + nbr++; + } + } + if(nbr<=1) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL) + { + if(file_recovery->file_stat->file_hint==&file_hint_mp3 +#if !defined(SINGLE_FORMAT) + || file_recovery->file_stat->file_hint==&file_hint_mkv +#endif + ) + { + header_ignored(file_recovery_new); + return 0; + } +#if !defined(SINGLE_FORMAT) + /* RGV values from TIFF may be similar to the beginning of an mp3 */ + if(file_recovery->file_stat->file_hint==&file_hint_tiff && + buffer[0]==buffer[3] && buffer[1]==buffer[4] && buffer[2]==buffer[5]) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + } + /*@ assert nbr > 1; */ + /*@ assert potential_frame_offset > 0; */ +#ifdef DEBUG_MP3 + log_info("header_check_mp3 mp3 found\n"); +#endif + reset_file_recovery(file_recovery_new); + /*@ assert file_recovery_new->file_check == \null; */ + /*@ assert file_recovery_new->data_check == \null; */ + file_recovery_new->calculated_file_size=potential_frame_offset; + /*@ assert file_recovery_new->calculated_file_size > 0; */ + file_recovery_new->min_filesize=287; + file_recovery_new->extension=file_hint_mp3.extension; + if(file_recovery_new->blocksize >= 16) + { + file_recovery_new->data_check=&data_check_mp3; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mp3(file_stat_t *file_stat) +{ + static const unsigned char mpeg1_L3_header1[2]= {0xFF, 0xFA}; + static const unsigned char mpeg1_L3_header2[2]= {0xFF, 0xFB}; + static const unsigned char mpeg2_L3_header1[2]= {0xFF, 0xF2}; + static const unsigned char mpeg2_L3_header2[2]= {0xFF, 0xF3}; + static const unsigned char mpeg25_L3_header1[2]={0xFF, 0xE2}; + static const unsigned char mpeg25_L3_header2[2]={0xFF, 0xE3}; + register_header_check(0, "ID3", 3, &header_check_id3, file_stat); + register_header_check(0, mpeg1_L3_header1, sizeof(mpeg1_L3_header1), &header_check_mp3, file_stat); + register_header_check(0, mpeg1_L3_header2, sizeof(mpeg1_L3_header2), &header_check_mp3, file_stat); + register_header_check(0, mpeg2_L3_header1, sizeof(mpeg2_L3_header1), &header_check_mp3, file_stat); + register_header_check(0, mpeg2_L3_header2, sizeof(mpeg2_L3_header2), &header_check_mp3, file_stat); + register_header_check(0, mpeg25_L3_header1, sizeof(mpeg25_L3_header1), &header_check_mp3, file_stat); + register_header_check(0, mpeg25_L3_header2, sizeof(mpeg25_L3_header2), &header_check_mp3, file_stat); +} +#endif + +#if defined(MAIN_mp3) +#define BLOCKSIZE 65536u +static int main_id3() +{ + const char fn[] = "recup_dir.1/f0000000.mp3"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_mp3; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_mp3(&file_stats); + if(header_check_id3(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new) != 1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.extension == file_hint_mp3.extension; */ + /*@ assert file_recovery_new.calculated_file_size > 0; */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.min_filesize == 287; */ + /*@ assert file_recovery_new.data_check == &data_check_id3; */ + /*@ assert file_recovery_new.file_rename == \null; */ + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_id3(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + /*@ assert file_recovery_new.data_check == &data_check_id3 || file_recovery_new.data_check == &data_check_mp3; */ + /*@ assert res_data_check == DC_CONTINUE && file_recovery_new.data_check == &data_check_mp3 ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */ + /*@ assert res_data_check == DC_CONTINUE && file_recovery_new.data_check == &data_check_id3 ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 1); */ + /*@ assert res_data_check == DC_CONTINUE ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */ + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + /*@ assert file_recovery_new.calculated_file_size >= file_recovery_new.file_size - 16; */ + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + file_recovery_new.data_check(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + if(file_recovery_new.file_stat!=NULL) + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_id3(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + if(file_recovery_new.file_check!=NULL) + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + (file_recovery_new.file_check)(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} + +static int main_mp3() +{ + const char fn[] = "recup_dir.1/f0000000.mp3"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_mp3; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_mp3(&file_stats); + if(header_check_mp3(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.min_filesize == 287; */ + /*@ assert file_recovery_new.extension == file_hint_mp3.extension; */ + /*@ assert file_recovery_new.calculated_file_size > 0; */ + /*@ assert file_recovery_new.file_rename == \null; */ + file_recovery_new.file_stat=&file_stats; + if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL && + file_recovery_new.data_check!=NULL) + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_mp3; */ + /*@ assert file_recovery_new.file_size == 0; */; + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_mp3(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + /*@ assert res_data_check == DC_CONTINUE ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */ + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + /*@ assert file_recovery_new.calculated_file_size >= file_recovery_new.file_size - 16; */ + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + file_recovery_new.data_check(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + if(file_recovery_new.file_stat!=NULL) + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + header_check_mp3(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + if(file_recovery_new.file_check!=NULL) + { + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + (file_recovery_new.file_check)(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} + +int main() +{ + main_mp3(); + main_id3(); + return 0; +} +#endif diff --git a/subprojects/lib/src/file_mpg.c b/subprojects/lib/src/file_mpg.c new file mode 100644 index 0000000..ecc7316 --- /dev/null +++ b/subprojects/lib/src/file_mpg.c @@ -0,0 +1,400 @@ +/* + + File: file_mpg.c + + Copyright (C) 1998-2005,2007-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mpg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mpg(file_stat_t *file_stat); + +const file_hint_t file_hint_mpg= { + .extension="mpg", + .description="Moving Picture Experts Group video", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mpg +}; + +/*@ + @ requires \valid_read(buffer + (0 .. 13)); + @ assigns \nothing; + @*/ +static unsigned int calculate_packet_size(const unsigned char *buffer) +{ + /* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */ + if(buffer[0]!=0 || buffer[1]!=0 || buffer[2]!=1) + return 0; + switch(buffer[3]) + { + /* Pack header: */ + case 0xBA: + if((buffer[4]&0xc4)==0x44 && (buffer[6]&4)==4 && (buffer[8]&4)==4 && + (buffer[9]&1)==1 && (buffer[12]&3)==3) + return (buffer[13] & 0x7) + 14; + if((buffer[4]&0xF1)==0x21 && (buffer[6]&1)==1 && (buffer[8]&1)==1 && + (buffer[9]&0x80)==0x80 && (buffer[11]&1)==1) + return 12; + return 0; + /* Sequence Header */ + case 0xB3: + if((buffer[10]&0x20)==0x20) + { + if((buffer[11]&3)!=0) + return 12+64; /* quantiser matrix */ + return 12; + } + return 0; + /* Extension */ + case 0xB5: + /* Sequence_Extension */ + if((buffer[4]&0xF0)==0x10 && (buffer[7]&1)==1) + return 10; + /* Sequence_Display_Extension without color description */ + if((buffer[4]&0xF0)==0x20 && (buffer[4]&1)==0 && (buffer[6]&2)==2) + return 9; + /* Sequence_Display_Extension with color description */ + if((buffer[4]&0xF0)==0x20 && (buffer[4]&1)==1 && (buffer[9]&2)==2) + return 12; + /* Picture_Coding_Extension */ + if((buffer[4]&0xF0)==0x40) + { + if((buffer[8]&0x40)==0) + return 9; + else + return 11; + } + return 0; + case 0xB8: /* Group of Pictures */ + if((buffer[5]&0x40)==0x40) + return 8; + return 0; + case 0xB9: /* EOC */ + return 4; + case 0xBD: /* Private stream 1 (non MPEG audio, subpictures) */ + case 0xC0 ... 0xDF: /* Mpeg Audio stream */ + case 0xE0 ... 0xEF: /* Mpeg Video stream */ +#if 0 + { + uint32_t pts = 0; + // This is mpeg 2: + if((buffer[6] & 0xC0) == 0x80 && + // PTS DTS flags + (buffer[7] >> 7)==1) + { + pts = ((buffer[13] | (buffer[12] << 8) ) >> 1) | + ((buffer[11] | (buffer[10] << 8) ) >> 1) << 15; + + // log_debug("MPG2 (%u - 0x%02X)PTS is 0x%08X\n", current->id,buffer[3], pts); + // This is mpeg 1. The PTS goes right after the header and must + // have the bits 0x21 set: + } + else if((buffer[6] & 0x21)==0x21) + { + pts = ((buffer[10] | (buffer[9] << 8) ) >> 1) | ((buffer[8] | (buffer[7] << 8) ) >> 1) << 15; + //log_debug("MPG1 (%u - 0x%02X)PTS is 0x%08X\n", current->id,buffer[3], pts); + }; + } +#endif + return (buffer[4] << 8) + buffer[5] + 6; + case 0xBB: /* System header */ + case 0xBE: /* Padding stream */ + case 0xBF: /* Private Stream 2 */ + return (buffer[4] << 8) + buffer[5] + 6; + case 0: + return 0; + default: +#ifdef DEBUG_MPG + log_info("I dont know how to handle 0x%02X\n", buffer[3]); +#endif + return 0; + } +} + +/*@ + @ requires file_recovery->data_check==&data_check_mpg; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_mpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 14 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert i < buffer_size - 14; */ + const unsigned int ret=calculate_packet_size(&buffer[i]); +#ifdef DEBUG_MPG + log_info("data_check_mpg %llu 0x%02x %u\n", (long long unsigned)file_recovery->calculated_file_size, buffer[i+3], ret); +#endif + if(ret==0) + return DC_STOP; + file_recovery->calculated_file_size+=ret; + } + return DC_CONTINUE; +} + +/*@ + @ requires \valid(file_recovery_new); + @ ensures valid_file_recovery(file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_mpg_found(file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mpg.extension; + if(file_recovery_new->blocksize < 14) + return 1; + file_recovery_new->data_check=&data_check_mpg; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires buffer_size >= 13; + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ assigns \nothing; + @*/ +static int is_valid_packet_size(const unsigned char *buffer, const unsigned int buffer_size) +{ + unsigned int i=0; + /*@ + @ loop assigns i; + @*/ + while(i+14 < td_min(buffer_size,512U)) + { + /*@ assert i < buffer_size - 14; */ + const unsigned int ret=calculate_packet_size(&buffer[i]); + if(ret==0) + return 0; + i+=ret; + } + return 1; +} + +/*@ + @ requires buffer_size >= 13; + @ requires separation: \separated(&file_hint_mpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_mpg_Pack(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(is_valid_packet_size(buffer, buffer_size)==0) + return 0; + /* MPEG-1 http://andrewduncan.ws/MPEG/MPEG-1.ps */ + /* pack start code 0x1BA + MPEG-1 + SCR=0 */ + if((buffer[4]&0xF1)==0x21 && (buffer[6]&1)==1 && (buffer[8]&1)==1 && + (buffer[9]&0x80)==0x80 && (buffer[11]&1)==1) + { + if(buffer[5]==0 && buffer[6]==1 && buffer[7]==0 && buffer[8]==1) + { + return header_mpg_found(file_recovery_new); + } + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mpg) + { + header_ignored(file_recovery_new); + return 0; + } + return header_mpg_found(file_recovery_new); + } + /* MPEG-2 Program stream http://neuron2.net/library/mpeg2/iso13818-1.pdf */ + /* MPEG2 system header start code, several per file */ + if((buffer[4]&0xc4)==0x44 && (buffer[6]&4)==4 && (buffer[8]&4)==4 && (buffer[9]&1)==1 && (buffer[12]&3)==3) + { + /* + * '01' 2 01 + system_clock_reference_base [32..30] 3 00 0 + marker_bit 1 1 + system_clock_reference_base [29..15] 15 00 buffer[4]=0x44 + 0000 0000 buffer[5]=0x00 + 0000 0 + marker_bit 1 1 + system_clock_reference_base [14..0] 15 00 buffer[6]=0x04 + + 0000 0000 buffer[7]=0x00 + 0000 + 0 + marker_bit 1 1 + system_clock_reference_extension 9 uimsbf + marker_bit 1 + => 0100 0100 + */ + + if(buffer[4]==0x44 && buffer[5]==0 && buffer[6]==4 && buffer[7]==0 && (buffer[8]&0xfc)==4) + { /* SCR=0 */ + return header_mpg_found(file_recovery_new); + } + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mpg) + { + header_ignored(file_recovery_new); + return 0; + } + return header_mpg_found(file_recovery_new); + } + return 0; +} + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_mpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_mpg_System(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* MPEG-1 http://andrewduncan.ws/MPEG/MPEG-1.ps */ + /* ISO/IEC INTERNATIONAL 13818-1 STANDARD + system_header_start_code 32 + header_length 16 + marker_bit 1 + rate_bound 22 + marker_bit 1 + audio_bound 6 + fixed_flag 1 + CSPS_flag 1 + system_audio_lock_flag 1 + system_video_lock_flag 1 + marker_bit 1 + video_bound 5 + packet_rate_restriction_flag 1 + reserved_bits 7 + */ + + /* MPEG-1 system header start code */ + if((buffer[6]&0x80)==0x80 && (buffer[8]&0x01)==0x01 && buffer[11]==0xff) + { + if(is_valid_packet_size(buffer, buffer_size)==0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mpg) + { + header_ignored(file_recovery_new); + return 0; + } + return header_mpg_found(file_recovery_new); + } + return 0; +} + +/*@ + @ requires buffer_size >= 11; + @ requires separation: \separated(&file_hint_mpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_mpg_Sequence(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* MPEG-1 sequence header code 0x1B3 */ + /* horizontal size>0 */ + if((buffer[4]<<4)+(buffer[5]>>4)>0 && + /* vertical size>0 */ + ((buffer[5]&0x0f)<<8)+buffer[6]>0 && + /* aspect_ratio */ + (buffer[7]>>4)!=0 && (buffer[7]>>4)!=15 && + /* picture rate*/ + (buffer[7]&0x0f)!=0 && (buffer[7]&0xf)!=15 && + /* bit rate */ + (buffer[8]!=0 || buffer[9]!=0 || (buffer[10]&0xc0)!=0) && + /* marker */ + (buffer[10]&0x20)==0x20) + { + if(is_valid_packet_size(buffer, buffer_size)==0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mpg) + { + header_ignored(file_recovery_new); + return 0; + } + return header_mpg_found(file_recovery_new); + } + return 0; +} + +/*@ + @ requires buffer_size >= 6; + @ requires separation: \separated(&file_hint_mpg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_mpg4_ElemVideo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* ISO/IEC 14496-2 (MPEG-4 video) ELEMENTARY VIDEO HEADER - visual object start code */ + /* is_visual_object_identifier */ + if((buffer[4]&0xf0)==0x80 && + /* visual_object_verid */ + (((buffer[4]>>3)&0x0f)==1 || ((buffer[4]>>3)&0x0f)==2) && + /* visual_object_priority */ + (buffer[4]&0x7)!=0 && + /* visual_object_type */ + (buffer[5]>>4)!=0 && (buffer[5]>>4)!=0x0f + ) + { + if(is_valid_packet_size(buffer, buffer_size)==0) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_mpg) + { + header_ignored(file_recovery_new); + return 0; + } + return header_mpg_found(file_recovery_new); + } + return 0; +} + +static void register_header_check_mpg(file_stat_t *file_stat) +{ + static const unsigned char mpg_header_B3[4]= {0x00, 0x00, 0x01, 0xB3}; + static const unsigned char mpg_header_B5[4]= {0x00, 0x00, 0x01, 0xB5}; + static const unsigned char mpg_header_BA[4]= {0x00, 0x00, 0x01, 0xBA}; + static const unsigned char mpg_header_BB[4]= {0x00, 0x00, 0x01, 0xBB}; + register_header_check(0, mpg_header_B3,sizeof(mpg_header_B3), &header_check_mpg_Sequence, file_stat); + register_header_check(0, mpg_header_B5,sizeof(mpg_header_B5), &header_check_mpg4_ElemVideo, file_stat); + register_header_check(0, mpg_header_BA,sizeof(mpg_header_BA), &header_check_mpg_Pack, file_stat); + register_header_check(0, mpg_header_BB,sizeof(mpg_header_BB), &header_check_mpg_System, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mpl.c b/subprojects/lib/src/file_mpl.c new file mode 100644 index 0000000..1ba53b1 --- /dev/null +++ b/subprojects/lib/src/file_mpl.c @@ -0,0 +1,63 @@ +/* + + File: file_mpl.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mpl) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mpl(file_stat_t *file_stat); + +const file_hint_t file_hint_mpl= { + .extension="mpl", + .description="AVHCD playlist", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mpl +}; + +/*@ + @ requires separation: \separated(&file_hint_mpl, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mpl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mpl.extension; + return 1; +} + +static void register_header_check_mpl(file_stat_t *file_stat) +{ + register_header_check(0, "MPLS0100", 8, &header_check_mpl, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mrw.c b/subprojects/lib/src/file_mrw.c new file mode 100644 index 0000000..1210f07 --- /dev/null +++ b/subprojects/lib/src/file_mrw.c @@ -0,0 +1,110 @@ +/* + + File: file_mrw.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mrw) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mrw(file_stat_t *file_stat); + +const file_hint_t file_hint_mrw= { + .extension="mrw", + .description="Minolta Raw picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mrw +}; + +struct hdr { + uint32_t fourcc; + uint32_t size; +#if 0 + char data[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +struct prd { + char ver[8]; + struct { + uint16_t y; + uint16_t x; + } ccd; + struct { + uint16_t y; + uint16_t x; + } img; + uint8_t datasize; // bpp, 12 or 16 + uint8_t pixelsize; // bits used, always 12 + uint8_t storagemethod; // 0x52 means not packed + uint8_t unknown1; + uint16_t unknown2; + uint16_t pattern; // 0x0001 RGGB, or 0x0004 GBRG +} __attribute__ ((gcc_struct, __packed__)); + +/* Minolta */ +/*@ + @ requires buffer_size >= 2*sizeof(struct hdr) + sizeof(struct prd); + @ requires separation: \separated(&file_hint_mrw, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mrw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char prd_header[4]= { 0x00,'P','R','D'}; + const struct hdr *mrmhdr = (const struct hdr*)buffer; + const struct hdr *prdhdr = (const struct hdr*)&buffer[sizeof(struct hdr)]; + /* Picture Raw Dimensions */ + const struct prd *prd = (const struct prd*)&buffer[2*sizeof(struct hdr)]; + if(memcmp(&prdhdr->fourcc, prd_header, sizeof(prd_header))!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mrw.extension; + file_recovery_new->calculated_file_size= (uint64_t)be32(mrmhdr->size)+ 8 + + ((uint64_t)be16(prd->ccd.x) * be16(prd->ccd.y) * prd->datasize + 8 - 1) / 8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + /* + log_debug("size=%lu x=%lu y=%lu datasize=%lu\n", be32(mrmhdr->size), + be16(prd->ccd.x), be16(prd->ccd.y), prd->datasize); + log_debug("mrw_file_size %lu\n", (long unsigned)file_recovery_new->calculated_file_size); + */ + return 1; +} + +static void register_header_check_mrw(file_stat_t *file_stat) +{ + static const unsigned char mrw_header[4]= { 0x00,'M','R','M'}; /* Minolta Raw */ + register_header_check(0, mrw_header,sizeof(mrw_header), &header_check_mrw, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_msa.c b/subprojects/lib/src/file_msa.c new file mode 100644 index 0000000..1f0c9a1 --- /dev/null +++ b/subprojects/lib/src/file_msa.c @@ -0,0 +1,92 @@ +/* + + File: file_msa.c + + Copyright (C) 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_msa) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_msa(file_stat_t *file_stat); + +const file_hint_t file_hint_msa= { + .extension="msa", + .description="Mensura", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_msa +}; + +struct msa_header +{ + uint32_t magic; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size > 0x13; + @ requires separation: \separated(&file_hint_msa, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_msa(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct msa_header *msa=(const struct msa_header *)buffer; + const uint64_t size=le32(msa->size); + if(buffer[0x13]!=0x40) + return 0; + if(size <= 0x13) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_msa.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_msa(file_stat_t *file_stat) +{ + static const unsigned char msa_header_fb[4]= { + 0xfb, 0xff, 0xff, 0xff + }; + static const unsigned char msa_header_fc[4]= { + 0xfc, 0xff, 0xff, 0xff + }; + register_header_check(0, msa_header_fb, sizeof(msa_header_fb), &header_check_msa, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, msa_header_fc, sizeof(msa_header_fc), &header_check_msa, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_mus.c b/subprojects/lib/src/file_mus.c new file mode 100644 index 0000000..960c529 --- /dev/null +++ b/subprojects/lib/src/file_mus.c @@ -0,0 +1,79 @@ +/* + + File: file_mus.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mus) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mus(file_stat_t *file_stat); + +const file_hint_t file_hint_mus = { + .extension = "mus", + .description = "Finale Music Score", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_mus +}; + +/*@ + @ requires file_recovery->file_check == &file_check_mus; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_mus(file_recovery_t *file_recovery) +{ + const unsigned char mus_footer[5] = { '-', '^', 'e', 'n', 'd' }; + file_search_footer(file_recovery, mus_footer, sizeof(mus_footer), 0); +} + +/*@ + @ requires separation: \separated(&file_hint_mus, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mus(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize = 18; + file_recovery_new->file_check = &file_check_mus; + file_recovery_new->extension = file_hint_mus.extension; + return 1; +} + +static void register_header_check_mus(file_stat_t *file_stat) +{ + static const unsigned char mus_header[18] = { 'E', 'N', 'I', 'G', 'M', 'A', ' ', 'B', 'I', 'N', 'A', 'R', 'Y', ' ', 'F', 'I', 'L', 'E' }; + register_header_check(0, mus_header, sizeof(mus_header), &header_check_mus, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mxf.c b/subprojects/lib/src/file_mxf.c new file mode 100644 index 0000000..360a6ad --- /dev/null +++ b/subprojects/lib/src/file_mxf.c @@ -0,0 +1,164 @@ +/* + + File: file_mxf.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mxf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_mxf(file_stat_t *file_stat); + +const file_hint_t file_hint_mxf= { + .extension="mxf", + .description="Material Exchange Format", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mxf +}; + +/* http://tools.ietf.org/html/rfc4539 + * Media Type Registration for the + * Society of Motion Picture and Television Engineers (SMPTE) + * Material Exchange Format (MXF) + * */ + +struct partition_pack_next +{ + uint16_t major_version; + uint16_t minor_version; + uint32_t kagsize; + uint64_t this_partition; + uint64_t previous_partition; + uint64_t footer_partition; + uint64_t header_byte_count; + uint64_t index_byte_count; + uint32_t index_SID; + uint64_t body_offset; + uint32_t body_SID; + char op_pattern[16]; +#ifndef __FRAMAC__ + char essence_container[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_mxf; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_mxf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + static const unsigned char mxf_header[4]= { 0x06, 0x0e, 0x2b, 0x34 }; + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 0x14 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 0x14; */ + if(memcmp(&buffer[i], mxf_header, sizeof(mxf_header))!=0) + return DC_STOP; +#ifdef DEBUG_MXF + log_info("data_check_mxf: header found 0x%02x\n", buffer[i+0x10]); + log_info("fs=0x%llx\n", file_recovery->calculated_file_size); +#endif + switch(buffer[i+0x10]) + { + case 0x81: + file_recovery->calculated_file_size+=(uint64_t)0x14+buffer[i+0x11]; + break; + case 0x82: + file_recovery->calculated_file_size+=(uint64_t)0x14+(buffer[i+0x11]<<8)+buffer[i+0x12]; + break; + case 0x83: + file_recovery->calculated_file_size+=(uint64_t)0x14+(buffer[i+0x11]<<16)+(buffer[i+0x12]<<8)+buffer[i+0x13]; + break; + case 0x84: + { + const uint32_t *p32=(const uint32_t*)&buffer[i+0x11]; + file_recovery->calculated_file_size+=(uint64_t)0x14 + le32(*p32); + } + break; + default: + file_recovery->calculated_file_size+=(uint64_t)0x14+buffer[i+0x10]; + break; + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 0x26; + @ requires separation: \separated(&file_hint_mxf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mxf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct partition_pack_next *hdr; + if(buffer[0x0d]!=0x02 || buffer[0x0e]!=0x04) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_mxf.extension; + switch(buffer[0x10]) + { + case 0x81: + hdr=(const struct partition_pack_next *)&buffer[0x12]; + break; + case 0x82: + hdr=(const struct partition_pack_next *)&buffer[0x13]; + break; + case 0x83: + hdr=(const struct partition_pack_next *)&buffer[0x14]; + break; + case 0x84: + hdr=(const struct partition_pack_next *)&buffer[0x15]; + break; + default: + hdr=(const struct partition_pack_next *)&buffer[0x11]; + break; + } + file_recovery_new->calculated_file_size=be64(hdr->footer_partition); + file_recovery_new->data_check=&data_check_mxf; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_mxf(file_stat_t *file_stat) +{ + static const unsigned char mxf_header[11]= { + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01, + 0x0d, 0x01, 0x02 + }; + register_header_check(0, mxf_header,sizeof(mxf_header), &header_check_mxf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_myo.c b/subprojects/lib/src/file_myo.c new file mode 100644 index 0000000..4351bd8 --- /dev/null +++ b/subprojects/lib/src/file_myo.c @@ -0,0 +1,76 @@ +/* + + File: file_myo.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_myo) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_myo(file_stat_t *file_stat); + +const file_hint_t file_hint_myo= { + .extension="myo", + .description="Mind Your Own Business", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_myo +}; + +/*@ + @ requires buffer_size >= 4; + @ requires separation: \separated(&file_hint_myo, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_myo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=(uint64_t)buffer[0]+(((uint64_t)buffer[1])<<8)+(((uint64_t)buffer[2])<<16)+(((uint64_t)buffer[3])<<24)+1; + if(size < 0x9ce + 6) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_myo) + { + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_myo.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_myo(file_stat_t *file_stat) +{ + register_header_check(0x9ce, "FC!DEF", 6, &header_check_myo, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_mysql.c b/subprojects/lib/src/file_mysql.c new file mode 100644 index 0000000..b68984b --- /dev/null +++ b/subprojects/lib/src/file_mysql.c @@ -0,0 +1,88 @@ +/* + + File: file_mysql.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_mysql) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_mysql(file_stat_t *file_stat); + +const file_hint_t file_hint_mysql= { + .extension="MYI", + .description="MySQL (myi/frm)", + .max_filesize=0, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_mysql +}; + +/*@ + @ requires separation: \separated(&file_hint_mysql, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_myisam(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* MySQL MYISAM compressed data file Version 1 */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="MYI"; + return 1; +} + +/*@ + @ requires buffer_size >= 6; + @ requires separation: \separated(&file_hint_mysql, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mysql(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* MySQL table definition file Version 7 up to 10 */ + if(buffer[0]==0xfe && buffer[1]==0x01 && (buffer[2]>=0x07 && buffer[2]<=0x0A) && buffer[3]==0x09 && buffer[5]==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="frm"; + return 1; + } + return 0; +} + +static void register_header_check_mysql(file_stat_t *file_stat) +{ + static const unsigned char mysql_header[4]= {0xfe, 0xfe, 0x07, 0x01}; + static const unsigned char mysql_header_def[2]= {0xfe, 0x01}; + register_header_check(0, mysql_header,sizeof(mysql_header), &header_check_myisam, file_stat); + register_header_check(0, mysql_header_def,sizeof(mysql_header_def), &header_check_mysql, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_nd2.c b/subprojects/lib/src/file_nd2.c new file mode 100644 index 0000000..39eba97 --- /dev/null +++ b/subprojects/lib/src/file_nd2.c @@ -0,0 +1,67 @@ +/* + + File: file_nd2.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nd2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_nd2(file_stat_t *file_stat); + +const file_hint_t file_hint_nd2= { + .extension="nd2", + .description="NIS-Elements", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_nd2 +}; + +/*@ + @ requires buffer_size >= 0x34; + @ requires separation: \separated(&file_hint_nd2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_nd2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isdigit(buffer[0x10+0x23])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_nd2.extension; + return 1; +} + +static void register_header_check_nd2(file_stat_t *file_stat) +{ + register_header_check(0x10, "ND2 FILE SIGNATURE CHUNK NAME01!Ver", 0x23, &header_check_nd2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_nds.c b/subprojects/lib/src/file_nds.c new file mode 100644 index 0000000..bf15fc9 --- /dev/null +++ b/subprojects/lib/src/file_nds.c @@ -0,0 +1,91 @@ +/* + + File: file_nds.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nds) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_nds(file_stat_t *file_stat); + +const file_hint_t file_hint_nds= { + .extension="nds", + .description="Nintendo DS Game ROM Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_nds +}; + +/*@ + @ requires file_recovery->file_rename==&file_rename_nds; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_nds(file_recovery_t *file_recovery) +{ + FILE *file; + unsigned char buffer[12]; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(fread(&buffer, sizeof(buffer), 1, file) != 1) + { + fclose(file); + return ; + } + fclose(file); + file_rename(file_recovery, &buffer, 12, 0, file_hint_nds.extension, 0); +} + +/*@ + @ requires buffer_size >= 0x10; + @ requires separation: \separated(&file_hint_nds, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_nds(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x0c], "NTRJ", 4)==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_nds.extension; + file_recovery_new->min_filesize=0x180; + file_recovery_new->file_rename=&file_rename_nds; + return 1; +} + +static void register_header_check_nds(file_stat_t *file_stat) +{ + static const unsigned char nds_header[6]= { + 0x24, 0xff, 0xae, 0x51, 0x69, 0x9a + }; + register_header_check(0xc0, nds_header, sizeof(nds_header), &header_check_nds, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_nes.c b/subprojects/lib/src/file_nes.c new file mode 100644 index 0000000..8863bdd --- /dev/null +++ b/subprojects/lib/src/file_nes.c @@ -0,0 +1,79 @@ +/* + + File: file_nes.c + + Copyright (C) 2013 James Holodnak + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nes) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_nes(file_stat_t *file_stat); + +const file_hint_t file_hint_nes= { + .extension="nes", + .description="iNES/iNES 2.0 ROM image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=0, + .register_header_check=®ister_header_check_nes +}; + +struct nes_header +{ + char ident[4]; + uint8_t prgsize; + uint8_t chrsize; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct nes_header); + @ requires separation: \separated(&file_hint_nes, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_nes(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct nes_header *bm=(const struct nes_header *)buffer; + const uint64_t size=16+bm->prgsize*0x4000+bm->chrsize*0x2000; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_nes.extension; + file_recovery_new->min_filesize=16; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_nes(file_stat_t *file_stat) +{ + static const unsigned char nes_header[4]= {'N','E','S',0x1A}; + register_header_check(0, nes_header,sizeof(nes_header), &header_check_nes, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_njx.c b/subprojects/lib/src/file_njx.c new file mode 100644 index 0000000..89da043 --- /dev/null +++ b/subprojects/lib/src/file_njx.c @@ -0,0 +1,84 @@ +/* + + File: file_njx.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_njx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_njx(file_stat_t *file_stat); + +const file_hint_t file_hint_njx= { + .extension="njx", + .description="NJStar Document", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_njx +}; + +/*@ + @ requires file_recovery->file_check == &file_check_njx; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_njx(file_recovery_t *file_recovery) +{ + const unsigned char njx_footer[4]= {'N', 'J', '*', 0x04}; + file_search_footer(file_recovery, njx_footer, sizeof(njx_footer), 0); +} + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_njx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_njx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]==0x04 && buffer[1]=='N' && buffer[2]=='j' && buffer[3]==0x0f && + buffer[6]=='N' && buffer[7]=='J' && buffer[8]=='S' && buffer[9]=='t' && buffer[10]=='a' && buffer[11]=='r') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_njx; + file_recovery_new->extension=file_hint_njx.extension; + return 1; + } + return 0; +} + +static void register_header_check_njx(file_stat_t *file_stat) +{ + static const unsigned char njx_header[4]= {0x04, 'N', 'j', 0x0f}; + register_header_check(0, njx_header,sizeof(njx_header), &header_check_njx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_nk2.c b/subprojects/lib/src/file_nk2.c new file mode 100644 index 0000000..71c17bb --- /dev/null +++ b/subprojects/lib/src/file_nk2.c @@ -0,0 +1,251 @@ +/* + + File: file_nk2.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nk2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_nk2(file_stat_t *file_stat); +#define NK2_MAX_FILESIZE 100*1024*1024 + +const file_hint_t file_hint_nk2= { + .extension="nk2", + .description="Outlook Nickfile", + .max_filesize=NK2_MAX_FILESIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_nk2 +}; + +typedef struct { + uint32_t magic; + uint32_t magic2; + uint32_t magic3; + uint32_t items_count; +} nk2Header; + +typedef struct { + uint32_t entries_count; +} itemHeader; + +typedef struct { + uint16_t value_type; + uint16_t entry_type; + uint32_t unk1; + uint32_t unk2; + uint32_t unk3; +} entryHeader; + +#define PT_UNSPECIFIED 0x0000 +#define PT_NULL 0x0001 +#define PT_I2 0x0002 +#define PT_LONG 0x0003 +#define PT_R4 0x0004 +#define PT_DOUBLE 0x0005 +#define PT_CURRENCY 0x0006 +#define PT_APPTIME 0x0007 +#define PT_ERROR 0x000a /* means the given attr contains no value */ +#define PT_BOOLEAN 0x000b +#define PT_OBJECT 0x000d +#define PT_I8 0x0014 +#define PT_STRING8 0x001e +#define PT_UNICODE 0x001f +#define PT_SYSTIME 0x0040 +#define PT_CLSID 0x0048 +#define PT_SRVEID 0x00fb +#define PT_SRESTRICT 0x00fd +#define PT_ACTIONS 0x00fe +#define PT_BINARY 0x0102 + +/*@ + @ requires fr->file_check == &file_check_nk2; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, fr->file_size, fr->offset_error, fr->offset_ok; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_nk2(file_recovery_t *fr) +{ + char buf_nk2h[sizeof(nk2Header)]; + const nk2Header *nk2h=(const nk2Header *)&buf_nk2h; + unsigned int i; + fr->file_size = 0; + fr->offset_error=0; + fr->offset_ok=0; + if(my_fseek(fr->handle, 0, SEEK_SET) < 0 || + fread(&buf_nk2h, sizeof(nk2Header), 1, fr->handle)!=1) + return; +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buf_nk2h, sizeof(nk2Header)); +#endif + fr->file_size+=sizeof(nk2Header); +#ifdef DEBUG_NK2 + log_info("nk2 item_count=%u\n", (unsigned int)le32(nk2h->items_count)); +#endif + /*@ + @ loop assigns *fr->handle, errno, fr->file_size, fr->offset_error; + @ loop assigns Frama_C_entropy_source; + @ loop assigns i; + @*/ + for(i=0; iitems_count); i++) + { + unsigned int j; + char buf_itemh[sizeof(itemHeader)]; + const itemHeader *itemh=(const itemHeader *)&buf_itemh; + if(fr->file_size >= NK2_MAX_FILESIZE) + { + fr->file_size=0; + return; + } + /*@ assert fr->file_size < NK2_MAX_FILESIZE; */ + if (fread(&buf_itemh, sizeof(itemHeader), 1, fr->handle)!=1) + { + fr->offset_error=fr->file_size; + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buf_itemh, sizeof(buf_itemh)); +#endif + fr->file_size+=sizeof(itemHeader); +#ifdef DEBUG_NK2 + log_info("nk2 entries_count=%u\n", (unsigned int)le32(itemh->entries_count)); +#endif + /*@ + @ loop assigns *fr->handle, errno, fr->file_size, fr->offset_error; + @ loop assigns Frama_C_entropy_source; + @ loop assigns j; + @*/ + for(j=0; jentries_count); j++) + { + uint64_t size; + char buf_entryh[sizeof(entryHeader)]; + const entryHeader *entryh=(const entryHeader *)&buf_entryh; + if (fread(&buf_entryh, sizeof(entryHeader), 1, fr->handle)!=1) + { + fr->offset_error=fr->file_size; + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buf_entryh, sizeof(entryHeader)); +#endif + switch(le16(entryh->value_type)) + { + case PT_LONG: + case PT_BOOLEAN: + case PT_ERROR: + case PT_NULL: + size=0; + break; + case PT_UNICODE: + case PT_BINARY: + { + char buf_entry_size[sizeof(uint32_t)]; + const uint32_t *entry_size=(const uint32_t *)&buf_entry_size; + if (fread(&buf_entry_size, sizeof(uint32_t), 1, fr->handle)!=1) + { + fr->offset_error=fr->file_size; + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buf_entry_size, sizeof(uint32_t)); +#endif + size=(uint64_t)4+le32(*entry_size); + } + break; + default: + log_info("nk2 entry %04x size=? at 0x%llx\n", + le16(entryh->value_type), + (long long unsigned)fr->file_size); + fr->offset_error=fr->file_size; + fr->file_size=0; + return; + } +#ifdef DEBUG_NK2 + { + log_info("nk2 entry %04x size=%u at 0x%llx\n", + le16(entryh->value_type), + (unsigned int)size, + (long long unsigned)fr->file_size); + char buffer[2048]; + unsigned int size_to_log=size; + if(size_to_log>2048) + size_to_log=2048; + fread(&buffer, size_to_log, 1, fr->handle); +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, 2048); +#endif + dump_log(&buffer, size_to_log); + } +#endif + fr->file_size+=sizeof(entryHeader); + if(fr->file_size >= NK2_MAX_FILESIZE) + { + fr->file_size=0; + return; + } + if (my_fseek(fr->handle, fr->file_size+size, SEEK_SET) < 0) + { + fr->offset_error=fr->file_size; + fr->file_size=0; + return; + } + fr->file_size+=size; + } + } + fr->file_size+=12; +} + +/*@ + @ requires separation: \separated(&file_hint_nk2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_nk2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_nk2.extension; + file_recovery_new->file_check=&file_check_nk2; + return 1; +} + +static void register_header_check_nk2(file_stat_t *file_stat) +{ + static const unsigned char nk2_header[8]= { 0x0d, 0xf0, 0xad, 0xba, 0x0a, 0x00, 0x00, 0x00 }; + register_header_check(0, nk2_header, sizeof(nk2_header), &header_check_nk2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_nsf.c b/subprojects/lib/src/file_nsf.c new file mode 100644 index 0000000..2fca4c5 --- /dev/null +++ b/subprojects/lib/src/file_nsf.c @@ -0,0 +1,71 @@ +/* + + File: file_nsf.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_nsf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_nsf(file_stat_t *file_stat); + +const file_hint_t file_hint_nsf= { + .extension="nsf", + .description="Lotus Notes", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_nsf +}; + +/*@ + @ requires buffer_size >= 0x12; + @ requires separation: \separated(&file_hint_nsf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_nsf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* I hope it's a valid check */ + if(buffer[0x10]!=0x25 || buffer[0x11]!=0x85) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_nsf.extension; + return 1; +} + +static void register_header_check_nsf(file_stat_t *file_stat) +{ + static const unsigned char nsf_header[6]= { + 0x1a, 0x00, 0x00, 0x04, 0x00, 0x00 + }; + register_header_check(0, nsf_header, sizeof(nsf_header), &header_check_nsf, file_stat); +} + +#endif diff --git a/subprojects/lib/src/file_oci.c b/subprojects/lib/src/file_oci.c new file mode 100644 index 0000000..08d41b1 --- /dev/null +++ b/subprojects/lib/src/file_oci.c @@ -0,0 +1,134 @@ +/* + + File: file_oci.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_oci) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_oci(file_stat_t *file_stat); + +const file_hint_t file_hint_oci= { + .extension="oci", + .description="OpenCanvas Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_oci +}; + +struct oci_header +{ + unsigned char type[4]; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_oci; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_oci(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8; */ + const struct oci_header *hdr=(const struct oci_header *)&buffer[i]; + const unsigned int atom_size=le32(hdr->size); +#ifdef DEBUG_MOV + log_trace("file_oci.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n", + file_recovery->filename, + buffer[i],buffer[i+1],buffer[i+2],buffer[i+3], + buffer[i],buffer[i+1],buffer[i+2],buffer[i+3], + (long long unsigned)atom_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(buffer[i+0]=='O' && + (buffer[i+1]>='A' && buffer[i+1]<='Z') && + (buffer[i+2]>='A' && buffer[i+2]<='Z') && + (buffer[i+3]>='A' && buffer[i+3]<='Z')) + { + file_recovery->calculated_file_size+=(uint64_t)8+atom_size; + } + else + { + return DC_STOP; + } + } +#ifdef DEBUG_MOV + log_trace("file_oci.c: new calculated_file_size %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct oci_header); + @ requires separation: \separated(&file_hint_oci, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_oci(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct oci_header *hdr=(const struct oci_header *)buffer; + const unsigned int size=le32(hdr->size); + if(size >= 0x0fffffff0) + return 0; + if(8+size+8 <= buffer_size) + { + const struct oci_header *hdr2=(const struct oci_header *)&buffer[8+size]; + if(!(hdr2->type[0]=='O' && + (hdr2->type[1]>='A' && hdr2->type[1]<='Z') && + (hdr2->type[2]>='A' && hdr2->type[2]<='Z') && + (hdr2->type[3]>='A' && hdr2->type[3]<='Z'))) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_oci.extension; + if(file_recovery_new->blocksize < 8) + return 1; + file_recovery_new->data_check=&data_check_oci; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_oci(file_stat_t *file_stat) +{ + static const unsigned char oci_header[8]= { + 'O' , 'P' , 'I' , 'M' , '0' , 0x00, 0x00, 0x00 + }; + register_header_check(0, oci_header, sizeof(oci_header), &header_check_oci, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ogg.c b/subprojects/lib/src/file_ogg.c new file mode 100644 index 0000000..6f19fb7 --- /dev/null +++ b/subprojects/lib/src/file_ogg.c @@ -0,0 +1,138 @@ +/* + + File: file_ogg.c + + Copyright (C) 1998-2005,2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ogg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ogg(file_stat_t *file_stat); + +const file_hint_t file_hint_ogg= { + .extension="ogg", + .description="OGG audio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ogg +}; + +/* header=OggS, version=0 */ +static const unsigned char ogg_header[5]= {'O','g','g','S', 0x00}; + +/* http://www.ietf.org/rfc/rfc3533.txt */ +/*@ + @ requires file_recovery->data_check==&data_check_ogg; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_ogg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 27 +255 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - (27 + 255); */ + if(memcmp(&buffer[i],ogg_header,sizeof(ogg_header))==0) + { + const unsigned int number_page_segments=buffer[i+26]; + const unsigned int header_size = number_page_segments + 27; + unsigned int page_size; + unsigned int j; + page_size=header_size; + /*@ + @ loop invariant page_size <= 255 + 27 + j * 255; + @ loop assigns j, page_size; + @ */ + for(j=0; jcalculated_file_size+=page_size; + /* + log_debug("+0x%x=0x%x\n",page_size,file_recovery->calculated_file_size); + */ + } + else + { + return DC_STOP; + } + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 0x78+7; + @ requires separation: \separated(&file_hint_ogg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_ogg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + static const unsigned char sign_theora[7]= {0x80, 't', 'h', 'e', 'o', 'r', 'a'}; + /* http://en.wikipedia.org/wiki/Ogg#File_format */ + /* Return if not Beginning Of Stream and already saving the file */ + if((buffer[5]&0x02)!=0x02 && + file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_ogg) + { + header_ignored(file_recovery_new); + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=0; + if(file_recovery_new->blocksize > 27+255) + { + file_recovery_new->data_check=&data_check_ogg; + file_recovery_new->file_check=&file_check_size; + } + /* Ogg data, Theora video */ + if(memcmp(&buffer[28], sign_theora, sizeof(sign_theora))==0) + file_recovery_new->extension="ogv"; + else if(memcmp(&buffer[0x78], sign_theora, sizeof(sign_theora))==0) + file_recovery_new->extension="ogv"; + else + file_recovery_new->extension=file_hint_ogg.extension; + return 1; +} + +static void register_header_check_ogg(file_stat_t *file_stat) +{ + register_header_check(0, ogg_header,sizeof(ogg_header), &header_check_ogg, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_one.c b/subprojects/lib/src/file_one.c new file mode 100644 index 0000000..06a47d0 --- /dev/null +++ b/subprojects/lib/src/file_one.c @@ -0,0 +1,74 @@ +/* + + File: file_one.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_one) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_one(file_stat_t *file_stat); + +const file_hint_t file_hint_one= { + .extension="one", + .description="Microsoft OneNote", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_one +}; + +/*@ + @ requires buffer_size >= 200; + @ requires separation: \separated(&file_hint_one, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_one(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=(buffer[196]<<0)+(buffer[197]<<8)+(buffer[198]<<16)+((uint64_t)buffer[199]<<24); + if(size < 200) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_one.extension; + file_recovery_new->min_filesize=200; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_one(file_stat_t *file_stat) +{ + static const unsigned char one_header[16]= { + 0xe4, 0x52, 0x5c, 0x7b, 0x8c, 0xd8, 0xa7, 0x4d, + 0xae, 0xb1, 0x53, 0x78, 0xd0, 0x29, 0x96, 0xd3 }; + register_header_check(0, one_header,sizeof(one_header), &header_check_one, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_orf.c b/subprojects/lib/src/file_orf.c new file mode 100644 index 0000000..01c091b --- /dev/null +++ b/subprojects/lib/src/file_orf.c @@ -0,0 +1,82 @@ +/* + + File: file_orf.c + + Copyright (C) 1998-2005,2007-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_orf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "file_tiff.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_orf(file_stat_t *file_stat); + +const file_hint_t file_hint_orf= { + .extension="orf", + .description="Olympus Raw Format picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_orf +}; + +/*@ + @ requires separation: \separated(&file_hint_orf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_orf_IIRS(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_orf.extension; + return 1; +} + +/*@ + @ requires separation: \separated(&file_hint_orf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_orf_IIRO(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_orf.extension; + file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size); + file_recovery_new->file_check=&file_check_tiff_le; + return 1; +} + +static void register_header_check_orf(file_stat_t *file_stat) +{ + static const unsigned char orf_header_IIRS[8]= { 0x49, 0x49, 0x52, 0x53, 0x08, 0x00, 0x00, 0x00}; + static const unsigned char orf_header_IIRO[8]= { 'I', 'I', 'R', 'O', 0x08, 0x00, 0x00, 0x00}; + register_header_check(0, orf_header_IIRS, sizeof(orf_header_IIRS), &header_check_orf_IIRS, file_stat); + register_header_check(0, orf_header_IIRO, sizeof(orf_header_IIRO), &header_check_orf_IIRO, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_paf.c b/subprojects/lib/src/file_paf.c new file mode 100644 index 0000000..a62a6ef --- /dev/null +++ b/subprojects/lib/src/file_paf.c @@ -0,0 +1,67 @@ +/* + + File: file_paf.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_paf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_paf(file_stat_t *file_stat); + +const file_hint_t file_hint_paf= { + .extension="paf", + .description="Personal Ancestral File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_paf +}; + +/* Personal Ancestral File Family Database is handled by + * The Church of Jesus Christ of Latter-day Saints */ + +/*@ + @ requires separation: \separated(&file_hint_paf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_paf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_paf.extension; + return 1; +} + +static void register_header_check_paf(file_stat_t *file_stat) +{ + static const unsigned char paf_header[11]= {'5', '0', '0', '\0', '5', '0', '0', '\0', 'P','A','F'}; + register_header_check(0, paf_header,sizeof(paf_header), &header_check_paf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pap.c b/subprojects/lib/src/file_pap.c new file mode 100644 index 0000000..308568b --- /dev/null +++ b/subprojects/lib/src/file_pap.c @@ -0,0 +1,65 @@ +/* + + File: file_pap.c + + Copyright (C) 2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pap) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pap(file_stat_t *file_stat); + +const file_hint_t file_hint_pap= { + .extension="pap", + .description="Papyrus word file", + .max_filesize=1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pap +}; + +/*@ + @ requires separation: \separated(&file_hint_pap, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pap(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pap.extension; + return 1; +} + +static void register_header_check_pap(file_stat_t *file_stat) +{ + static const unsigned char pap_header[] = {'P','A','P','1'}; + register_header_check(0, pap_header,sizeof(pap_header), &header_check_pap, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_par2.c b/subprojects/lib/src/file_par2.c new file mode 100644 index 0000000..cfc33ec --- /dev/null +++ b/subprojects/lib/src/file_par2.c @@ -0,0 +1,158 @@ +/* + + File: file_par2.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_par2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_par2(file_stat_t *file_stat); + +const file_hint_t file_hint_par2= { + .extension="par2", + .description="parchive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_par2 +}; + +static const unsigned char par2_header[8]= { + 'P' , 'A' , 'R' , '2' , 0x00, 'P' , 'K' , 'T' +}; + +/*@ + @ requires file_recovery->data_check == &data_check_par2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_par2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 16; */ + const uint64_t length=le64((*(const uint64_t *)(&buffer[i+8]))); + if(memcmp(&buffer[i], &par2_header, sizeof(par2_header))!=0) + return DC_STOP; + if(length % 4 !=0 || length < 16 || length > PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + file_recovery->calculated_file_size+=length; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_par2; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_par2(file_recovery_t *file_recovery) +{ + FILE *file; + uint64_t offset=0; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + /*@ loop invariant valid_file_rename_param(file_recovery); */ + while(offset <= PHOTOREC_MAX_FILE_SIZE) + { + uint64_t length; + size_t buffer_size; + unsigned char buffer[4096]; + const uint64_t *lengthp=(const uint64_t *)&buffer[8]; + if(my_fseek(file, offset, SEEK_SET)<0) + { + fclose(file); + return; + } + buffer_size=fread(buffer, 1, sizeof(buffer), file); + if(buffer_size<0x78) + { + fclose(file); + return; + } + length=le64(*lengthp); + if(length % 4 !=0 || length < 16 || length >= PHOTOREC_MAX_FILE_SIZE || + memcmp(&buffer, &par2_header, sizeof(par2_header))!=0) + { + fclose(file); + return; + } + if(memcmp(&buffer[0x30], "PAR 2.0\0FileDesc", 16)==0) + { + fclose(file); + file_rename(file_recovery, buffer, + (length < buffer_size ? length : buffer_size), + 0x78, NULL, 1); + return ; + } + offset+=length; + } + fclose(file); + return; +} + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_par2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_par2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t length=le64((*(const uint64_t *)(&buffer[8]))); + if(length % 4 !=0 || length < 16 || length > PHOTOREC_MAX_FILE_SIZE) + return 0; + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_par2) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_par2.extension; + file_recovery_new->file_rename=&file_rename_par2; + file_recovery_new->min_filesize=64+length; + if(file_recovery_new->blocksize < 16) + return 1; + file_recovery_new->data_check=&data_check_par2; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_par2(file_stat_t *file_stat) +{ + register_header_check(0, par2_header, sizeof(par2_header), &header_check_par2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pcap.c b/subprojects/lib/src/file_pcap.c new file mode 100644 index 0000000..504a9c2 --- /dev/null +++ b/subprojects/lib/src/file_pcap.c @@ -0,0 +1,72 @@ +/* + + File: file_pcap.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcap) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pcap(file_stat_t *file_stat); + +const file_hint_t file_hint_pcap= { + .extension="pcap", + .description="tcpdump capture file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pcap +}; + +/*@ + @ requires separation: \separated(&file_hint_pcap, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pcap(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="pcp"; +#else + file_recovery_new->extension=file_hint_pcap.extension; +#endif + return 1; +} + +static void register_header_check_pcap(file_stat_t *file_stat) +{ + static const unsigned char pcap_le_header1[6] = {0xd4, 0xc3, 0xb2, 0xa1, 0x01, 0x00}; + static const unsigned char pcap_le_header2[6] = {0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00}; + register_header_check(0, pcap_le_header1, sizeof(pcap_le_header1), &header_check_pcap, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, pcap_le_header2, sizeof(pcap_le_header2), &header_check_pcap, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_pcb.c b/subprojects/lib/src/file_pcb.c new file mode 100644 index 0000000..b6492f4 --- /dev/null +++ b/subprojects/lib/src/file_pcb.c @@ -0,0 +1,67 @@ +/* + + File: file_pcb.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pcb(file_stat_t *file_stat); + +const file_hint_t file_hint_pcb= { + .extension="pcb", + .description="PCB Wizard", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pcb +}; + +/*@ + @ requires separation: \separated(&file_hint_pcb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pcb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pcb.extension; + file_recovery_new->min_filesize=8; + return 1; +} + +static void register_header_check_pcb(file_stat_t *file_stat) +{ + static const unsigned char pcb_header[8]= { + 'D' , 's' , 'g' , 0x00, 0x0a, 'd' , 0x0a, 0x00, + }; + register_header_check(0, pcb_header, sizeof(pcb_header), &header_check_pcb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pct.c b/subprojects/lib/src/file_pct.c new file mode 100644 index 0000000..4351fa6 --- /dev/null +++ b/subprojects/lib/src/file_pct.c @@ -0,0 +1,158 @@ +/* + + File: file_pct.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pct) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +#if !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_indd; +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pct(file_stat_t *file_stat); + +const file_hint_t file_hint_pct= { + .extension="pct", + .description="Macintosh Picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pct +}; + +/* We are searching for PICTv2 files + http://www.fileformat.info/format/macpict/ + SHORT Version operator (0x0011) + SHORT Version number (0x02ff) + SHORT Header opcode for Version 2 (0C00) + */ + +struct pct_file_entry { + uint16_t filesize; /* 0x00 */ + uint16_t XMin; /* 0x02 72 DPI */ + uint16_t YMin; /* 0x04 */ + uint16_t XMax; /* 0x06 */ + uint16_t YMax; /* 0x08 */ + uint16_t VersionOperator; /* 0x0A 0x0011 */ + uint16_t VersionNumber; /* 0x0C 0x02ff */ + uint16_t HeaderOpcode; /* 0x0E 0x0C00 */ + uint16_t Val; /* 0x10 0xFFEF or 0xFFEE */ + uint16_t Reserved; /* 0x12 0x0000 */ + uint32_t HDPI; /* 0x14 */ + uint32_t VDPI; /* 0x18 */ +#if 0 + uint16_t OYMax; // pbmplus format + uint16_t OYMin; + uint16_t OXMax; + uint16_t OXMin; +#else + uint16_t OXMin; + uint16_t OYMin; + uint16_t OXMax; + uint16_t OYMax; +#endif + uint32_t Reserved2; /* 0x24 */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_check == &file_check_pct; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns file_recovery->file_size; + @*/ +static void file_check_pct(file_recovery_t *file_recovery) +{ + uint64_t diff; + if(file_recovery->file_size<0x210 || + file_recovery->file_sizemin_filesize) + { + file_recovery->file_size=0; + return ; + } + /*@ assert file_recovery->file_size >= file_recovery->min_filesize; */ + diff=file_recovery->file_size-file_recovery->min_filesize; + file_recovery->file_size=file_recovery->min_filesize + (diff&0xffffffffffff0000); +} + +/*@ + @ requires buffer_size >= 0x200+sizeof(struct pct_file_entry); + @ requires separation: \separated(&file_hint_pct, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_pct(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct pct_file_entry *pct=(const struct pct_file_entry *)(&buffer[0x200]); + if(be16(pct->XMin) <= be16(pct->XMax) && + be16(pct->YMin) <= be16(pct->YMax) && + ((be16(pct->OXMin) <= be16(pct->OXMax) && + be16(pct->OYMin) <= be16(pct->OYMax)) || + (be16(pct->OYMax) <= be16(pct->OXMax) && /* pbmplus creates boggus files */ + be16(pct->OYMin) <= be16(pct->OXMin))) && + be16(pct->XMin)==0 && /* Reject some valid but uncommon files */ + be16(pct->YMin)==0 && + be16(pct->OYMin)==0 && + be16(pct->VersionOperator)==0x0011 && + be16(pct->VersionNumber)==0x02ff) + { + const unsigned int min_filesize=(buffer[0x200]<<8)+buffer[0x201]; +#if !defined(SINGLE_FORMAT) + if(file_recovery->file_stat != NULL && + file_recovery->file_stat->file_hint==&file_hint_indd) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pct.extension; + /* We only have the low 16bits of the filesystem */ + file_recovery_new->min_filesize=(min_filesize > 0x200+sizeof(struct pct_file_entry) ? min_filesize : 0x200+sizeof(struct pct_file_entry)); + file_recovery_new->file_check=&file_check_pct; +#ifdef DEBUG_PCT + log_info("X %u-%u, Y %u-%u\n", + be16(pct->XMin), be16(pct->XMax), + be16(pct->YMin), be16(pct->YMax)); + log_info("X %u-%u, Y %u-%u\n", + be16(pct->OXMin), be16(pct->OXMax), + be16(pct->OYMin), be16(pct->OYMax)); +#endif + return 1; + } + return 0; +} + +static void register_header_check_pct(file_stat_t *file_stat) +{ + static const unsigned char pct_header[6]= { 0x00, 0x11, 0x02, 0xff, 0x0c, 0x00}; + register_header_check(0x20a, pct_header,sizeof(pct_header), &header_check_pct, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pcx.c b/subprojects/lib/src/file_pcx.c new file mode 100644 index 0000000..543b17e --- /dev/null +++ b/subprojects/lib/src/file_pcx.c @@ -0,0 +1,121 @@ +/* + + File: file_pcx.c + + Copyright (C) 2006-2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pcx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_PCX +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pcx(file_stat_t *file_stat); + +const file_hint_t file_hint_pcx= { + .extension="pcx", + .description="PCX bitmap image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pcx +}; + +struct pcx_file_entry { + uint8_t Manufacturer; /* should always be 0Ah */ + uint8_t Version; + /* Version + * 0x00 PCX ver. 2.5 image data + * 0x02 PCX ver. 2.8 image data, with palette + * 0x03 PCX ver. 2.8 image data, without palette + * 0x04 PCX for Windows image data + * 0x05 PCX ver. 3.0 image data + */ + uint8_t Encoding; /* 0: uncompressed, 1: RLE compressed */ + uint8_t BitsPerPixel; + uint16_t XMin; /* image width = XMax-XMin */ + uint16_t YMin; /* image height = YMax-YMin */ + uint16_t XMax; + uint16_t YMax; + uint16_t VertDPI; + uint8_t Palette[48]; + uint8_t Reserved; + uint8_t ColorPlanes; + /* 4 -- 16 colors + * 3 -- 24 bit color (16.7 million colors) + */ + uint16_t BytesPerLine; + uint16_t PaletteType; + uint16_t HScrSize; /* only supported by */ + uint16_t VScrSize; /* PC Paintbrush IV or higher */ + uint8_t Filler[56]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct pcx_file_entry); + @ requires separation: \separated(&file_hint_pcx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pcx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct pcx_file_entry *pcx=(const struct pcx_file_entry *)buffer; + if(pcx->Manufacturer==0x0a && + (pcx->Version<=5 && pcx->Version!=1) && + pcx->Encoding <=1 && + (pcx->BitsPerPixel==1 || pcx->BitsPerPixel==4 || + pcx->BitsPerPixel==8 || pcx->BitsPerPixel==24) && + pcx->Reserved==0 && + le16(pcx->XMin) <= le16(pcx->XMax) && + le16(pcx->YMin) <= le16(pcx->YMax) && + pcx->BytesPerLine>0 && pcx->BytesPerLine%2==0 && + pcx->Filler[0]==0 && pcx->Filler[1]==0 && + pcx->Filler[54]==0 && pcx->Filler[55]==0) + { + reset_file_recovery(file_recovery_new); +#ifdef DEBUG_PCX + log_info("X %u-%u, Y %u-%u\n", + le16(pcx->XMin), le16(pcx->XMax), + le16(pcx->YMin), le16(pcx->YMax)); + log_info("ColorPlanes %u\n", pcx->ColorPlanes); + log_info("BytesPerLine %u - %u\n", pcx->BytesPerLine, (le16(pcx->XMax)-le16(pcx->XMin)+1)*pcx->BitsPerPixel/8); +#endif + file_recovery_new->extension=file_hint_pcx.extension; + return 1; + } + return 0; +} + +static void register_header_check_pcx(file_stat_t *file_stat) +{ + static const unsigned char pcx_header[1]= {0x0a}; + register_header_check(0, pcx_header,sizeof(pcx_header), &header_check_pcx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pdb.c b/subprojects/lib/src/file_pdb.c new file mode 100644 index 0000000..10da002 --- /dev/null +++ b/subprojects/lib/src/file_pdb.c @@ -0,0 +1,125 @@ +/* + + File: file_pdb.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pdb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pdb(file_stat_t *file_stat); + +const file_hint_t file_hint_pdb= { + .extension="pdb", + .description="Protein Data Bank data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pdb +}; + +/*@ + @ requires file_recovery->data_check==&data_check_pdb; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_pdb(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + unsigned int i; + /*@ loop assigns i; */ + for(i=buffer_size/2; icalculated_file_size+=i; + return DC_STOP; + } + file_recovery->calculated_file_size+=buffer_size/2; + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_check == &file_check_pdb; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_pdb(file_recovery_t *file_recovery) +{ + char buffer[512]; + if(my_fseek(file_recovery->handle, 0, SEEK_SET) < 0 || + fread(&buffer, 1, sizeof(buffer), file_recovery->handle) < 82) + return ; +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + if(buffer[80]=='\r' && buffer[81]=='\n') + file_recovery->file_size=file_recovery->calculated_file_size/82*82; + else if(buffer[80]=='\n') + file_recovery->file_size=file_recovery->calculated_file_size/81*81; + else + file_recovery->file_size=0; +} + +/*@ + @ requires buffer_size >= 70; + @ requires separation: \separated(&file_hint_pdb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pdb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* Check date */ + if(buffer[0x32] < '0' || buffer[0x32] > '9' || buffer[0x33] < '0' || buffer[0x33] > '9') + return 0; + if(buffer[0x34]!='-') + return 0; + if(buffer[0x35] < 'A' || buffer[0x35] > 'Z' || buffer[0x36] < 'A' || buffer[0x36] > 'Z' || buffer[0x37] < 'A' || buffer[0x37] > 'Z') + return 0; + if(buffer[0x38]!='-') + return 0; + if(buffer[0x39] < '0' || buffer[0x39] > '9' || buffer[0x3a] < '0' || buffer[0x3a] > '9') + return 0; + /* Check space */ + if(buffer[59]!=' ' || buffer[60]!=' ' || buffer[61]!=' ' || buffer[66]!=' ' || buffer[67]!=' ' || buffer[68]!=' ' || buffer[69]!=' ') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pdb.extension; + file_recovery_new->data_check=&data_check_pdb; + file_recovery_new->file_check=&file_check_pdb; + file_recovery_new->min_filesize=80; + return 1; +} + +static void register_header_check_pdb(file_stat_t *file_stat) +{ + register_header_check(0, "HEADER ", 10, &header_check_pdb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pdf.c b/subprojects/lib/src/file_pdf.c new file mode 100644 index 0000000..9375d7a --- /dev/null +++ b/subprojects/lib/src/file_pdf.c @@ -0,0 +1,464 @@ +/* + + File: file_pdf.c + + Copyright (C) 1998-2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pdf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include /* free */ +#endif +#include +#include "types.h" +#include "filegen.h" +#include "memmem.h" +#include "common.h" + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_pdf(file_stat_t *file_stat); + +const file_hint_t file_hint_pdf= { + .extension="pdf", + .description="Portable Document Format, Adobe Illustrator", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pdf +}; + +/*@ + @ assigns \nothing; + @*/ +static int is_hexa(const int c) +{ + return ((c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f')); +} + +/*@ + @ assigns \nothing; + @ ensures 0 <= \result <= 15; + @*/ +static unsigned int hex(const int c) +{ + if(c>='0' && c<='9') + return c-'0'; + if(c>='A' && c<='F') + return c-'A'+10; + if(c>='a' && c<='f') + return c-'a'+10; + return 0; +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_pdf; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_pdf(file_recovery_t *file_recovery) +{ + char title[512]; + const unsigned char pattern[6]={ '/', 'T', 'i', 't', 'l', 'e' }; + off_t offset; + uint64_t tmp; + FILE *handle; + unsigned char*buffer; + unsigned int i; + unsigned int l; + size_t bsize; + const unsigned char utf16[3]= { 0xfe, 0xff, 0x00}; + if((handle=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(my_fseek(handle, 0, SEEK_END)<0) + { + fclose(handle); + return; + } +#ifdef HAVE_FTELLO + offset=ftello(handle); +#else + offset=ftell(handle); +#endif + if(offset <= 0) + { + fclose(handle); + return; + } + tmp=file_rsearch(handle, offset, pattern, sizeof(pattern)); + if(tmp==0 || tmp > PHOTOREC_MAX_FILE_SIZE) + { + fclose(handle); + return; + } + offset=tmp+sizeof(pattern); + if(my_fseek(handle, offset, SEEK_SET)<0) + { + fclose(handle); + return ; + } + buffer=(unsigned char*)MALLOC(512); + if((bsize=fread(buffer, 1, 512, handle)) <= 2) + { + free(buffer); + fclose(handle); + return ; + } + /*@ assert 2 < bsize; */ +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, 512); +#endif + /*@ assert \initialized(buffer + (0 .. 512-1)); */ + fclose(handle); + /* Skip spaces after /Title */ + /*@ + @ loop invariant 0 <= i <= bsize; + @ loop assigns i; + @ */ + for(i=0; i= bsize) + { + /* Too much spaces */ + free(buffer); + return ; + } + /*@ assert i + 2 < bsize; */ + if(buffer[i]=='<') + { + unsigned int j; + unsigned int s; + /* hexa to ascii */ + buffer[i]='('; + /*@ assert \valid(buffer + (0 .. bsize -1)); */ + /*@ + @ loop invariant s <= bsize; + @ loop invariant j <= s; + @ loop invariant j < bsize; + @ loop assigns s, j, buffer[0 .. 512-1]; + @ */ + for(s=i+1, j=i+1; + s+14 && + (memcmp(&title[l-4], ".doc", 4)==0 || + memcmp(&title[l-4], ".xls", 4)==0)) + l-=4; + else if(l>5 && + (memcmp(&title[l-5], ".docx", 5)==0 || + memcmp(&title[l-5], ".xlsx", 5)==0)) + l-=5; + file_rename(file_recovery, title, l, 0, NULL, 1); + free(buffer); +} + +/*@ + @ requires \valid(file_recovery); + @ requires valid_file_recovery(file_recovery); + @ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source); + @*/ +static void file_date_pdf(file_recovery_t *file_recovery) +{ + const unsigned char pattern[14]={'x', 'a', 'p', ':', 'C', 'r', 'e', 'a', 't', 'e', 'D', 'a', 't', 'e'}; + uint64_t offset=0; + unsigned int j=0; + unsigned char*buffer; + if(file_recovery->file_size > PHOTOREC_MAX_FILE_SIZE) + return ; + /*@ assert file_recovery->file_size <= PHOTOREC_MAX_FILE_SIZE; */ + buffer=(unsigned char*)MALLOC(4096); + if(my_fseek(file_recovery->handle, 0, SEEK_SET)<0) + { + free(buffer); + return ; + } + while(offset < file_recovery->file_size) + { + int i; + const int bsize=fread(buffer, 1, 4096, file_recovery->handle); + if(bsize<=0) + { + free(buffer); + return ; + } + /*@ + @ loop invariant \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, buffer + (..)); + @ loop assigns i, j, *file_recovery->handle, file_recovery->time, buffer[0..21]; + @ loop assigns errno; + @*/ + for(i=0; ihandle, offset+i+1, SEEK_SET)>=0 && + fread(buffer, 1, 22, file_recovery->handle) == 22) + { + /*@ assert \initialized( buffer+ (0 .. 22-1)); */ + if(buffer[0]=='=' && (buffer[1]=='\'' || buffer[1]=='"')) + { + file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[2]); + } + else if(buffer[0]=='>') + { + file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[1]); + } + } + free(buffer); + return ; + } + } + else + j=0; + } + offset+=bsize; + } + free(buffer); +} + + +#define PDF_READ_SIZE 20 + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +static void file_check_pdf_and_size(file_recovery_t *file_recovery) +{ + unsigned char buffer[PDF_READ_SIZE + 3]; + int i; + int taille; + if( file_recovery->file_size < file_recovery->calculated_file_size || + file_recovery->calculated_file_size < PDF_READ_SIZE) + { + file_recovery->file_size=0; + return; + } + /*@ assert file_recovery->calculated_file_size >= PDF_READ_SIZE; */ + file_recovery->file_size=file_recovery->calculated_file_size; + /*@ assert file_recovery->file_size >= PDF_READ_SIZE; */ + if(my_fseek(file_recovery->handle,file_recovery->file_size-PDF_READ_SIZE,SEEK_SET)<0) + { + file_recovery->file_size=0; + return ; + } + taille=fread(buffer, 1, PDF_READ_SIZE, file_recovery->handle); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&buffer, sizeof(buffer)); +#endif + for(i=taille-4;i>=0;i--) + { + if(buffer[i]=='%' && buffer[i+1]=='E' && buffer[i+2]=='O' && buffer[i+3]=='F') + { + file_date_pdf(file_recovery); + return ; + } + } + file_recovery->file_size=0; +} + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +static void file_check_pdf(file_recovery_t *file_recovery) +{ + const unsigned char pdf_footer[4]= { '%', 'E', 'O', 'F'}; + file_search_footer(file_recovery, pdf_footer, sizeof(pdf_footer), 0); + file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR); + file_date_pdf(file_recovery); +} + +/*@ + @ requires \valid_read(buffer+(0..512-1)); + @ assigns \nothing; + @*/ +static uint64_t read_pdf_file_aux(const unsigned char *buffer, unsigned int i) +{ + uint64_t file_size=0; + /*@ loop assigns i; */ + while(i < 512 && + (buffer[i] ==' ' || buffer[i]=='\t' || buffer[i]=='\n' || buffer[i]=='\r')) + i++; + /*@ + @ loop invariant file_size <= PHOTOREC_MAX_FILE_SIZE; + @ loop assigns i, file_size; + @ */ + for(;i<512 && buffer[i]>='0' && buffer[i]<='9'; i++) + { + file_size*=10; + file_size+=buffer[i]-'0'; + if(file_size > PHOTOREC_MAX_FILE_SIZE) + { + return PHOTOREC_MAX_FILE_SIZE + 1; + } + /*@ assert file_size <= PHOTOREC_MAX_FILE_SIZE; */ + } + return file_size; +} + +/*@ + @ requires \valid_read(buffer+(0..512-1)); + @ assigns \nothing; + @*/ +static uint64_t read_pdf_file(const unsigned char *buffer) +{ + const unsigned char sig_linearized[10]={'L','i','n','e','a','r','i','z','e','d'}; + const char *src; + unsigned int i; + const char *sbuffer=(const char *)buffer; + src=(const char *)td_memmem(sbuffer, 512, sig_linearized, sizeof(sig_linearized)); + if(src == NULL) + return 0; + i = src - sbuffer; + i+=sizeof(sig_linearized); + if( i >= 512 -1) + return 0; + /*@ assert i < 512-1; */ + /*@ + @ loop assigns i; + @ loop variant 512 - 1 - i; + @ */ + for(; i < 512-1 && buffer[i]!='>'; i++) + { + if(buffer[i]=='/' && buffer[i+1]=='L') + return read_pdf_file_aux(buffer, i+2); + } + return 0; +} + +/*@ + @ requires buffer_size >= 512; + @ requires separation: \separated(&file_hint_pdf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pdf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t file_size; + if(!isprint(buffer[6])) + return 0; + file_size=read_pdf_file(buffer); + if(file_size > PHOTOREC_MAX_FILE_SIZE) + return 0; + reset_file_recovery(file_recovery_new); + if(td_memmem(buffer, buffer_size, "<extension="ai"; + else + { + file_recovery_new->extension=file_hint_pdf.extension; + file_recovery_new->file_rename=&file_rename_pdf; + } + if(file_size == 0) + { + file_recovery_new->file_check=&file_check_pdf; + return 1; + } + file_recovery_new->calculated_file_size=file_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_pdf_and_size; + return 1; +} + +static void register_header_check_pdf(file_stat_t *file_stat) +{ + static const unsigned char pdf_header[] = { '%','P','D','F','-','1'}; + register_header_check(0, pdf_header,sizeof(pdf_header), &header_check_pdf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pds.c b/subprojects/lib/src/file_pds.c new file mode 100644 index 0000000..a069f62 --- /dev/null +++ b/subprojects/lib/src/file_pds.c @@ -0,0 +1,69 @@ +/* + + File: file_pds.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pds) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pds(file_stat_t *file_stat); + +const file_hint_t file_hint_pds= { + .extension="pds", + .description="Reson - Sonar Data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pds +}; + +/*@ + @ requires separation: \separated(&file_hint_pds, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pds(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pds.extension; + return 1; +} + +static void register_header_check_pds(file_stat_t *file_stat) +{ + static const unsigned char pds_header[25]= { + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x04, 0x5b, 'H' , 'E' , 'A' , 'D' , 'E' , 'R' , + 0x5d + }; + register_header_check(0, pds_header, sizeof(pds_header), &header_check_pds, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pf.c b/subprojects/lib/src/file_pf.c new file mode 100644 index 0000000..b037ee2 --- /dev/null +++ b/subprojects/lib/src/file_pf.c @@ -0,0 +1,212 @@ +/* + + File: file_pf.c + + Copyright (C) 2016 Christophe GRENIER + and Ralf Almon usd AG 2016 + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pf(file_stat_t *file_stat); + +const file_hint_t file_hint_pf= { + .extension="pf", + .description="Windows prefetch file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pf +}; + +struct pf_header +{ + uint32_t version; + uint32_t magic; + uint32_t unknown; + uint32_t size; + char name[60]; + uint32_t hash; + uint32_t unknown2; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename==&file_rename_pf; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_pf(file_recovery_t *file_recovery) +{ + FILE *file; + char buffer[sizeof(struct pf_header)]; + const struct pf_header *hdr=(const struct pf_header*)&buffer; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + { + /*@ assert valid_read_string((char*)&file_recovery->filename); */ + return; + } + if(fread(&buffer, sizeof(buffer), 1, file) != 1) + { + fclose(file); + /*@ assert valid_read_string((char*)&file_recovery->filename); */ + return ; + } + fclose(file); + /*@ assert valid_read_string((char*)&file_recovery->filename); */ + file_rename_unicode(file_recovery, &hdr->name, sizeof(hdr->name), 0, "pf", 0); + /*@ assert valid_read_string((char*)&file_recovery->filename); */ +} + +/*@ + @ requires buffer_size >= sizeof(struct pf_header); + @ requires separation: \separated(&file_hint_pf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_pf.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= sizeof(struct pf_header)); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check==&data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check==&file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename==&file_rename_pf); + @ assigns *file_recovery_new; + @*/ +static int header_check_pf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct pf_header *pf=(const struct pf_header *)buffer; + const unsigned int size=le32(pf->size); + if(size < sizeof(struct pf_header)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pf.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->file_rename=&file_rename_pf; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_pf(file_stat_t *file_stat) +{ + static const unsigned char pf_header[7] = {0x00, 0x00, 0x00, 'S', 'C', 'C', 'A'}; + register_header_check(1, pf_header,sizeof(pf_header), &header_check_pf, file_stat); +} +#endif + +#if defined(MAIN_pf) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.pf"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_pf; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_pf(&file_stats); + if(header_check_pf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.extension == file_hint_pf.extension; */ + /*@ assert file_recovery_new.file_rename==&file_rename_pf; */ + /*@ assert file_recovery_new.file_check == &file_check_size; */ + /*@ assert file_recovery_new.data_check == &data_check_size; */ + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL && + file_recovery_new.data_check!=NULL) + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_size == 0; */; + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + { + file_recovery_t file_recovery_new2; + /* Test when another file of the same is detected in the next block */ + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ + #if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + header_check_pf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + file_recovery_new.handle=fopen(fn, "rb"); + /*@ assert file_recovery_new.file_check == &file_check_size; */ + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + /*@ assert file_recovery_new.file_rename==&file_rename_pf; */ + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_rename_pf(&file_recovery_new); + return 0; +} +#endif diff --git a/subprojects/lib/src/file_pfx.c b/subprojects/lib/src/file_pfx.c new file mode 100644 index 0000000..c2054df --- /dev/null +++ b/subprojects/lib/src/file_pfx.c @@ -0,0 +1,102 @@ +/* + + File: file_pfx.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pfx) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pfx(file_stat_t *file_stat); + +const file_hint_t file_hint_pfx= { + .extension="pfx", + .description="PKCS#12 keys", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pfx +}; + +/* A pfx file are PKCS#12 data encoded following ASN.1 DER + * + * PKCS #12: Personal Information Exchange Syntax Standard + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf + * + * For the recovery PhotoRec assumes + * - the file is smaller than 65535+4 bytes + * - PKCS #7 ContentInfo contentType=data + * + * 0:d=0 hl=4 l=XXXX cons: SEQUENCE + * 30 82 XX XX XXXX + 4 = filesize + * 4:d=1 hl=2 l= 1 prim: INTEGER + * 02 01 03 version 3 + * 7:d=1 hl=4 l=XXXX cons: SEQUENCE + * 30 82 XX XX + * 11:d=2 hl=2 l= 9 prim: OBJECT :pkcs7-data + * 06 09 2a 86 48 86 f7 0d 01 07 01 + * A PKCS #7 ContentInfo, whose contentType is signedData in + * public-key integrity mode and data in password integrity mode. + * Here, contentType=data + */ + +/*@ + @ requires buffer_size >= 9; + @ requires separation: \separated(&file_hint_pfx, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pfx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0]==0x30 && buffer[1]==0x82 && + buffer[4]==0x02 && buffer[5]==0x01 && buffer[6]==0x03 && + buffer[7]==0x30 && buffer[8]==0x82) + { + const uint64_t size=((buffer[2])<<8) + buffer[3] + 4; + if(size < 11 + 11) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pfx.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_pfx(file_stat_t *file_stat) +{ + static const unsigned char pfx_header[11]= { + 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 + }; + register_header_check(11, pfx_header,sizeof(pfx_header), &header_check_pfx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pgdump.c b/subprojects/lib/src/file_pgdump.c new file mode 100644 index 0000000..162c8cf --- /dev/null +++ b/subprojects/lib/src/file_pgdump.c @@ -0,0 +1,119 @@ +/* + + File: file_pgdump.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pgdump) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/* Information from https://doxygen.postgresql.org/pg__backup__archiver_8h_source.html */ +#define MAKE_ARCHIVE_VERSION(major, minor, rev) (((major) * 256 + (minor)) * 256 + (rev)) +/* Historical version numbers (checked in code) */ + #define K_VERS_1_0 MAKE_ARCHIVE_VERSION(1, 0, 0) + #define K_VERS_1_2 MAKE_ARCHIVE_VERSION(1, 2, 0) /* Allow No ZLIB */ + #define K_VERS_1_3 MAKE_ARCHIVE_VERSION(1, 3, 0) /* BLOBs */ + #define K_VERS_1_4 MAKE_ARCHIVE_VERSION(1, 4, 0) /* Date & name in header */ + #define K_VERS_1_5 MAKE_ARCHIVE_VERSION(1, 5, 0) /* Handle dependencies */ + #define K_VERS_1_6 MAKE_ARCHIVE_VERSION(1, 6, 0) /* Schema field in TOCs */ + #define K_VERS_1_7 MAKE_ARCHIVE_VERSION(1, 7, 0) /* File Offset size in + * header */ + #define K_VERS_1_8 MAKE_ARCHIVE_VERSION(1, 8, 0) /* change interpretation + * of ID numbers and + * dependencies */ + #define K_VERS_1_9 MAKE_ARCHIVE_VERSION(1, 9, 0) /* add default_with_oids + * tracking */ + #define K_VERS_1_10 MAKE_ARCHIVE_VERSION(1, 10, 0) /* add tablespace */ + #define K_VERS_1_11 MAKE_ARCHIVE_VERSION(1, 11, 0) /* add toc section + * indicator */ + #define K_VERS_1_12 MAKE_ARCHIVE_VERSION(1, 12, 0) /* add separate BLOB + * entries */ + #define K_VERS_1_13 MAKE_ARCHIVE_VERSION(1, 13, 0) /* change search_path + * behavior */ + +struct pgdmp_hdr +{ + char magic[5]; + uint8_t vmaj; + uint8_t vmin; + uint8_t vrev; + uint8_t intSize; + uint8_t offSize; /* 1.7+ */ + uint8_t format; + /* 1.2 uint8_t 1.4+ uint32_t assuming intSize == 4*/ + uint32_t compression; + /* 1.4 uint32_t assuming intSize == 4 */ + uint32_t tm_sec; + uint32_t tm_min; + uint32_t tm_hour; + uint32_t tm_mday; + uint32_t tm_mon; + uint32_t tm_year; + uint32_t tm_isdst; + /* connection */ + /* 1.10 */ + /* remoteVersionStr */ + /* PG_VERSION */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pgdump(file_stat_t *file_stat); + +const file_hint_t file_hint_pgdump= { + .extension="dump", + .description="Postgresql Binary Dump", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pgdump +}; + +/*@ + @ requires buffer_size >= sizeof(struct pgdmp_hdr); + @ requires separation: \separated(&file_hint_pgdump, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pgdump(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct pgdmp_hdr *hdr=(const struct pgdmp_hdr *)buffer; + if(hdr->intSize == 0 || hdr->intSize > 32) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pgdump.extension; + return 1; +} + +static void register_header_check_pgdump(file_stat_t *file_stat) +{ + register_header_check(0, "PGDMP", 5, &header_check_pgdump, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_plist.c b/subprojects/lib/src/file_plist.c new file mode 100644 index 0000000..56970fe --- /dev/null +++ b/subprojects/lib/src/file_plist.c @@ -0,0 +1,78 @@ +/* + + File: file_plist.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plist) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +#if !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_qbb; +extern const file_hint_t file_hint_sqlite; +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_plist(file_stat_t *file_stat); + +const file_hint_t file_hint_plist= { + .extension="plist", + .description="Apple binary property list", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_plist +}; + +/*@ + @ requires separation: \separated(&file_hint_plist, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_plist(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ +#if !defined(SINGLE_FORMAT) + if(file_recovery->file_stat!=NULL) + { + if( file_recovery->file_stat->file_hint==&file_hint_qbb || + file_recovery->file_stat->file_hint==&file_hint_sqlite) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_plist.extension; + return 1; +} + +static void register_header_check_plist(file_stat_t *file_stat) +{ + register_header_check(0, "bplist00", 8, &header_check_plist, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_plr.c b/subprojects/lib/src/file_plr.c new file mode 100644 index 0000000..6198b20 --- /dev/null +++ b/subprojects/lib/src/file_plr.c @@ -0,0 +1,70 @@ +/* + + File: file_plr.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plr) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_plr(file_stat_t *file_stat); + +const file_hint_t file_hint_plr= { + .extension="plr", + .description="Terraria Player File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_plr +}; + +/*@ + @ requires separation: \separated(&file_hint_plr, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_plr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_plr.extension; + file_recovery_new->calculated_file_size=1856; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_plr(file_stat_t *file_stat) +{ + static const unsigned char plr_header[16]= { + 0x0f, 'w' , 'g' , 0xfe, 0xb1, 'J' , 0xb2, 0xef, + 0xfc, 'j' , 0x9b, 'K' , 'x' , 0x5b, 0xf4, 'V' + }; + register_header_check(0, plr_header, sizeof(plr_header), &header_check_plr, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_plt.c b/subprojects/lib/src/file_plt.c new file mode 100644 index 0000000..8fb5bd5 --- /dev/null +++ b/subprojects/lib/src/file_plt.c @@ -0,0 +1,71 @@ +/* + + File: file_plt.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_plt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_plt(file_stat_t *file_stat); + +const file_hint_t file_hint_plt= { + .extension="plt", + .description="Gerber Graphix Advantage", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_plt +}; + +/*@ + @ requires separation: \separated(&file_hint_plt, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_plt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_plt.extension; + return 1; +} + +static void register_header_check_plt(file_stat_t *file_stat) +{ + static const unsigned char plt_header[44]= { + 'G', 'e', 'r', 'b', 'e', 'r', ' ', 'S', + 'c', 'i', 'e', 'n', 't', 'i', 'f', 'i', + 'c', ' ', 'P', 'r', 'o', 'd', 'u', 'c', + 't', 's', ' ', 'G', 'R', 'A', 'P', 'H', + 'I', 'X', ' ', 'A', 'D', 'V', 'A', 'N', + 'T', 'A', 'G', 'E', + }; + register_header_check(2, plt_header, sizeof(plt_header), &header_check_plt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_png.c b/subprojects/lib/src/file_png.c new file mode 100644 index 0000000..b87d80d --- /dev/null +++ b/subprojects/lib/src/file_png.c @@ -0,0 +1,358 @@ +/* + + File: file_png.c + + Copyright (C) 1998-2009 Christophe GRENIER + Thanks to Holger Klemm for JNG (JPEG Network Graphics) and + MNG (Multiple-Image Network Graphics) support (2006) + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +/* + MNG (Multiple-image Network Graphics) Format + http://www.libpng.org/pub/mng/spec/ +*/ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_png) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +extern const file_hint_t file_hint_doc; + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_png(file_stat_t *file_stat); + +const file_hint_t file_hint_png= { + .extension="png", + .description="Portable/JPEG/Multiple-Image Network Graphics", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_png +}; + +struct png_chunk +{ + uint32_t length; + uint32_t type; +#if 0 + char data[0]; +#endif + /* data is followed by uint32_t crc; */ +} __attribute__ ((gcc_struct, __packed__)); + +struct png_ihdr +{ + uint32_t width; + uint32_t height; + uint8_t bit_depth; + uint8_t color_type; + uint8_t compression; + uint8_t filter; + uint8_t interlace; +} __attribute__ ((gcc_struct, __packed__)); + +/* png_check_ihdr: return 1 if valid */ +/*@ + @ requires \valid_read(ihdr); + @ requires \initialized(ihdr); + @ ensures \result == 0 || \result == 1; + @ assigns \nothing; + @ */ +static int png_check_ihdr(const struct png_ihdr *ihdr) +{ + if(be32(ihdr->width)==0 || be32(ihdr->height)==0) + return 0; + switch(ihdr->color_type) + { + case 0: /* Greyscale */ + if(ihdr->bit_depth!=1 && ihdr->bit_depth!=2 && ihdr->bit_depth!=4 && ihdr->bit_depth!=8 && ihdr->bit_depth!=16) + return 0; + break; + case 3: /* Indexed-colour*/ + if(ihdr->bit_depth!=1 && ihdr->bit_depth!=2 && ihdr->bit_depth!=4 && ihdr->bit_depth!=8) + return 0; + break; + case 2: /* Truecolour */ + case 4: /* Greyscale with alpha */ + case 6: /* Truecolour with alpha */ + if(ihdr->bit_depth!=8 && ihdr->bit_depth!=16) + return 0; + break; + default: + return 0; + } + return 1; +} + +/*@ + @ requires fr->file_check == &file_check_png; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, fr->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_png(file_recovery_t *fr) +{ + if(fr->file_sizecalculated_file_size) + { + fr->file_size=0; + return ; + } + fr->file_size=8; + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant fr->file_size < 0x8000000000000000; + @ loop assigns *fr->handle, errno, fr->file_size; + @ loop assigns Frama_C_entropy_source; + @*/ + while(1) + { + char buffer[8]; + const struct png_chunk *chunk=(const struct png_chunk *)&buffer; + uint32_t length; + if(my_fseek(fr->handle, fr->file_size, SEEK_SET) < 0 || + fread(&buffer, sizeof(buffer), 1, fr->handle) != 1) + { + fr->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif + length = be32(chunk->length); + fr->file_size+=(uint64_t)12 + length; + if(fr->file_size >= 0x8000000000000000) + return ; + if(memcmp(&buffer[4], "IEND", 4)==0) + return ; + if(memcmp(&buffer[4], "IHDR", 4) == 0) + { + char buf_ihdr[sizeof(struct png_ihdr)]; + const struct png_ihdr *ihdr=(const struct png_ihdr *)&buf_ihdr; + if(fread(&buf_ihdr, sizeof(buf_ihdr), 1, fr->handle) != 1) + { + fr->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(&buf_ihdr, sizeof(buf_ihdr)); +#endif + if(png_check_ihdr(ihdr)==0) + { + fr->file_size=0; + return ; + } + } + } +} + +/*@ + @ requires file_recovery->data_check==&data_check_mng; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->offset_ok, file_recovery->offset_error; + @*/ +static data_check_t data_check_mng(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + static const unsigned char mng_footer[4]= {'M','E','N','D'}; + /*@ + @ loop assigns file_recovery->calculated_file_size, file_recovery->offset_ok; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 8 ; */ + const struct png_chunk *chunk=(const struct png_chunk *)&buffer[i]; + const uint32_t length=be32(chunk->length); + if(memcmp(&buffer[i+4], mng_footer, sizeof(mng_footer))==0) + { + file_recovery->calculated_file_size+=(uint64_t)12 + length; + return DC_STOP; + } + if( !((isupper(buffer[i+4]) || islower(buffer[i+4])) && + (isupper(buffer[i+5]) || islower(buffer[i+5])) && + (isupper(buffer[i+6]) || islower(buffer[i+6])) && + (isupper(buffer[i+7]) || islower(buffer[i+7])))) + { + file_recovery->offset_error=file_recovery->calculated_file_size+7; + return DC_ERROR; + } + file_recovery->offset_ok=file_recovery->calculated_file_size+7; + file_recovery->calculated_file_size+=(uint64_t)12 + length; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&data_check_png; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->offset_ok, file_recovery->offset_error; + @*/ +static data_check_t data_check_png(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size, file_recovery->offset_ok; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 8 ; */ + const struct png_chunk *chunk=(const struct png_chunk *)&buffer[i]; + const uint32_t length=be32(chunk->length); + if(memcmp(&buffer[i+4], "IEND", 4)==0) + { + file_recovery->calculated_file_size+=(uint64_t)12 + length; + return DC_STOP; + } +// PNG chunk code +// IDAT IHDR PLTE bKGD cHRM fRAc gAMA gIFg gIFt gIFx hIST iCCP +// iTXt oFFs pCAL pHYs sBIT sCAL sPLT sRGB sTER tEXt tRNS zTXt + if( !((isupper(buffer[i+4]) || islower(buffer[i+4])) && + (isupper(buffer[i+5]) || islower(buffer[i+5])) && + (isupper(buffer[i+6]) || islower(buffer[i+6])) && + (isupper(buffer[i+7]) || islower(buffer[i+7])))) + { + file_recovery->offset_error=file_recovery->calculated_file_size+7; + return DC_ERROR; + } + file_recovery->offset_ok=file_recovery->calculated_file_size+7; + file_recovery->calculated_file_size+=(uint64_t)12 + length; + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_png, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_jng(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if( !((isupper(buffer[8+4]) || islower(buffer[8+4])) && + (isupper(buffer[8+5]) || islower(buffer[8+5])) && + (isupper(buffer[8+6]) || islower(buffer[8+6])) && + (isupper(buffer[8+7]) || islower(buffer[8+7])))) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="jng"; + file_recovery_new->min_filesize=16; + if(file_recovery_new->blocksize < 8) + { + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + file_recovery_new->calculated_file_size=8; + file_recovery_new->data_check=&data_check_png; + file_recovery_new->file_check=&file_check_size; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +/*@ + @ requires buffer_size >= 16; + @ requires separation: \separated(&file_hint_png, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_mng(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if( !((isupper(buffer[8+4]) || islower(buffer[8+4])) && + (isupper(buffer[8+5]) || islower(buffer[8+5])) && + (isupper(buffer[8+6]) || islower(buffer[8+6])) && + (isupper(buffer[8+7]) || islower(buffer[8+7])))) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="mng"; + file_recovery_new->min_filesize=16; + if(file_recovery_new->blocksize < 8) + { + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + file_recovery_new->calculated_file_size=8; + file_recovery_new->data_check=&data_check_mng; + file_recovery_new->file_check=&file_check_size; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +/*@ + @ requires buffer_size >= 16 + sizeof(struct png_ihdr); + @ requires separation: \separated(&file_hint_png, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_png(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if( !((isupper(buffer[8+4]) || islower(buffer[8+4])) && + (isupper(buffer[8+5]) || islower(buffer[8+5])) && + (isupper(buffer[8+6]) || islower(buffer[8+6])) && + (isupper(buffer[8+7]) || islower(buffer[8+7])))) + return 0; + if(memcmp(&buffer[8+4], "IHDR", 4) == 0 && + png_check_ihdr((const struct png_ihdr *)&buffer[16])==0) + return 0; +#if !defined(SINGLE_FORMAT) + /* SolidWorks files contain a png */ + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_doc) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_png.extension; + file_recovery_new->min_filesize=16; + if(file_recovery_new->blocksize < 8) + { + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + file_recovery_new->calculated_file_size=8; + file_recovery_new->data_check=&data_check_png; + file_recovery_new->file_check=&file_check_png; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +static void register_header_check_png(file_stat_t *file_stat) +{ + static const unsigned char jng_header[8]= { 0x8b, 'J', 'N','G', 0x0d, 0x0a, 0x1a, 0x0a}; + static const unsigned char mng_header[8]= { 0x8a, 'M', 'N','G', 0x0d, 0x0a, 0x1a, 0x0a}; + static const unsigned char png_header[8]= { 0x89, 'P', 'N','G', 0x0d, 0x0a, 0x1a, 0x0a}; + register_header_check(0, jng_header, sizeof(jng_header), &header_check_jng, file_stat); + register_header_check(0, mng_header, sizeof(mng_header), &header_check_mng, file_stat); + register_header_check(0, png_header, sizeof(png_header), &header_check_png, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pnm.c b/subprojects/lib/src/file_pnm.c new file mode 100644 index 0000000..28884ce --- /dev/null +++ b/subprojects/lib/src/file_pnm.c @@ -0,0 +1,105 @@ +/* + + File: file_pnm.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pnm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pnm(file_stat_t *file_stat); + +const file_hint_t file_hint_pnm = { + .extension = "pnm", + .description = "Netpbm (PBM/PGM/PPM)", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_pnm +}; + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_pnm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pbm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[5]) || !isprint(buffer[6]) || !isprint(buffer[7])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = "pbm"; + return 1; +} + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_pnm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pgm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[5]) || !isprint(buffer[6]) || !isprint(buffer[7])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = "pgm"; + return 1; +} + +/*@ + @ requires buffer_size >= 8; + @ requires separation: \separated(&file_hint_pnm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ppm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[5]) || !isprint(buffer[6]) || !isprint(buffer[7])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = "ppm"; + return 1; +} + +static void register_header_check_pnm(file_stat_t *file_stat) +{ + /* See http://en.wikipedia.org/wiki/Netpbm_format */ + register_header_check(0, "P1\n# ", 5, &header_check_pbm, file_stat); + register_header_check(0, "P2\n# ", 5, &header_check_pgm, file_stat); + register_header_check(0, "P3\n# ", 5, &header_check_ppm, file_stat); + register_header_check(0, "P4\n# ", 5, &header_check_pbm, file_stat); + register_header_check(0, "P5\n# ", 5, &header_check_pgm, file_stat); + register_header_check(0, "P6\n# ", 5, &header_check_ppm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_prc.c b/subprojects/lib/src/file_prc.c new file mode 100644 index 0000000..a9e09e9 --- /dev/null +++ b/subprojects/lib/src/file_prc.c @@ -0,0 +1,86 @@ +/* + + File: file_prc.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prc) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_prc(file_stat_t *file_stat); + +const file_hint_t file_hint_prc = { + .extension = "prc", + .description = "PalmOS application", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_prc +}; + +struct DatabaseHdrType_s +{ + unsigned char name[32]; + uint16_t attributes; /* 0x20 */ + uint32_t creationDate; /* 0x22 */ + uint32_t modificationDate; /* 0x26 */ + uint32_t lastBackupDate; /* 0x2a */ + uint32_t modificationNumber; /* 0x2e */ + unsigned char appInfoID[5]; /* 0x32 */ + unsigned char sortInfoID[5]; + uint32_t type; /* 0x3c */ + uint32_t creator; /* 0x40 */ + uint32_t uniqueIDSeed; /* 0x44 */ + /* RecordListType recordList; */ +} __attribute__((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct DatabaseHdrType_s); + @ requires separation: \separated(&file_hint_prc, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_prc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct DatabaseHdrType_s *prc = (const struct DatabaseHdrType_s *)buffer; + if(be32(prc->uniqueIDSeed) != 0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_prc.extension; + file_recovery_new->time = be32(prc->modificationDate); + return 1; +} + +static void register_header_check_prc(file_stat_t *file_stat) +{ + static const unsigned char prc_header[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'a', 'p', 'p', 'l' }; + register_header_check(0x30, prc_header, sizeof(prc_header), &header_check_prc, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_prd.c b/subprojects/lib/src/file_prd.c new file mode 100644 index 0000000..e898ea7 --- /dev/null +++ b/subprojects/lib/src/file_prd.c @@ -0,0 +1,69 @@ +/* + + File: file_prd.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_prd(file_stat_t *file_stat); + +const file_hint_t file_hint_prd = { + .extension = "prd", + .description = "Paessler PRTG", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_prd +}; + +/*@ + @ requires buffer_size >= 0x18; + @ requires separation: \separated(&file_hint_prd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_prd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0x0d] != 0xdb || buffer[0x0e] != 0xe4 || buffer[0x0f] != 0x40 || buffer[0x15] != 0xdb || buffer[0x16] != 0xe4 || buffer[0x17] != 0x40) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_prd.extension; + return 1; +} + +static void register_header_check_prd(file_stat_t *file_stat) +{ + static const unsigned char prd_header[8] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + register_header_check(0, prd_header, sizeof(prd_header), &header_check_prd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_prt.c b/subprojects/lib/src/file_prt.c new file mode 100644 index 0000000..bf43f4d --- /dev/null +++ b/subprojects/lib/src/file_prt.c @@ -0,0 +1,84 @@ +/* + + File: file_prt.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_prt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_prt(file_stat_t *file_stat); + +const file_hint_t file_hint_prt = { + .extension = "prt", + .description = "Pro/ENGINEER Model", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_prt +}; + +/*@ + @ requires file_recovery->file_check == &file_check_prt; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_prt(file_recovery_t *file_recovery) +{ + const unsigned char prt_footer[11] = { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C' + }; + file_search_footer(file_recovery, prt_footer, sizeof(prt_footer), 1); +} + +/*@ + @ requires separation: \separated(&file_hint_prt, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_prt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check = &file_check_prt; + file_recovery_new->extension = file_hint_prt.extension; + return 1; +} + +static void register_header_check_prt(file_stat_t *file_stat) +{ + static const unsigned char prt_header[12] = { + '#', 'U', 'G', 'C', ':', '2', ' ', 'P', + 'A', 'R', 'T', ' ' + }; + register_header_check(0, prt_header, sizeof(prt_header), &header_check_prt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ps.c b/subprojects/lib/src/file_ps.c new file mode 100644 index 0000000..1e29d1b --- /dev/null +++ b/subprojects/lib/src/file_ps.c @@ -0,0 +1,129 @@ +/* + + File: file_ps.c + + Copyright (C) 2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ps) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ps(file_stat_t *file_stat); + +const file_hint_t file_hint_ps= { + .extension="ps", + .description="PostScript or Encapsulated PostScript document", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ps +}; + +static const unsigned char ps_header[11]= { '%','!','P','S','-','A','d','o','b','e','-'}; + +/*@ + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_ps(file_recovery_t *file_recovery) +{ + const unsigned char ps_footer[5]="%%EOF"; + file_search_footer(file_recovery, ps_footer, sizeof(ps_footer), 1); +} + +/*@ + @ requires buffer_size > 8; + @ requires file_recovery->data_check==&data_check_ps; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_ps(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + unsigned int i; + /*@ + @ loop assigns i, file_recovery->calculated_file_size; + @*/ + for(i=(buffer_size/2)-4;i+4calculated_file_size=file_recovery->file_size+i+5-(buffer_size/2); + return DC_STOP; + } + } + file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2); + return DC_CONTINUE; +} + +/*@ + @ requires separation: \separated(&file_hint_ps, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ps(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* PS or EPSF */ + int i; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=sizeof(ps_header); + file_recovery_new->file_check=&file_check_ps; + /*@ loop assigns i, file_recovery_new->extension, file_recovery_new->data_check; */ + for(i=sizeof(ps_header); i < 20; i++) + { + switch(buffer[i]) + { + case '\n': + file_recovery_new->extension=file_hint_ps.extension; + if(file_recovery_new->blocksize > 8) + file_recovery_new->data_check=&data_check_ps; + return 1; + case 'E': + if(i+5 <= buffer_size && memcmp(&buffer[i],"EPSF-",5)==0) + { + file_recovery_new->extension="eps"; + return 1; + } + break; + } + } + file_recovery_new->extension=file_hint_ps.extension; + if(file_recovery_new->blocksize > 8) + file_recovery_new->data_check=&data_check_ps; + return 1; +} + +static void register_header_check_ps(file_stat_t *file_stat) +{ + register_header_check(0, ps_header,sizeof(ps_header), &header_check_ps, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_psb.c b/subprojects/lib/src/file_psb.c new file mode 100644 index 0000000..630613e --- /dev/null +++ b/subprojects/lib/src/file_psb.c @@ -0,0 +1,240 @@ +/* + + File: file_psb.c + + Copyright (C) 2006-2009,2013,2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +#ifdef DEBUG_PHOTOSHOP +#include "log.h" +#endif + +/* https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */ + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_psb(file_stat_t *file_stat); + +const file_hint_t file_hint_psb= { + .extension="psb", + .description="Adobe Photoshop Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_psb +}; + +struct psb_file_header +{ + char signature[4]; + uint16_t version; /* must be 2 */ + char reserved[6]; /* must be 0 */ + uint16_t channels; /* between 1 and 56 */ + uint32_t height; /* max of 300,000 */ + uint32_t width; /* max of 300,000 */ + uint16_t depth; /* 1, 8, 16 or 32 */ + uint16_t color_mode; /* Bitmap = 0; Grayscale = 1; Indexed = 2; RGB = 3; CMYK = 4; Multichannel = 7; Duotone = 8; Lab = 9 */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read((char *)buffer + (offset .. offset + 3)); + @ assigns \nothing; + @*/ +static uint32_t get_be32(const void *buffer, const unsigned int offset) +{ + const uint32_t *val=(const uint32_t *)((const unsigned char *)buffer+offset); + return be32(*val); +} + +/*@ + @ requires \valid_read((char *)buffer + (offset .. offset + 7)); + @ assigns \nothing; + @*/ +static uint64_t get_be64(const void *buffer, const unsigned int offset) +{ + const uint64_t *val=(const uint64_t *)((const unsigned char *)buffer+offset); + return be64(*val); +} + +/*@ + @ requires file_recovery->data_check==&psb_skip_image_data; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==\null; + @ ensures \result == DC_CONTINUE; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psb_skip_image_data(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + file_recovery->calculated_file_size+=2; + file_recovery->data_check=NULL; + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&psb_skip_layer_info; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psb_skip_layer_info || file_recovery->data_check==\null; + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ assigns file_recovery->data_check, file_recovery->file_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psb_skip_layer_info(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 8 ; */ + const uint64_t l=get_be64(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Layer info at 0x%lx, l=0x%lx\n", (long unsigned)file_recovery->calculated_file_size, (long unsigned)l); +#endif + if(l> PHOTOREC_MAX_FILE_SIZE) + return DC_STOP; + file_recovery->calculated_file_size+=l+8; +#ifdef DEBUG_PHOTOSHOP + log_info("Image data at 0x%lx\n", (long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->data_check=&psb_skip_image_data; + return psb_skip_image_data(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&psb_skip_image_resources; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psb_skip_image_resources || file_recovery->data_check==&psb_skip_layer_info || file_recovery->data_check==\null; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psb_skip_image_resources(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + const unsigned int l=get_be32(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Image resource at 0x%lx, l=0x%x\n", (long unsigned)file_recovery->calculated_file_size, l); +#endif + file_recovery->calculated_file_size+=(uint64_t)l+4; +#ifdef DEBUG_PHOTOSHOP + log_info("Layer info at 0x%lx\n", (long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->data_check=&psb_skip_layer_info; + return psb_skip_layer_info(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 32; + @ requires file_recovery->data_check==&psb_skip_color_mode; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psb_skip_color_mode || file_recovery->data_check==&psb_skip_image_resources || file_recovery->data_check==&psb_skip_layer_info || file_recovery->data_check==\null; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psb_skip_color_mode(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + const struct psb_file_header *hdr=(const struct psb_file_header *)&buffer[buffer_size/2]; + const unsigned int channels=be16(hdr->channels); + const unsigned int depth=be16(hdr->depth); + const unsigned int height=be32(hdr->height); + const unsigned int width=be32(hdr->width); + if(channels==0 || channels>56 || + height==0 || height>300000 || + width==0 || width>300000 || + (depth!=1 && depth!=8 && depth!=16 && depth!=32)) + return DC_ERROR; + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + const unsigned int l=get_be32(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Color mode at 0x%lx, l=0x%x\n", (long unsigned)file_recovery->calculated_file_size, l); +#endif + if(l!=0 && l<4) + return DC_ERROR; + file_recovery->calculated_file_size+=(uint64_t)l+4; + file_recovery->data_check=&psb_skip_image_resources; + return psb_skip_image_resources(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct psb_file_header); + @ requires separation: \separated(&file_hint_psb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_psb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct psb_file_header *hdr=(const struct psb_file_header *)buffer; + const unsigned int channels=be16(hdr->channels); + const unsigned int depth=be16(hdr->depth); + const unsigned int height=be32(hdr->height); + const unsigned int width=be32(hdr->width); +#ifdef DEBUG_PHOTOSHOP + log_info("channels %u\n", channels); + log_info("height %u\n", height); + log_info("width %u\n", width); + log_info("depth %u\n", depth); + log_info("color_mode %u\n", be16(hdr->color_mode)); +#endif + if(channels==0 || channels>56 || + height==0 || height>300000 || + width==0 || width>300000 || + (depth!=1 && depth!=8 && depth!=16 && depth!=32)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=70; + file_recovery_new->extension=file_hint_psb.extension; + if(file_recovery_new->blocksize < 16) + return 1; + /* File header */ + file_recovery_new->calculated_file_size=0x1a; + file_recovery_new->data_check=&psb_skip_color_mode; + file_recovery_new->file_check=&file_check_size_min; + return 1; +} + +static void register_header_check_psb(file_stat_t *file_stat) +{ + static const unsigned char psb_header[6]={'8', 'B', 'P', 'S', 0x00, 0x02}; + register_header_check(0, psb_header,sizeof(psb_header), &header_check_psb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_psd.c b/subprojects/lib/src/file_psd.c new file mode 100644 index 0000000..fc01ef5 --- /dev/null +++ b/subprojects/lib/src/file_psd.c @@ -0,0 +1,229 @@ +/* + + File: file_psd.c + + Copyright (C) 2006-2009,2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +#ifdef DEBUG_PHOTOSHOP +#include "log.h" +#endif + +/* https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */ + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_psd(file_stat_t *file_stat); + +const file_hint_t file_hint_psd= { + .extension="psd", + .description="Adobe Photoshop Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_psd +}; + +struct psd_file_header +{ + char signature[4]; + uint16_t version; /* must be 1 */ + char reserved[6]; /* must be 0 */ + uint16_t channels; /* between 1 and 56 */ + uint32_t height; /* max of 30,000 */ + uint32_t width; /* max of 30,000 */ + uint16_t depth; /* 1, 8, 16 or 32 */ + uint16_t color_mode; /* Bitmap = 0; Grayscale = 1; Indexed = 2; RGB = 3; CMYK = 4; Multichannel = 7; Duotone = 8; Lab = 9 */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read((char *)buffer + (offset .. offset + 3)); + @ assigns \nothing; + @*/ +static uint32_t get_be32(const void *buffer, const unsigned int offset) +{ + const uint32_t *val=(const uint32_t *)((const unsigned char *)buffer+offset); + return be32(*val); +} + +/*@ + @ requires file_recovery->data_check==&psd_skip_image_data; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==\null; + @ ensures \result == DC_CONTINUE; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psd_skip_image_data(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + file_recovery->calculated_file_size+=2; + file_recovery->data_check=NULL; + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&psd_skip_layer_info; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psd_skip_layer_info || file_recovery->data_check==\null; + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psd_skip_layer_info(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + const unsigned int l=get_be32(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Layer info at 0x%lx, l=0x%x\n", (long unsigned)file_recovery->calculated_file_size, l); +#endif + file_recovery->calculated_file_size+=(uint64_t)l+4; +#ifdef DEBUG_PHOTOSHOP + log_info("Image data at 0x%lx\n", (long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->data_check=&psd_skip_image_data; + return psd_skip_image_data(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->data_check==&psd_skip_image_resources; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psd_skip_image_resources || file_recovery->data_check==&psd_skip_layer_info || file_recovery->data_check==\null; + @ ensures \result == DC_CONTINUE || \result == DC_STOP; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psd_skip_image_resources(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + const unsigned int l=get_be32(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Image resource at 0x%lx, l=0x%x\n", (long unsigned)file_recovery->calculated_file_size, l); +#endif + file_recovery->calculated_file_size+=(uint64_t)l+4; +#ifdef DEBUG_PHOTOSHOP + log_info("Layer info at 0x%lx\n", (long unsigned)file_recovery->calculated_file_size); +#endif + file_recovery->data_check=&psd_skip_layer_info; + return psd_skip_layer_info(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 32; + @ requires file_recovery->data_check==&psd_skip_color_mode; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ ensures file_recovery->data_check==&psd_skip_color_mode || file_recovery->data_check==&psd_skip_image_resources || file_recovery->data_check==&psd_skip_layer_info || file_recovery->data_check==\null; + @ assigns file_recovery->data_check, file_recovery->calculated_file_size; + @*/ +static data_check_t psd_skip_color_mode(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + const struct psd_file_header *hdr=(const struct psd_file_header *)&buffer[buffer_size/2]; + const unsigned int channels=be16(hdr->channels); + const unsigned int depth=be16(hdr->depth); + const unsigned int height=be32(hdr->height); + const unsigned int width=be32(hdr->width); + if(channels==0 || channels>56 || + height==0 || height>30000 || + width==0 || width>30000 || + (depth!=1 && depth!=8 && depth!=16 && depth!=32)) + return DC_ERROR; + if(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 4 ; */ + const unsigned int l=get_be32(buffer, i); +#ifdef DEBUG_PHOTOSHOP + log_info("Color mode at 0x%lx, l=0x%x\n", (long unsigned)file_recovery->calculated_file_size, l); +#endif + if(l!=0 && l<4) + return DC_ERROR; + file_recovery->calculated_file_size+=(uint64_t)l+4; + file_recovery->data_check=&psd_skip_image_resources; + return psd_skip_image_resources(buffer, buffer_size, file_recovery); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= sizeof(struct psd_file_header); + @ requires separation: \separated(&file_hint_psd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_psd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct psd_file_header *hdr=(const struct psd_file_header *)buffer; + const unsigned int channels=be16(hdr->channels); + const unsigned int depth=be16(hdr->depth); + const unsigned int height=be32(hdr->height); + const unsigned int width=be32(hdr->width); +#ifdef DEBUG_PHOTOSHOP + log_info("channels %u\n", channels); + log_info("height %u\n", height); + log_info("width %u\n", width); + log_info("depth %u\n", depth); + log_info("color_mode %u\n", be16(hdr->color_mode)); +#endif + if(channels==0 || channels>56 || + height==0 || height>30000 || + width==0 || width>30000 || + (depth!=1 && depth!=8 && depth!=16 && depth!=32)) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=70; + file_recovery_new->extension=file_hint_psd.extension; + if(file_recovery_new->blocksize < 16) + return 1; + /* File header */ + file_recovery_new->calculated_file_size=0x1a; + file_recovery_new->data_check=&psd_skip_color_mode; + file_recovery_new->file_check=&file_check_size_min; + return 1; +} + +static void register_header_check_psd(file_stat_t *file_stat) +{ + static const unsigned char psd_header[6]={'8', 'B', 'P', 'S', 0x00, 0x01}; + register_header_check(0, psd_header,sizeof(psd_header), &header_check_psd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_psf.c b/subprojects/lib/src/file_psf.c new file mode 100644 index 0000000..8f9fa12 --- /dev/null +++ b/subprojects/lib/src/file_psf.c @@ -0,0 +1,73 @@ +/* + + File: file_psf.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_psf(file_stat_t *file_stat); + +const file_hint_t file_hint_psf= { + .extension="psf", + .description="Print Shop", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_psf +}; + +/*@ + @ requires buffer_size >= 32; + @ requires separation: \separated(&file_hint_psf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_psf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=((uint64_t)buffer[28]<<24)+((uint64_t)buffer[29]<<16)+((uint64_t)buffer[30]<<8)+((uint64_t)buffer[31]<<0)+272; + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_psf) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_psf.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_psf(file_stat_t *file_stat) +{ + register_header_check(12, "PSD5RDOC", 8, &header_check_psf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_psp.c b/subprojects/lib/src/file_psp.c new file mode 100644 index 0000000..48ae0c0 --- /dev/null +++ b/subprojects/lib/src/file_psp.c @@ -0,0 +1,106 @@ +/* + + File: file_psp.c + + Copyright (C) 2008,2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_psp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_psp(file_stat_t *file_stat); + +const file_hint_t file_hint_psp= { + .extension="psp", + .description="Paint Shop Pro Image File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_psp +}; + +struct psp_chunk { + char header[4]; + uint16_t id; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_psp; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_psp(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 10 < file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i < buffer_size - 10; */ + const struct psp_chunk *chunk=(const struct psp_chunk *)&buffer[i]; + if(memcmp(&buffer[i], "~BK\0", 4) != 0) + return DC_STOP; + /* chunk: header, id, total_length */ + file_recovery->calculated_file_size+=10; + file_recovery->calculated_file_size+=le32(chunk->size); + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 0x28; + @ requires separation: \separated(&file_hint_psp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_psp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned int ver_major=buffer[0x20]+(buffer[0x21]<<8); + if(memcmp(&buffer[0x24], "~BK\0", 4)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_psp.extension; + if(ver_major>=4 && file_recovery_new->blocksize >= 16) + { + file_recovery_new->calculated_file_size=0x24; + file_recovery_new->data_check=&data_check_psp; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_psp(file_stat_t *file_stat) +{ + register_header_check(0, "Paint Shop Pro Image File\n\032\0\0\0\0\0", 32, &header_check_psp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pst.c b/subprojects/lib/src/file_pst.c new file mode 100644 index 0000000..603375c --- /dev/null +++ b/subprojects/lib/src/file_pst.c @@ -0,0 +1,171 @@ +/* + + File: file_pst.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pst) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pst(file_stat_t *file_stat); + +const file_hint_t file_hint_pst= { + .extension="pst", + .description="Outlook (pst/wab/dbx)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pst +}; + +#define INDEX_TYPE_OFFSET 0x0A +#define FILE_SIZE_POINTER 0xA8 +#define FILE_SIZE_POINTER_64 0xB8 +#define DBX_SIZE_POINTER 0x7C + +/*@ + @ requires buffer_size >= DBX_SIZE_POINTER + 4; + @ requires separation: \separated(&file_hint_pst, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_dbx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const uint64_t size=(uint64_t)buffer[DBX_SIZE_POINTER] + + (((uint64_t)buffer[DBX_SIZE_POINTER+1])<<8) + + (((uint64_t)buffer[DBX_SIZE_POINTER+2])<<16) + + (((uint64_t)buffer[DBX_SIZE_POINTER+3])<<24); + if(size < DBX_SIZE_POINTER + 4) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="dbx"; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/* + Outlook 2000 + 0x0000 uchar signature[4]; + 0x000a uchar indexType; + 0x00a8 uint32_t total_file_size; + 0x00b8 uint32_t backPointer2; + 0x00bc uint32_t offsetIndex2; + 0x00c0 uint32_t backPointer1; + 0x00c4 uint32_t offsetIndex1; + 0x01cd uchar encryptionType; + + Outlook 2003 + 0x0000 uchar signature[4]; + 0x000a uchar indexType; + 0x00b8 uint64_t total_file_size; + 0x00d8 uint64_t backPointer2; + 0x00e0 uint64_t offsetIndex2; + 0x00e8 uint64_t backPointer1; + 0x00f0 uint64_t offsetIndex1; + 0x0201 uchar encryptionType; + + More information about the file structure can be found at + http://www.five-ten-sg.com/libpst/ +*/ + +/*@ + @ requires separation: \separated(&file_hint_pst, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_wab(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="wab"; /* Adresse Book */ + return 1; +} + +/*@ + @ requires buffer_size >= FILE_SIZE_POINTER + 4; + @ requires buffer_size >= FILE_SIZE_POINTER_64 + 8; + @ requires separation: \separated(&file_hint_pst, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pst(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[INDEX_TYPE_OFFSET]==0x0e || + buffer[INDEX_TYPE_OFFSET]==0x0f) + { + const uint64_t size=(uint64_t)buffer[FILE_SIZE_POINTER] + + (((uint64_t)buffer[FILE_SIZE_POINTER+1])<<8) + + (((uint64_t)buffer[FILE_SIZE_POINTER+2])<<16) + + (((uint64_t)buffer[FILE_SIZE_POINTER+3])<<24); + if(size < 0x1cd) + return 0; + /* Outlook 2000 and older versions */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pst.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + else + // if(buffer[INDEX_TYPE_OFFSET]==0x15 || buffer[INDEX_TYPE_OFFSET]==0x17) + { /* Outlook 2003 */ + const uint64_t size=(uint64_t)buffer[FILE_SIZE_POINTER_64] + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+1])<<8) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+2])<<16) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+3])<<24) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+4])<<32) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+5])<<40) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+6])<<48) + + (((uint64_t)buffer[FILE_SIZE_POINTER_64+7])<<56); + if(size < 0x201) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pst.extension; + file_recovery_new->calculated_file_size=size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } +} + +static void register_header_check_pst(file_stat_t *file_stat) +{ + static const unsigned char dbx_header[4]= { 0xCF, 0xAD, 0x12, 0xFE }; + static const unsigned char wab_header[16] = { 0x9c, 0xcb, 0xcb, 0x8d, 0x13, 0x75, 0xd2, 0x11, + 0x91, 0x58, 0x00, 0xc0, 0x4f, 0x79, 0x56, 0xa4 }; + register_header_check(0, "!BDN", 4, &header_check_pst, file_stat); + register_header_check(0, dbx_header,sizeof(dbx_header), &header_check_dbx, file_stat); + register_header_check(0, wab_header,sizeof(wab_header), &header_check_wab, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ptb.c b/subprojects/lib/src/file_ptb.c new file mode 100644 index 0000000..3bc4357 --- /dev/null +++ b/subprojects/lib/src/file_ptb.c @@ -0,0 +1,70 @@ +/* + + File: file_ptb.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ptb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ptb(file_stat_t *file_stat); + +const file_hint_t file_hint_ptb= { + .extension="ptb", + .description="PowerTab", + .max_filesize=10*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ptb +}; + +/*@ + @ requires buffer_size >= 6; + @ requires separation: \separated(&file_hint_ptb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ptb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned int file_version=buffer[4]|(buffer[5]<<8); + if(file_version>=1 && file_version<=4) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ptb.extension; + return 1; + } + return 0; +} + +static void register_header_check_ptb(file_stat_t *file_stat) +{ + static const unsigned char ptb_header[4]= {'p', 't', 'a', 'b'}; + register_header_check(0, ptb_header,sizeof(ptb_header), &header_check_ptb, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ptf.c b/subprojects/lib/src/file_ptf.c new file mode 100644 index 0000000..277028f --- /dev/null +++ b/subprojects/lib/src/file_ptf.c @@ -0,0 +1,81 @@ +/* + + File: file_ptf.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ptf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ptf(file_stat_t *file_stat); + +const file_hint_t file_hint_ptf= { + .extension="ptf", + .description="Pro Tools session File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ptf +}; + +/*@ + @ requires buffer_size >= 0x2d + 9; + @ requires separation: \separated(&file_hint_ptf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ptf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + switch(buffer[0x12]) + { + case 1: + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ptf.extension; + return 1; + case 5: + if(memcmp(&buffer[0x2d], "Pro Tools", 9)!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="ptx"; + return 1; + default: + return 0; + } +} + +static void register_header_check_ptf(file_stat_t *file_stat) +{ + static const unsigned char ptf_header[18]= { + 0x03, '0' , '0' , '1' , '0' , '1' , '1' , '1' , + '1', '0' , '0' , '1' , '0' , '1' , '0' , '1' , + '1', 0x00 + }; + register_header_check(0, ptf_header, sizeof(ptf_header), &header_check_ptf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pyc.c b/subprojects/lib/src/file_pyc.c new file mode 100644 index 0000000..b907c20 --- /dev/null +++ b/subprojects/lib/src/file_pyc.c @@ -0,0 +1,107 @@ +/* + + File: file_pyc.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pyc) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pyc(file_stat_t *file_stat); + +const file_hint_t file_hint_pyc= { + .extension="pyc", + .description="Python Compiled Script", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pyc +}; + +struct pyc_header { + uint32_t magic_number; + uint32_t modtime; +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_pyc, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pyc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct pyc_header *pyc=(const struct pyc_header *)buffer; + /* marshalled code object must be of of type TYPE_CODE and argcount < 256 */ + if(buffer[8]!='c' || buffer[9]!=0 || buffer[10]!=0 || buffer[11]!=0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pyc.extension; + file_recovery_new->time=le32(pyc->modtime); + return 1; +} + +static void register_header_check_pyc(file_stat_t *file_stat) +{ + static const unsigned char pyc_15_magic[4]= { 0x99, 0x4e, '\r', '\n'}; + static const unsigned char pyc_20_magic[4]= { 0x87, 0xc6, '\r', '\n'}; + static const unsigned char pyc_21_magic[4]= { 0x2a, 0xeb, '\r', '\n'}; + static const unsigned char pyc_22_magic[4]= { 0x2d, 0xed, '\r', '\n'}; + static const unsigned char pyc_23_magic[4]= { 0x3b, 0xf2, '\r', '\n'}; + static const unsigned char pyc_24_magic[4]= { 0x6d, 0xf2, '\r', '\n'}; + static const unsigned char pyc_25_magic[4]= { 0xb3, 0xf2, '\r', '\n'}; + static const unsigned char pyc_26_magic[4]= { 0xd1, 0xf2, '\r', '\n'}; + static const unsigned char pyc_27_magic[4]= { 0x03, 0xf3, '\r', '\n'}; + static const unsigned char pyc_30_magic[4]= { 0x3b, 0x0c, '\r', '\n'}; + static const unsigned char pyc_31_magic[4]= { 0x4f, 0x0c, '\r', '\n'}; + static const unsigned char pyc_32_magic[4]= { 0x6c, 0x0c, '\r', '\n'}; + static const unsigned char pyc_33_magic[4]= { 0x9e, 0x0c, '\r', '\n'}; + static const unsigned char pyc_34_magic[4]= { 0xee, 0x0c, '\r', '\n'}; + register_header_check(0, pyc_15_magic, sizeof(pyc_15_magic), &header_check_pyc, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, pyc_20_magic, sizeof(pyc_20_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_21_magic, sizeof(pyc_21_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_22_magic, sizeof(pyc_22_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_23_magic, sizeof(pyc_23_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_24_magic, sizeof(pyc_24_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_25_magic, sizeof(pyc_25_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_26_magic, sizeof(pyc_26_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_27_magic, sizeof(pyc_27_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_30_magic, sizeof(pyc_30_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_31_magic, sizeof(pyc_31_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_32_magic, sizeof(pyc_32_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_33_magic, sizeof(pyc_33_magic), &header_check_pyc, file_stat); + register_header_check(0, pyc_34_magic, sizeof(pyc_34_magic), &header_check_pyc, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_pzf.c b/subprojects/lib/src/file_pzf.c new file mode 100644 index 0000000..11ac46e --- /dev/null +++ b/subprojects/lib/src/file_pzf.c @@ -0,0 +1,84 @@ +/* + + File: file_pzf.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pzf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pzf(file_stat_t *file_stat); + +const file_hint_t file_hint_pzf= { + .extension="pzf", + .description="GraphPrism 4", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pzf +}; + +/*@ + @ requires file_recovery->file_check == &file_check_pzf; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_pzf(file_recovery_t *file_recovery) +{ + const unsigned char pzf_footer[17]= { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x40 + }; + file_search_footer(file_recovery, pzf_footer, sizeof(pzf_footer), 0); +} + +/*@ + @ requires separation: \separated(&file_hint_pzf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pzf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pzf.extension; + file_recovery_new->file_check=&file_check_pzf; + return 1; +} + +static void register_header_check_pzf(file_stat_t *file_stat) +{ + static const unsigned char pzf_header[8]= { + 'P' , 'C' , 'F' , 'F' , 'G' , 'R' , 'A' , '4' + }; + register_header_check(0, pzf_header, sizeof(pzf_header), &header_check_pzf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_pzh.c b/subprojects/lib/src/file_pzh.c new file mode 100644 index 0000000..2379747 --- /dev/null +++ b/subprojects/lib/src/file_pzh.c @@ -0,0 +1,95 @@ +/* + + File: file_pzh.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_pzh) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_pzh(file_stat_t *file_stat); + +/* Presto http://www.soft.es/ */ + +const file_hint_t file_hint_pzh= { + .extension="pzh", + .description="Presto", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_pzh +}; + +static const unsigned char pzh_header[10]= { + 0x00, 0x00, 0x01, '8', '.', '0', 0x00, 0x02, + 0x05, 0x03 +}; + +/*@ + @ requires file_recovery->file_rename==&file_rename_pzh; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_pzh(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + int buffer_size; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(fseek(file, 0x9ce, SEEK_SET)<0) + { + fclose(file); + return ; + } + buffer_size=fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size > 0) + file_rename(file_recovery, buffer, buffer_size, 0, "pzh", 0); +} + +/*@ + @ requires separation: \separated(&file_hint_pzh, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_pzh(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_pzh.extension; + file_recovery_new->file_rename=&file_rename_pzh; + file_recovery_new->min_filesize=0x9c4 + sizeof(pzh_header); + return 1; +} + +static void register_header_check_pzh(file_stat_t *file_stat) +{ + register_header_check(0x9c4, pzh_header, sizeof(pzh_header), &header_check_pzh, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_qbb.c b/subprojects/lib/src/file_qbb.c new file mode 100644 index 0000000..ec6127b --- /dev/null +++ b/subprojects/lib/src/file_qbb.c @@ -0,0 +1,228 @@ +/* + + File: file_qbb.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qbb) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#ifdef DEBUG_QBB +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_qbb(file_stat_t *file_stat); + +const file_hint_t file_hint_qbb= { + .extension="qbb", + .description="Quickbooks (qbb/qbw)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_qbb +}; + +struct qbb_header +{ + uint16_t magic; + uint16_t type; + uint16_t data_len; + uint16_t unk1; +#if 0 + unsigned char data[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +struct qbb_header02 +{ + uint16_t magic; + uint16_t type; /* 2 */ + uint16_t data_len; + uint16_t unk1; + uint8_t unk2[6]; + uint32_t size; + uint8_t unk3[10]; + uint16_t title_len; +#if 0 + uint8_t title[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename==&file_rename_qbb; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_qbb(file_recovery_t *file_recovery) +{ + FILE *file; + unsigned int i=0; + char buffer[4096]; + /*@ assert \valid((char *)&buffer + (0 .. sizeof(buffer)-1)); */ + size_t lu; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + lu=fread(&buffer, 1, sizeof(buffer), file); + fclose(file); + if(lu <= 0) + return; + /*@ assert 0 < lu <= sizeof(buffer); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, sizeof(buffer)); +#endif + /*@ assert \valid_read((char *)&buffer + (0 .. lu-1)); */ + /*@ loop assigns i; */ + while(i+sizeof(struct qbb_header02) <= lu) + { + /*@ assert i+sizeof(struct qbb_header02) <= lu; */ + /*@ assert i+sizeof(struct qbb_header) <= lu; */ + const struct qbb_header *hdr=(const struct qbb_header*)&buffer[i]; + const unsigned int data_len=le16(hdr->data_len); + if(le16(hdr->magic)!=0x8645) + return ; + if(le16(hdr->type)==2) + { + if(i+sizeof(struct qbb_header)+data_len < lu) + { + const struct qbb_header02 *hdr2=(const struct qbb_header02 *)&buffer[i]; + /*@ assert \valid_read(hdr2); */ + const unsigned int title_len=le16(hdr2->title_len); + if(sizeof(struct qbb_header02)+title_len <= sizeof(struct qbb_header)+data_len) + { + const char *title=&buffer[i+sizeof(struct qbb_header02)]; + file_rename(file_recovery, title, title_len, 0, NULL, 1); + } + } + return ; + } + i+=sizeof(struct qbb_header)+data_len; + } +} + +/*@ + @ requires buffer_size >= 0x10; + @ requires separation: \separated(&file_hint_qbb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qbb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct qbb_header *hdr0=(const struct qbb_header*)buffer; + uint64_t data_size=0; + unsigned int i=0; + if(buffer[0x0e]!=0x45 || buffer[0x0f]!=0x86) + return 0; + /*@ + @ loop assigns i, data_size; + @*/ + while(i+sizeof(struct qbb_header02) < buffer_size) + { + const struct qbb_header *hdr=(const struct qbb_header*)&buffer[i]; + const unsigned int data_len=le16(hdr->data_len); + if(le16(hdr->magic)!=0x8645) + break; + if(le16(hdr->type)==2) + { + const struct qbb_header02 *hdr2=(const struct qbb_header02 *)hdr; + data_size=le32(hdr2->size); + } +#ifdef DEBUG_QBB + log_info("i=0x%x size=0x%lx len=0x%x\n", i, sizeof(struct qbb_header), data_len); +#endif + i+=sizeof(struct qbb_header)+data_len; + } +#ifdef DEBUG_QBB + log_info("i=0x%x data_size=0x%lx\n", i, (long unsigned)data_size); +#endif + if(data_size==0) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=data_size+i; + if(le16(hdr0->unk1)==1) + file_recovery_new->extension="qbmb"; + else + file_recovery_new->extension=file_hint_qbb.extension; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->file_rename=&file_rename_qbb; + return 1; +} + +/*@ + @ requires buffer_size >= 0x64; + @ requires separation: \separated(&file_hint_qbb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qbw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0x60]=='M' && buffer[0x61]=='A' && buffer[0x62]=='U' && buffer[0x63]=='I') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="qbw"; + file_recovery_new->calculated_file_size=(((uint64_t)buffer[0x34] + (((uint64_t)buffer[0x34+1])<<8)+ + (((uint64_t)buffer[0x34+2])<<16) + (((uint64_t)buffer[0x34+3])<<24))+1)*1024; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +/*@ + @ requires buffer_size >= 0x87A + 6; + @ requires separation: \separated(&file_hint_qbb, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qbw2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x87A], "Sybase", 6)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="qbw"; + return 1; + } + return 0; +} + +static void register_header_check_qbb(file_stat_t *file_stat) +{ + static const unsigned char qbb_header[8]= {0x45, 0x86, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00}; + static const unsigned char qbmb_header[8]= {0x45, 0x86, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00}; + static const unsigned char qbw2_header[4]= {0x5e, 0xba, 0x7a, 0xda}; + static const unsigned char qbw_header[4]= {0x56, 0x00, 0x00, 0x00}; + register_header_check(0, qbb_header,sizeof(qbb_header), &header_check_qbb, file_stat); + register_header_check(0, qbmb_header,sizeof(qbmb_header), &header_check_qbb, file_stat); + register_header_check(4, qbw_header,sizeof(qbw_header), &header_check_qbw, file_stat); + register_header_check(0x14, qbw2_header,sizeof(qbw2_header), &header_check_qbw2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_qdf.c b/subprojects/lib/src/file_qdf.c new file mode 100644 index 0000000..5f4603b --- /dev/null +++ b/subprojects/lib/src/file_qdf.c @@ -0,0 +1,76 @@ +/* + + File: file_qdf.c + + Copyright (C) 2006 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qdf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +#if !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_doc; +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_qdf(file_stat_t *file_stat); + +const file_hint_t file_hint_qdf= { + .extension="qdf", + .description="Quicken", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_qdf +}; + +/*@ + @ requires separation: \separated(&file_hint_qdf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @*/ +static int header_check_qdf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ +#if !defined(SINGLE_FORMAT) + if(file_recovery->file_stat != NULL && + file_recovery->file_stat->file_hint==&file_hint_doc) +// && strstr(file_recovery->filename, ".qdf-backup")!=NULL) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_qdf.extension; + return 1; +} + +static void register_header_check_qdf(file_stat_t *file_stat) +{ + static const unsigned char qdf_header[6] = { 0xAC, 0x9E, 0xBD, 0x8F, 0x00, 0x00}; + register_header_check(0, qdf_header, sizeof(qdf_header), &header_check_qdf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_qkt.c b/subprojects/lib/src/file_qkt.c new file mode 100644 index 0000000..b1dda88 --- /dev/null +++ b/subprojects/lib/src/file_qkt.c @@ -0,0 +1,66 @@ +/* + + File: file_qkt.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qkt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_qkt(file_stat_t *file_stat); + +const file_hint_t file_hint_qkt= { + .extension="qkt", + .description="Apple QuickTake 100", + .max_filesize=1024*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_qkt +}; + +/*@ + @ requires separation: \separated(&file_hint_qkt, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qkt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_qkt.extension; + return 1; +} + +static void register_header_check_qkt(file_stat_t *file_stat) +{ + static const unsigned char qkt_header[8]= { + 'q' , 'k' , 't' , 'k' , 0x00, 0x00, 0x00, 0x08 + }; + register_header_check(0, qkt_header, sizeof(qkt_header), &header_check_qkt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_qxd.c b/subprojects/lib/src/file_qxd.c new file mode 100644 index 0000000..807cb3a --- /dev/null +++ b/subprojects/lib/src/file_qxd.c @@ -0,0 +1,84 @@ +/* + + File: file_qxd.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_qxd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_qxd(file_stat_t *file_stat); + +const file_hint_t file_hint_qxd= { + .extension="qxd", + .description="QuarkXpress Document", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_qxd +}; + +/*@ + @ requires separation: \separated(&file_hint_qxd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qxd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_qxd.extension; + file_recovery_new->min_filesize=4; + return 1; +} + +/*@ + @ requires separation: \separated(&file_hint_qxd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_qxp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* Intel or Mac QuarkXpress Document */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="qxp"; + file_recovery_new->min_filesize=8; + return 1; +} + +static void register_header_check_qxd(file_stat_t *file_stat) +{ + static const unsigned char qxd_header[4]={'X','P','R','3' }; + static const unsigned char qxp_header_be[6]={'I','I','X','P','R','3' }; + static const unsigned char qxp_header_le[6]={'M','M','X','P','R','3' }; + register_header_check(0, qxd_header,sizeof(qxd_header), &header_check_qxd, file_stat); + register_header_check(2, qxp_header_be,sizeof(qxp_header_be), &header_check_qxp, file_stat); + register_header_check(2, qxp_header_le,sizeof(qxp_header_le), &header_check_qxp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_r3d.c b/subprojects/lib/src/file_r3d.c new file mode 100644 index 0000000..e77ce63 --- /dev/null +++ b/subprojects/lib/src/file_r3d.c @@ -0,0 +1,180 @@ +/* + + File: file_r3d.c + + Copyright (C) 2009,2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_r3d) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_r3d(file_stat_t *file_stat); + +const file_hint_t file_hint_r3d = { + .extension = "r3d", + .description = "RED r3d camera", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_r3d +}; + +struct atom_struct +{ + uint32_t size; + uint32_t type; +} __attribute__((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->data_check==&data_check_r3d; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size, file_recovery->data_check; + @*/ +static data_check_t data_check_r3d(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ + @ loop assigns file_recovery->calculated_file_size; + @*/ + while(file_recovery->calculated_file_size + buffer_size / 2 >= file_recovery->file_size && file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size / 2) + { + const unsigned int i = file_recovery->calculated_file_size + buffer_size / 2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size-8; */ + const struct atom_struct *atom = (const struct atom_struct *)&buffer[i]; + uint64_t atom_size = be32(atom->size); + if(atom_size < 8) + return DC_STOP; +#ifdef DEBUG_R3D + log_trace("file_r3d.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n", + file_recovery->filename, + buffer[i + 4], buffer[i + 5], buffer[i + 6], buffer[i + 7], + buffer[i + 4], buffer[i + 5], buffer[i + 6], buffer[i + 7], + (long long unsigned)atom_size, + (long long unsigned)file_recovery->calculated_file_size); +#endif + if(buffer[i + 4] == 'R' && buffer[i + 5] == 'E' && buffer[i + 6] == 'O') + { + /* End of file */ + file_recovery->calculated_file_size += atom_size; + file_recovery->data_check = NULL; + return DC_CONTINUE; + } + if(buffer[i + 4] != 'R') + { + return DC_STOP; + } + /* REDV1 REDV RPAD RDVO RDVS RDAO RDAS REOB */ + file_recovery->calculated_file_size += atom_size; + } +#ifdef DEBUG_R3D + log_trace("file_r3d.c: new calculated_file_size %llu\n", + (long long unsigned)file_recovery->calculated_file_size); +#endif + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_rename==&file_rename_r3d; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_r3d(file_recovery_t *file_recovery) +{ + unsigned char buffer[512]; + FILE *file; + size_t buffer_size; + unsigned int i; + if((file = fopen(file_recovery->filename, "rb")) == NULL) + return; + buffer_size = fread(buffer, 1, sizeof(buffer), file); + fclose(file); + if(buffer_size < 0x44) + return; + /*@ loop assigns i; */ + for(i = 0x43; i < buffer_size && buffer[i] != 0 && buffer[i] != '.'; i++) + { + if(!isalnum(buffer[i]) && buffer[i] != '_') + return; + } + file_rename(file_recovery, buffer, i, 0x43, NULL, 1); +} + +/*@ + @ requires buffer_size >= sizeof(struct atom_struct); + @ requires separation: \separated(&file_hint_r3d, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_r3d(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct atom_struct *atom = (const struct atom_struct *)buffer; + if(be32(atom->size) < 8) + return 0; + if(buffer[0xa] == 'R' && buffer[0xb] == '1') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_r3d.extension; + file_recovery_new->file_rename = &file_rename_r3d; + if(file_recovery_new->blocksize < 8) + return 1; + file_recovery_new->data_check = &data_check_r3d; + file_recovery_new->file_check = &file_check_size; + return 1; + } + return 0; +} + +/*@ + @ requires buffer_size >= 0xc; + @ requires separation: \separated(&file_hint_r3d, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_r3d_v2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[0xa] == 'R' && buffer[0xb] == '2') + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_r3d.extension; + return 1; + } + return 0; +} + +static void register_header_check_r3d(file_stat_t *file_stat) +{ + static const unsigned char r3d_header1[4] = { 'R', 'E', 'D', '1' }; + static const unsigned char r3d_header2[4] = { 'R', 'E', 'D', '2' }; + register_header_check(4, r3d_header1, sizeof(r3d_header1), &header_check_r3d, file_stat); + register_header_check(4, r3d_header2, sizeof(r3d_header2), &header_check_r3d_v2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ra.c b/subprojects/lib/src/file_ra.c new file mode 100644 index 0000000..95af7cc --- /dev/null +++ b/subprojects/lib/src/file_ra.c @@ -0,0 +1,128 @@ +/* + + File: file_ra.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the teras of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ra) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ra(file_stat_t *file_stat); + +const file_hint_t file_hint_ra= { + .extension="ra", + .description="Real Audio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ra +}; + +struct ra3_header { + char magic[4]; + uint16_t version; /* 3 */ + uint16_t header_size; /* not including first 8 bytes */ + char unk1[10]; + uint32_t data_size; + uint8_t title_length; +#if 0 + char title[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +struct ra4_header { + char magic[4]; + uint16_t version; /* 4 */ + uint16_t unused; /* always 0 */ + char sign[4]; /* .ra4 */ + uint32_t data_size; + uint16_t version2; + uint16_t header_size; /* not including the first 20 bytes ? */ + uint16_t codec_flavor; + uint32_t codec_frame_size; + char unk1[12]; + uint16_t sub_packet_h; + uint16_t frame_size; + uint16_t subpacket_size; + uint16_t unk2; + uint16_t samplerate; + uint16_t unk3; + uint16_t sample_size; + uint16_t channels; + char interleaver_ID_length; /* always 4 */ + char interleaver_ID[4]; + char FourCC_length; /* always 4 */ + char FourCC_string[4]; + char unk4[3]; + uint8_t title_length; +#if 0 + char title[0]; +#endif +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct ra3_header); + @ requires buffer_size >= sizeof(struct ra4_header); + @ requires separation: \separated(&file_hint_ra, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ra(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[4]==0x00 && buffer[5]==0x03) + { /* V3 */ + const struct ra3_header *ra3=(const struct ra3_header *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ra.extension; + file_recovery_new->calculated_file_size=(uint64_t)8 + be16(ra3->header_size) + be32(ra3->data_size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + else if(buffer[4]==0x00 && buffer[5]==0x04 && + buffer[8]=='.' && buffer[9]=='r' && buffer[10]=='a' && buffer[11]=='4') + { /* V4 */ + const struct ra4_header *ra4=(const struct ra4_header *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ra.extension; + file_recovery_new->calculated_file_size=(uint64_t)40 + be16(ra4->header_size) + be32(ra4->data_size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; + } + return 0; +} + +static void register_header_check_ra(file_stat_t *file_stat) +{ + static const unsigned char ra_header[4] = { '.', 'r', 'a', 0xfd}; + register_header_check(0, ra_header,sizeof(ra_header), &header_check_ra, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_raf.c b/subprojects/lib/src/file_raf.c new file mode 100644 index 0000000..ca7234b --- /dev/null +++ b/subprojects/lib/src/file_raf.c @@ -0,0 +1,121 @@ +/* + + File: file_raf.c + + Copyright (C) 1998-2005,2007-2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_raf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_raf(file_stat_t *file_stat); + +const file_hint_t file_hint_raf= { + .extension="raf", + .description="Raw Fujifilm picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_raf +}; + +/* Documentation source: https://libopenraw.pages.freedesktop.org/formats/raf/ */ +struct header_raf +{ + char magic[16]; + char unk1[4]; /* 0201 */ + char unk2[8]; /* FF393103 */ + char model[32]; /* ie. FinePix E900 */ + char dir_version[4]; /* 0100 or 0159 */ + char unk3[20]; + uint32_t jpg_offset; + uint32_t jpg_size; + uint32_t cfa_header_offset; + uint32_t cfa_header_size; + uint32_t cfa_offset; + uint32_t cfa_size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct header_raf); + @ requires separation: \separated(&file_hint_raf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_raf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct header_raf *raf=(const struct header_raf *)buffer; + /*@ assert \valid_read(raf); */ + /* Fuji */ + const unsigned int cfa_header_offset=be32(raf->cfa_header_offset); + const unsigned int cfa_header_size=be32(raf->cfa_header_size); + const unsigned int cfa_offset=be32(raf->cfa_offset); + const unsigned int cfa_size=be32(raf->cfa_size); + const unsigned int jpg_offset=be32(raf->jpg_offset); + const unsigned int jpg_size=be32(raf->jpg_size); + uint64_t size=0; + if(jpg_size > 0) + { + const uint64_t tmp=(uint64_t)jpg_offset + jpg_size; + if(jpg_offset size) + size=tmp; + } + if(cfa_size > 0) + { + const uint64_t tmp=(uint64_t)cfa_offset + cfa_size; + if(cfa_offset 0) + { + const uint64_t tmp=(uint64_t)cfa_header_offset + cfa_header_size; + if(cfa_header_offsetextension=file_hint_raf.extension; + file_recovery_new->calculated_file_size=size; + /* The size is bigger than calculated_file_size */ + file_recovery_new->file_check=&file_check_size_min; + return 1; +} + +static void register_header_check_raf(file_stat_t *file_stat) +{ + register_header_check(0, "FUJIFILMCCD-RAW ", 16, &header_check_raf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rar.c b/subprojects/lib/src/file_rar.c new file mode 100644 index 0000000..a00bc70 --- /dev/null +++ b/subprojects/lib/src/file_rar.c @@ -0,0 +1,116 @@ +/* + + File: file_rar.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rar) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rar(file_stat_t *file_stat); + +const file_hint_t file_hint_rar= { + .extension="rar", + .description="Rar archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rar +}; + +#define MHD_PASSWORD 0x0080U + +/*@ + @ requires file_recovery->file_check == &file_check_rar15fmt; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_rar15fmt(file_recovery_t *file_recovery) +{ + static const unsigned char rar15fmt_footer[7]={0xc4, 0x3d, 0x7b, 0x00, 0x40, 0x07, 0x00 }; + file_search_footer(file_recovery, rar15fmt_footer, sizeof(rar15fmt_footer), 0); +} + +/*@ + @ requires buffer_size >= 0xb; + @ requires separation: \separated(&file_hint_rar, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rar15fmt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=70; + if((buffer[0xa] & MHD_PASSWORD)==0) + file_recovery_new->file_check=&file_check_rar15fmt; + file_recovery_new->extension=file_hint_rar.extension; + return 1; +} + +/*@ + @ requires file_recovery->file_check == &file_check_rar50fmt; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_rar50fmt(file_recovery_t *file_recovery) +{ + static const unsigned char rar50fmt_footer[8]={0x1d, 0x77, 0x56, 0x51, 0x03, 0x05, 0x04, 0x00 }; + file_search_footer(file_recovery, rar50fmt_footer, sizeof(rar50fmt_footer), 0); +} + +/*@ + @ requires buffer_size >= 0xb; + @ requires separation: \separated(&file_hint_rar, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rar50fmt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=60; + if((buffer[0xa] & MHD_PASSWORD)==0) + file_recovery_new->file_check=&file_check_rar50fmt; + file_recovery_new->extension=file_hint_rar.extension; + return 1; +} + +static void register_header_check_rar(file_stat_t *file_stat) +{ + static const unsigned char rar15fmt_header[7]={0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; + static const unsigned char rar50fmt_header[8]={0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }; + register_header_check(0, rar15fmt_header,sizeof(rar15fmt_header), &header_check_rar15fmt, file_stat); + register_header_check(0, rar50fmt_header,sizeof(rar50fmt_header), &header_check_rar50fmt, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_raw.c b/subprojects/lib/src/file_raw.c new file mode 100644 index 0000000..eb3e1b9 --- /dev/null +++ b/subprojects/lib/src/file_raw.c @@ -0,0 +1,65 @@ +/* + + File: file_raw.c + + Copyright (C) 1998-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_raw) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_raw(file_stat_t *file_stat); + +const file_hint_t file_hint_raw= { + .extension="raw", /* What is the correct extension ? */ + .description="Contax picture RAW", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_raw +}; + +/*@ + @ requires separation: \separated(&file_hint_raw, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_raw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* Contax Kyocera */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_raw.extension; + return 1; +} + +static void register_header_check_raw(file_stat_t *file_stat) +{ + static const unsigned char raw_header_contax[7]= {'A','R','E','C','O','Y','K'}; + register_header_check(25, raw_header_contax,sizeof(raw_header_contax), &header_check_raw, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rdc.c b/subprojects/lib/src/file_rdc.c new file mode 100644 index 0000000..8e6c497 --- /dev/null +++ b/subprojects/lib/src/file_rdc.c @@ -0,0 +1,65 @@ +/* + + File: file_rdc.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rdc) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rdc(file_stat_t *file_stat); + +const file_hint_t file_hint_rdc= { + .extension="rdc", + .description="Rollei picture", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rdc +}; + +/*@ + @ requires separation: \separated(&file_hint_rdc, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rdc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* Rollei */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rdc.extension; + return 1; +} + +static void register_header_check_rdc(file_stat_t *file_stat) +{ + static const unsigned char rdc_header[9]= {'D','S','C','-','I','m','a','g','e'}; + register_header_check(0, rdc_header,sizeof(rdc_header), &header_check_rdc, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_reg.c b/subprojects/lib/src/file_reg.c new file mode 100644 index 0000000..111cde9 --- /dev/null +++ b/subprojects/lib/src/file_reg.c @@ -0,0 +1,144 @@ +/* + + File: file_reg.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_reg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_reg(file_stat_t *file_stat); + +const file_hint_t file_hint_reg= { + .extension="reg", + .description="Windows Registry", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_reg +}; + +struct creg_file_header +{ + uint32_t CREG_ID; /* CREG */ + uint32_t uk1; + uint32_t rgdb_offset; + uint32_t chksum; + uint16_t num_rgdb; + uint16_t flags; + uint32_t uk2; + uint32_t uk3; + uint32_t uk4; +} __attribute__ ((gcc_struct, __packed__)); + +struct rgdb_block +{ + uint32_t RGDB_ID; /* RGDB */ + uint32_t size; + uint32_t unused_size; + uint16_t flags; + uint16_t section; + uint32_t free_offset; /* -1 if there is no free space */ + uint16_t max_id; + uint16_t first_free_id; + uint32_t uk1; + uint32_t chksum; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size > sizeof(struct creg_file_header); + @ requires separation: \separated(&file_hint_reg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_reg_9x(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct creg_file_header*header=(const struct creg_file_header*)buffer; + if(le32(header->rgdb_offset) > buffer_size - 4) + return 0; + { + const struct rgdb_block*block=(const struct rgdb_block*)(buffer+le32(header->rgdb_offset)); + if(memcmp(block,"RGDB",4)!=0) + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=0x1000; + file_recovery_new->extension=file_hint_reg.extension; + return 1; +} + +struct regf_file_header +{ + uint32_t signature; + uint32_t primary_sequence_number; + uint32_t secondary_sequence_number; + int64_t modification_time; + uint32_t major_version; + uint32_t minor_version; + uint32_t file_type; + uint32_t unknown3; + uint32_t root_key_offset; + uint32_t hive_bins_size; + uint32_t unknown4; + uint8_t unknown5[ 64 ]; + uint8_t unknown6[ 396 ]; + uint32_t xor_checksum; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size > sizeof(struct regf_file_header); + @ requires separation: \separated(&file_hint_reg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_reg_nt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct regf_file_header *header=(const struct regf_file_header*)buffer; + if(le32(header->file_type) > 1) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=0x1000; + file_recovery_new->extension=file_hint_reg.extension; + file_recovery_new->time=td_ntfs2utc(le64(header->modification_time)); + return 1; +} + +/* TODO: use information from http://home.eunet.no/pnordahl/ntpasswd/WinReg.txt to get the file size + Registry: regf hbin hbin... +*/ +static void register_header_check_reg(file_stat_t *file_stat) +{ + static const unsigned char reg_header_nt[4] = { 'r','e','g','f'}; + static const unsigned char reg_header_9x[4] = { 'C','R','E','G'}; + register_header_check(0, reg_header_nt,sizeof(reg_header_nt), &header_check_reg_nt, file_stat); + register_header_check(0, reg_header_9x,sizeof(reg_header_9x), &header_check_reg_9x, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_res.c b/subprojects/lib/src/file_res.c new file mode 100644 index 0000000..f83f9b5 --- /dev/null +++ b/subprojects/lib/src/file_res.c @@ -0,0 +1,65 @@ +/* + + File: file_res.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_res) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_res(file_stat_t *file_stat); + +const file_hint_t file_hint_res= { + .extension="res", + .description="Microsoft Visual Studio Resource file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_res +}; + +/*@ + @ requires separation: \separated(&file_hint_res, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_res(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_res.extension; + return 1; +} + +static void register_header_check_res(file_stat_t *file_stat) +{ + static const unsigned char MS_res_header[14]= {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0, 0, 0xFF, 0xFF}; + register_header_check(0, MS_res_header,sizeof(MS_res_header), &header_check_res, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rfp.c b/subprojects/lib/src/file_rfp.c new file mode 100644 index 0000000..b6dd950 --- /dev/null +++ b/subprojects/lib/src/file_rfp.c @@ -0,0 +1,67 @@ +/* + + File: file_rfp.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rfp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rfp(file_stat_t *file_stat); + +const file_hint_t file_hint_rfp= { + .extension="rfp", + .description="RoboForm", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rfp +}; + +/*@ + @ requires separation: \separated(&file_hint_rfp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rfp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rfp.extension; + return 1; +} + +static void register_header_check_rfp(file_stat_t *file_stat) +{ + static const unsigned char rfp_header[10]= { + 'U' , 'R' , 'L' , '3' , ':', 'v' , 'e' , 'r' , + '3' , ':', + }; + register_header_check(0, rfp_header, sizeof(rfp_header), &header_check_rfp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_riff.c b/subprojects/lib/src/file_riff.c new file mode 100644 index 0000000..573c0bb --- /dev/null +++ b/subprojects/lib/src/file_riff.c @@ -0,0 +1,414 @@ +/* + + File: file_riff.c + + Copyright (C) 1998-2005,2007-2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_riff) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "file_riff.h" +#ifdef DEBUG_RIFF +#include "log.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_riff(file_stat_t *file_stat); + +const file_hint_t file_hint_riff= { + .extension="riff", + .description="RIFF audio/video: wav, cdr, avi", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_riff +}; + +typedef struct { + uint32_t dwFourCC; + uint32_t dwSize; +// char data[dwSize]; // contains headers or video/audio data +} riff_chunk_header; + +typedef struct { + uint32_t dwList; + uint32_t dwSize; + uint32_t dwFourCC; +// char data[dwSize-4]; +} riff_list_header_t; + +#ifdef DEBUG_RIFF +static void log_riff_list(const uint64_t offset, const unsigned int depth, const riff_list_header_t *list_header) +{ + unsigned int i; + log_info("0x%08lx - 0x%08lx ", offset, offset + 8 - 1 + le32(list_header->dwSize)); + for(i = 0; i < depth; i++) + log_info(" "); + log_info("%c%c%c%c %c%c%c%c 0x%x\n", + le32(list_header->dwList), + le32(list_header->dwList)>>8, + le32(list_header->dwList)>>16, + le32(list_header->dwList)>>24, + le32(list_header->dwFourCC), + le32(list_header->dwFourCC)>>8, + le32(list_header->dwFourCC)>>16, + le32(list_header->dwFourCC)>>24, + le32(list_header->dwSize)); +} + +static void log_riff_chunk(const uint64_t offset, const unsigned int depth, const riff_list_header_t *list_header) +{ + unsigned int i; + if(le32(list_header->dwSize)==0) + return ; + log_info("0x%08lx - 0x%08lx ", offset, offset + 8 - 1 + le32(list_header->dwSize)); + for(i = 0; i < depth; i++) + log_info(" "); + log_info("%c%c%c%c 0x%x\n", + le32(list_header->dwList), + le32(list_header->dwList)>>8, + le32(list_header->dwList)>>16, + le32(list_header->dwList)>>24, + le32(list_header->dwSize)); +} +#endif + +/*@ + @ requires \valid(fr); + @ requires valid_file_recovery(fr); + @ requires \valid(fr->handle); + @ requires \separated(fr, fr->handle, fr->extension, &errno, &Frama_C_entropy_source); + @ requires end <= PHOTOREC_MAX_FILE_SIZE; + @ ensures valid_file_recovery(fr); + @ ensures \valid(fr->handle); + @ assigns *fr->handle, errno; + @ assigns fr->offset_error; + @ assigns Frama_C_entropy_source; + @*/ +static void check_riff_list(file_recovery_t *fr, const unsigned int depth, const uint64_t start, const uint64_t end) +{ + uint64_t file_size; + if(depth>5) + return; + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant \valid(fr->handle); + @ loop assigns *fr->handle, errno; + @ loop assigns fr->offset_error; + @ loop assigns Frama_C_entropy_source; + @ loop assigns file_size; + @*/ + for(file_size=start; file_size < end;) + { + char buf[sizeof(riff_list_header_t)]; + uint64_t next_fs; + const riff_list_header_t *list_header=(const riff_list_header_t *)&buf; + if(my_fseek(fr->handle, file_size, SEEK_SET)<0) + { + fr->offset_error=file_size; + return; + } + if (fread(buf, sizeof(buf), 1, fr->handle)!=1) + { + fr->offset_error=file_size; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(buf, sizeof(buf)); +#endif + /*@ assert \initialized((char *)list_header+ (0 .. sizeof(riff_list_header_t)-1)); */ + next_fs=file_size + (uint64_t)8 + le32(list_header->dwSize); + if(next_fs > end) + { + fr->offset_error=file_size; + return; + } + /*@ assert valid_file_recovery(fr); */ + if(memcmp(&list_header->dwList, "LIST", 4) == 0) + { +#ifdef DEBUG_RIFF + log_riff_list(file_size, depth, list_header); +#endif + check_riff_list(fr, depth+1, file_size + sizeof(riff_list_header_t), next_fs-1); + } + else + { +#ifdef DEBUG_RIFF + /* It's a chunk */ + log_riff_chunk(file_size, depth, list_header); +#endif + } + file_size = next_fs; + /* align to word boundary */ + file_size = (file_size&1); + } +} + +/*@ + @ requires fr->file_check == &file_check_avi; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns *fr->handle, errno, fr->file_size; + @ assigns fr->offset_error, fr->offset_ok; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_avi(file_recovery_t *fr) +{ + fr->file_size = 0; + fr->offset_error=0; + fr->offset_ok=0; + /*@ + @ loop assigns *fr->handle, errno, fr->file_size; + @ loop assigns fr->offset_error, fr->offset_ok; + @ loop assigns Frama_C_entropy_source; + @*/ + while(fr->file_size!=fr->calculated_file_size) + { + const uint64_t file_size=fr->file_size; + uint64_t calculated_file_size; + char buffer[sizeof(riff_list_header_t)]; + const riff_list_header_t *list_header=(const riff_list_header_t *)&buffer; + if(my_fseek(fr->handle, fr->file_size, SEEK_SET)<0) + { + fr->file_size=0; + return ; + } + if (fread(&buffer, sizeof(buffer), 1, fr->handle)!=1) + { + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(buffer)); +#endif +#ifdef DEBUG_RIFF + log_riff_list(file_size, 0, list_header); +#endif + if(memcmp(&list_header->dwList, "RIFF", 4) != 0) + { + fr->offset_error=fr->file_size; + return; + } + calculated_file_size=file_size + 8 + le32(list_header->dwSize); + if(calculated_file_size > PHOTOREC_MAX_FILE_SIZE) + { + fr->file_size=0; + return; + } + /*@ assert calculated_file_size <= PHOTOREC_MAX_FILE_SIZE; */ + check_riff_list(fr, 1, file_size + sizeof(riff_list_header_t), calculated_file_size - 1); + if(fr->offset_error > 0) + { + fr->file_size=0; + return; + } + fr->file_size=calculated_file_size; + } +} + +/*@ + @ requires file_recovery->data_check==&data_check_avi; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_avi(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 12 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 12; */ + const riff_chunk_header *chunk_header=(const riff_chunk_header*)&buffer[i]; + if(memcmp(&buffer[i], "RIFF", 4)==0 && memcmp(&buffer[i+8], "AVIX", 4)==0) + file_recovery->calculated_file_size += (uint64_t)8 + le32(chunk_header->dwSize); + else + return DC_STOP; + } + return DC_CONTINUE; +} + +data_check_t data_check_avi_stream(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 8; */ + const riff_chunk_header *chunk_header=(const riff_chunk_header*)&buffer[i]; + if(buffer[i+2]!='d' || buffer[i+3]!='b') /* Video Data Binary ?*/ + { +#ifdef DEBUG_RIFF + log_info("data_check_avi_stream stop\n"); +#endif + return DC_STOP; + } + file_recovery->calculated_file_size += (uint64_t)8 + le32(chunk_header->dwSize); +#ifdef DEBUG_RIFF + log_info("data_check_avi_stream %llu\n", (long long unsigned)file_recovery->calculated_file_size); +#endif + } + return DC_CONTINUE; +} + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_riff, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_riff(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t size; + if(!( buffer[8]>='A' && buffer[8]<='Z' && + buffer[9]>='A' && buffer[9]<='Z' && + buffer[10]>='A' && buffer[10]<='Z' && + ((buffer[11]>='A' && buffer[11]<='Z') || buffer[11]==' ' || + (buffer[11]>='0' && buffer[11]<='9')))) + return 0; + if(memcmp(&buffer[8],"NUND",4)==0) + { + /* Cubase Project File */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="cpr"; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->calculated_file_size=(((uint64_t)buffer[4])<<24) + + (((uint64_t)buffer[5])<<16) + (((uint64_t)buffer[6])<<8) + + (uint64_t)buffer[7] + 12; + return 1; + } + size=(uint64_t)buffer[4]+(((uint64_t)buffer[5])<<8)+(((uint64_t)buffer[6])<<16)+(((uint64_t)buffer[7])<<24); + + /* Windows Animated Cursor */ + if(memcmp(&buffer[8],"ACON",4)==0) + { + if(size < 12) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_size; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->calculated_file_size=size; + file_recovery_new->extension="ani"; + return 1; + } + size+=8; + if(memcmp(&buffer[8],"AVI ",4)==0) + { + const riff_list_header_t list_movi={ + .dwList=be32(0x4c495354), /* LIST */ + .dwSize=le32(4), + .dwFourCC=be32(0x6d6f7669) /* movi */ + }; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="avi"; + /* Is it a raw avi stream with Data Binary chunks ? */ + if(size >= sizeof(list_movi) && size <= buffer_size - 4 && + memcmp(&buffer[size - sizeof(list_movi)], &list_movi, sizeof(list_movi)) ==0 && + buffer[size+2]=='d' && + buffer[size+3]=='b') + { + if(file_recovery_new->blocksize < 8) + return 1; + file_recovery_new->data_check=&data_check_avi_stream; + file_recovery_new->file_check=&file_check_size_max; + } + else + { + if(file_recovery_new->blocksize < 12) + return 1; + file_recovery_new->data_check=&data_check_avi; + file_recovery_new->file_check=&file_check_avi; + } + file_recovery_new->calculated_file_size=size; + return 1; + } + if(size < 12) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->calculated_file_size=size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->data_check=&data_check_size; + if(memcmp(&buffer[8],"CDDA",4)==0) + file_recovery_new->extension="cda"; + else if(memcmp(&buffer[8],"CDR",3)==0 || memcmp(&buffer[8],"cdr6",4)==0) + file_recovery_new->extension="cdr"; + else if(memcmp(&buffer[8],"RMP3",4)==0 || memcmp(&buffer[8],"WAVE",4)==0) + file_recovery_new->extension="wav"; + /* MIDI sound file */ + else if(memcmp(&buffer[8],"RMID",4)==0) + file_recovery_new->extension="mid"; + /* MIDI Instruments Definition File */ + else if(memcmp(&buffer[8],"IDF LIST",8)==0) + file_recovery_new->extension="idf"; + /* Autogen http://www.fsdeveloper.com/wiki/index.php?title=AGN_%28FSX%29 */ + else if(memcmp(&buffer[8],"AGNX",4)==0) + file_recovery_new->extension="agn"; + /* http://www.fsdeveloper.com/wiki/index.php?title=MDL_file_format_%28FSX%29 */ + else if(memcmp(&buffer[8],"MDLX",4)==0) + file_recovery_new->extension="mdl"; + /* RFC3625 The QCP File Format and Media Types for Speech Data */ + else if(memcmp(&buffer[8],"QLCM",4)==0) + file_recovery_new->extension="qcp"; + /* https://en.wikipedia.org/wiki/WebP */ + else if(memcmp(&buffer[8],"WEBP",4)==0) + file_recovery_new->extension="webp"; + else + file_recovery_new->extension="avi"; + return 1; +} + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_riff, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rifx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[8],"Egg!",4)==0) + { + /* After Effects */ + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check=&file_check_size_min; + file_recovery_new->calculated_file_size=(uint64_t)buffer[7]+(((uint64_t)buffer[6])<<8)+(((uint64_t)buffer[5])<<16)+(((uint64_t)buffer[4])<<24)+8; + file_recovery_new->extension="aep"; + return 1; + } + return 0; +} + +static void register_header_check_riff(file_stat_t *file_stat) +{ + register_header_check(0, "RIFF", 4, &header_check_riff, file_stat); + register_header_check(0, "RIFX", 4, &header_check_rifx, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_riff.h b/subprojects/lib/src/file_riff.h new file mode 100644 index 0000000..a9e4c1c --- /dev/null +++ b/subprojects/lib/src/file_riff.h @@ -0,0 +1,39 @@ +/* + + File: file_riff.h + + Copyright (C) 2021 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_RIFF_H +#define _FILE_RIFF_H +#ifdef __cplusplus +extern "C" { +#endif + +/*@ + @ requires file_recovery->data_check==&data_check_avi_stream; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +data_check_t data_check_avi_stream(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_rlv.c b/subprojects/lib/src/file_rlv.c new file mode 100644 index 0000000..c4e296b --- /dev/null +++ b/subprojects/lib/src/file_rlv.c @@ -0,0 +1,71 @@ +/* + + File: file_rlv.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rlv) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rlv(file_stat_t *file_stat); + +const file_hint_t file_hint_rlv= { + .extension="rlv", + .description="Revelation password", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rlv +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_rlv, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rlv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[5]!=0 || buffer[9]!=0 || buffer[10]!=0 || buffer[11]!=0) + return 0; + /* Recover version 1 and 2 */ + if(buffer[4]!=1 && buffer[4]!=2) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rlv.extension; + file_recovery_new->min_filesize=12+16; + return 1; +} + +static void register_header_check_rlv(file_stat_t *file_stat) +{ + static const unsigned char rlv_header[4]= { 'r' , 'v' , 'l' , 0x00 }; + register_header_check(0, rlv_header, sizeof(rlv_header), &header_check_rlv, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rm.c b/subprojects/lib/src/file_rm.c new file mode 100644 index 0000000..d720b44 --- /dev/null +++ b/subprojects/lib/src/file_rm.c @@ -0,0 +1,78 @@ +/* + + File: file_rm.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rm(file_stat_t *file_stat); + +const file_hint_t file_hint_rm= { + .extension="rm", + .description="Real Audio", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rm +}; + +struct rm_header +{ + uint32_t type; + uint32_t size; + uint16_t version; + uint32_t file_version; + uint32_t header_nbr; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct rm_header); + @ requires separation: \separated(&file_hint_rm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct rm_header *hdr=(const struct rm_header *)buffer; + if(be32(hdr->header_nbr) < 3) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rm.extension; + return 1; +} + +static void register_header_check_rm(file_stat_t *file_stat) +{ + static const unsigned char rm_header[9] = { '.', 'R', 'M', 'F', 0x00, 0x00, 0x00, 0x12, 0x00}; + register_header_check(0, rm_header,sizeof(rm_header), &header_check_rm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rns.c b/subprojects/lib/src/file_rns.c new file mode 100644 index 0000000..5c7f60f --- /dev/null +++ b/subprojects/lib/src/file_rns.c @@ -0,0 +1,64 @@ +/* + + File: file_rns.c + + Copyright (C) 2006-2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rns) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rns(file_stat_t *file_stat); + +const file_hint_t file_hint_rns= { + .extension="rns", + .description="Reason Audio File", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rns +}; + +/*@ + @ requires separation: \separated(&file_hint_rns, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rns(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rns.extension; + return 1; +} + +static void register_header_check_rns(file_stat_t *file_stat) +{ + static const unsigned char rns_header[] = "Propellerheads Reason Song File"; + register_header_check(0, rns_header,sizeof(rns_header)-1, &header_check_rns, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rpm.c b/subprojects/lib/src/file_rpm.c new file mode 100644 index 0000000..94a3503 --- /dev/null +++ b/subprojects/lib/src/file_rpm.c @@ -0,0 +1,114 @@ +/* + + File: file_rpm.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rpm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rpm(file_stat_t *file_stat); + +const file_hint_t file_hint_rpm= { + .extension="rpm", + .description="RPM package", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rpm +}; + +struct rpmlead { + unsigned char magic[4]; + unsigned char major, minor; + uint16_t type; + uint16_t archnum; + char name[66]; + uint16_t osnum; + uint16_t signature_type; + char reserved[16]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires file_recovery->file_rename==&file_rename_rpm; + @ requires valid_file_rename_param(file_recovery); + @ ensures valid_file_rename_result(file_recovery); + @*/ +static void file_rename_rpm(file_recovery_t *file_recovery) +{ + FILE *file; + struct rpmlead hdr; + if((file=fopen(file_recovery->filename, "rb"))==NULL) + return; + if(fread(&hdr, sizeof(hdr), 1, file)!=1) + { + fclose(file); + return ; + } + fclose(file); + file_rename(file_recovery, &hdr.name, 66, 0, "rpm", 0); +} + +/*@ + @ requires buffer_size >= sizeof(struct rpmlead); + @ requires separation: \separated(&file_hint_rpm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rpm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct rpmlead *hdr=(const struct rpmlead *)buffer; + if(be16(hdr->type)>1) /* 0=bin 1=src */ + return 0; + switch(be16(hdr->signature_type)) + { + case 0: /* RPMSIG_NONE */ + case 1: /* RPMSIG_PGP262_1024 */ + case 5: /* RPMSIG_HEADERSIG */ + break; + default: + return 0; + } + if(hdr->name[0]=='\0') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->min_filesize=(96 + 16 + 16); /* file header + checksum + content header */ + file_recovery_new->extension=file_hint_rpm.extension; + file_recovery_new->file_rename=&file_rename_rpm; + return 1; +} + +static void register_header_check_rpm(file_stat_t *file_stat) +{ + /* RPM v3 */ + static const unsigned char rpm_header[5]= {0xed, 0xab, 0xee, 0xdb, 0x3}; + register_header_check(0, rpm_header,sizeof(rpm_header), &header_check_rpm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rw2.c b/subprojects/lib/src/file_rw2.c new file mode 100644 index 0000000..4309f7b --- /dev/null +++ b/subprojects/lib/src/file_rw2.c @@ -0,0 +1,73 @@ +/* + + File: file_rw2.c + + Copyright (C) 1998-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rw2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "file_tiff.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rw2(file_stat_t *file_stat); + +const file_hint_t file_hint_rw2= { + .extension="rw2", + .description="Panasonic/Leica RAW", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rw2 +}; + +/*@ + @ requires buffer_size >= sizeof(TIFFHeader); + @ requires separation: \separated(&file_hint_rw2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rw2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const TIFFHeader *header=(const TIFFHeader *)buffer; + if(le32(header->tiff_diroff) < sizeof(TIFFHeader)) + return 0; + /* Panasonic/Leica */ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension="rw2"; + file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size); + file_recovery_new->file_check=&file_check_tiff_le; + return 1; +} + +static void register_header_check_rw2(file_stat_t *file_stat) +{ + static const unsigned char rw2_header_panasonic[4]= {'I','I','U','\0'}; + register_header_check(0, rw2_header_panasonic, sizeof(rw2_header_panasonic), &header_check_rw2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_rx2.c b/subprojects/lib/src/file_rx2.c new file mode 100644 index 0000000..f4ef319 --- /dev/null +++ b/subprojects/lib/src/file_rx2.c @@ -0,0 +1,78 @@ +/* + + File: file_rx2.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_rx2) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_rx2(file_stat_t *file_stat); + +const file_hint_t file_hint_rx2= { + .extension="rx2", + .description="Zotope RX 2, Audio Repair Software file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_rx2 +}; + +struct rx2_header +{ + uint32_t magic; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct rx2_header); + @ requires separation: \separated(&file_hint_rx2, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_rx2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct rx2_header *rx2=(const struct rx2_header *)buffer; + if(memcmp(&buffer[8], "REX2HEAD", 8)!=0 || be32(rx2->size) < 4) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_rx2.extension; + file_recovery_new->calculated_file_size=(uint64_t)be32(rx2->size)+8; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_rx2(file_stat_t *file_stat) +{ + static const unsigned char rx2_header[4]= { 'C' , 'A' , 'T' , ' ' }; + register_header_check(0, rx2_header, sizeof(rx2_header), &header_check_rx2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_save.c b/subprojects/lib/src/file_save.c new file mode 100644 index 0000000..3740d89 --- /dev/null +++ b/subprojects/lib/src/file_save.c @@ -0,0 +1,66 @@ +/* + + File: file_save.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_save) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_save(file_stat_t *file_stat); + +const file_hint_t file_hint_save= { + .extension="save", + .description="Assassin's Creed II", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_save +}; + +/*@ + @ requires separation: \separated(&file_hint_save, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_save(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_save.extension; + return 1; +} + +static void register_header_check_save(file_stat_t *file_stat) +{ + static const unsigned char save_header[8]= { + 'A' , 0x00, 'C' , 0x00, 'I' , 0x00, 'I' , 0x00 + }; + register_header_check(8, save_header, sizeof(save_header), &header_check_save, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sdsk.c b/subprojects/lib/src/file_sdsk.c new file mode 100644 index 0000000..198df9f --- /dev/null +++ b/subprojects/lib/src/file_sdsk.c @@ -0,0 +1,75 @@ +/* + + File: file_sdsk.c + + Copyright (C) 2019 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sdsk) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sdsk(file_stat_t *file_stat); + +const file_hint_t file_hint_sdsk= { + .extension="sdsk", + .description="SafeHouse virtual disk", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sdsk +}; + +/*@ + @ requires separation: \separated(&file_hint_sdsk, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sdsk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sdsk.extension; + file_recovery_new->min_filesize=0x1000; + return 1; +} + +static void register_header_check_sdsk(file_stat_t *file_stat) +{ + static const unsigned char sdsk_header[0x48]= { + 'W' , 'A' , 'R' , 'N' , 'I' , 'N' , 'G' , 0x3a, + ' ' , 'T' , 'h' , 'i' , 's' , ' ' , 'f' , 'i' , + 'l' , 'e' , ' ' , 'i' , 's' , ' ' , 'a' , ' ' , + 'S' , 'a' , 'f' , 'e' , 'H' , 'o' , 'u' , 's' , + 'e' , ' ' , 'v' , 'i' , 'r' , 't' , 'u' , 'a' , + 'l' , ' ' , 'd' , 'i' , 's' , 'k' , ' ' , 'v' , + 'o' , 'l' , 'u' , 'm' , 'e' , '.' , 0x0d, 0x0a, + 'h' , 'e' , 'a' , 'd' , 'e' , 'r' , ' ' , 'v' , + 'e' , 'r' , 's' , 'i' , 'o' , 'n' , 0x3a, ' ' , + }; + register_header_check(0, sdsk_header, sizeof(sdsk_header), &header_check_sdsk, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ses.c b/subprojects/lib/src/file_ses.c new file mode 100644 index 0000000..e74d9d7 --- /dev/null +++ b/subprojects/lib/src/file_ses.c @@ -0,0 +1,64 @@ +/* + + File: file_ses.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ses) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ses(file_stat_t *file_stat); + +const file_hint_t file_hint_ses= { + .extension="ses", + .description="Cool Edit/Adobe Audition session", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ses +}; + +/*@ + @ requires separation: \separated(&file_hint_ses, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ses(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_ses.extension; + return 1; +} + +static void register_header_check_ses(file_stat_t *file_stat) +{ + register_header_check(0, "COOLNESS", 8, &header_check_ses, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sgcta.c b/subprojects/lib/src/file_sgcta.c new file mode 100644 index 0000000..13f6681 --- /dev/null +++ b/subprojects/lib/src/file_sgcta.c @@ -0,0 +1,67 @@ +/* + + File: file_sgcta.c + + Copyright (C) 2014 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sgcta) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sgcta(file_stat_t *file_stat); + +const file_hint_t file_hint_sgcta= { + .extension="sgcta", + .description="Ciel", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sgcta +}; + +/*@ + @ requires separation: \separated(&file_hint_sgcta, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sgcta(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sgcta.extension; + return 1; +} + +static void register_header_check_sgcta(file_stat_t *file_stat) +{ + static const unsigned char sgcta_header[16]= { + 'C' , 'a' , 'm' , 'B' , 'F' , 'i' , 'l' , 'e' , + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + register_header_check(0, sgcta_header, sizeof(sgcta_header), &header_check_sgcta, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_shn.c b/subprojects/lib/src/file_shn.c new file mode 100644 index 0000000..bbe7e83 --- /dev/null +++ b/subprojects/lib/src/file_shn.c @@ -0,0 +1,64 @@ +/* + + File: file_shn.c + + Copyright (C) 2013 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_shn) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_shn(file_stat_t *file_stat); + +const file_hint_t file_hint_shn= { + .extension="shn", + .description="Shorten audio file", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_shn +}; + +/*@ + @ requires separation: \separated(&file_hint_shn, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_shn(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_shn.extension; + return 1; +} + +static void register_header_check_shn(file_stat_t *file_stat) +{ + static const unsigned char shn_header[5]= { 'a' , 'j' , 'k' , 'g' , 0x02 }; + register_header_check(0, shn_header, sizeof(shn_header), &header_check_shn, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sib.c b/subprojects/lib/src/file_sib.c new file mode 100644 index 0000000..796bf1e --- /dev/null +++ b/subprojects/lib/src/file_sib.c @@ -0,0 +1,64 @@ +/* + + File: file_sib.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sib) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sib(file_stat_t *file_stat); + +const file_hint_t file_hint_sib= { + .extension="sib", + .description="Sibelius", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sib +}; + +/*@ + @ requires separation: \separated(&file_hint_sib, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sib(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sib.extension; + return 1; +} + +static void register_header_check_sib(file_stat_t *file_stat) +{ + static const unsigned char sib_header[9]= {0x0F, 'S', 'I', 'B', 'E', 'L', 'I', 'U', 'S'}; + register_header_check(0, sib_header,sizeof(sib_header), &header_check_sib, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sig.c b/subprojects/lib/src/file_sig.c new file mode 100644 index 0000000..0ab3a16 --- /dev/null +++ b/subprojects/lib/src/file_sig.c @@ -0,0 +1,686 @@ +/* + + File: file_sig.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if ((!defined(SINGLE_FORMAT) && !defined(__FRAMAC__)) || defined(SINGLE_FORMAT_sig)) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" + +/*@ requires valid_string_s: valid_read_string(s); + @ ensures valid_string(\result); + @*/ +static char *td_strdup(const char *s) +{ + size_t l = strlen(s) + 1; + char *p = MALLOC(l); + /*@ assert valid_read_string(s); */ + memcpy(p, s, l); + p[l-1]='\0'; + /*@ assert valid_read_string(p); */ + return p; +} + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sig(file_stat_t *file_stat); + +const file_hint_t file_hint_sig= { + .extension="custom", + .description="Own custom signatures", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sig +}; + +#define WIN_PHOTOREC_SIG "\\photorec.sig" +#define DOT_PHOTOREC_SIG "/.photorec.sig" +#define PHOTOREC_SIG "photorec.sig" + +typedef struct signature_s signature_t; +struct signature_s +{ + struct td_list_head list; + const char *extension; + unsigned char *sig; + unsigned int sig_size; + unsigned int offset; +}; + +static signature_t signatures={ + .list = TD_LIST_HEAD_INIT(signatures.list) +}; + +#ifndef __FRAMAC__ +static +#endif +int signature_cmp(const struct td_list_head *a, const struct td_list_head *b) +{ + const signature_t *sig_a=td_list_entry_const(a, const signature_t, list); + const signature_t *sig_b=td_list_entry_const(b, const signature_t, list); + int res; + if(sig_a->sig_size==0 && sig_b->sig_size!=0) + return -1; + if(sig_a->sig_size!=0 && sig_b->sig_size==0) + return 1; + res=sig_a->offset-sig_b->offset; + if(res!=0) + return res; + if(sig_a->sig_size<=sig_b->sig_size) + { + res=memcmp(sig_a->sig,sig_b->sig, sig_a->sig_size); + if(res!=0) + return res; + return 1; + } + else + { + res=memcmp(sig_a->sig,sig_b->sig, sig_b->sig_size); + if(res!=0) + return res; + return -1; + } +} + +/*@ + @ requires offset <= PHOTOREC_MAX_SIG_OFFSET; + @ requires 0 < sig_size <= PHOTOREC_MAX_SIG_SIZE; + @ requires offset + sig_size <= PHOTOREC_MAX_SIG_OFFSET; + @ requires \valid_read(sig + (0 .. sig_size-1)); + @ requires valid_read_string(extension); + @*/ +static void signature_insert(const char *extension, unsigned int offset, unsigned char *sig, unsigned int sig_size) +{ + /* FIXME: small memory leak */ + signature_t *newsig=(signature_t*)MALLOC(sizeof(*newsig)); + newsig->extension=extension; + newsig->sig=sig; + newsig->sig_size=sig_size; + newsig->offset=offset; + td_list_add_sorted(&newsig->list, &signatures.list, signature_cmp); +} + +/*@ + @ requires separation: \separated(&file_hint_sig, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sig(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + struct td_list_head *pos; + /*@ loop assigns pos; */ + td_list_for_each(pos, &signatures.list) + { + const signature_t *sig = td_list_entry(pos, signature_t, list); + /*@ assert sig->offset + sig->sig_size <= buffer_size; */ + /*@ assert valid_read_string(sig->extension); */ + if(memcmp(&buffer[sig->offset], sig->sig, sig->sig_size)==0) + { + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=sig->extension; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; + } + } + return 0; +} + +static FILE *open_signature_file(void) +{ +#if defined(__CYGWIN__) || defined(__MINGW32__) + { + char *path; + path = getenv("USERPROFILE"); + if (path == NULL) + path = getenv("HOMEPATH"); + if(path!=NULL) + { + FILE*handle; + char *filename=NULL; + filename=(char*)MALLOC(strlen(path)+strlen(WIN_PHOTOREC_SIG)+1); + strcpy(filename, path); + strcat(filename, WIN_PHOTOREC_SIG); + handle=fopen(filename,"rb"); + if(handle!=NULL) + { + log_info("Open signature file %s\n", filename); + free(filename); + return handle; + } + free(filename); + } + } +#endif +#ifndef DJGPP + { + const char *home = getenv("HOME"); + if (home != NULL) + { + FILE*handle; + char *filename; + size_t len_home; + const size_t len_sig=strlen(DOT_PHOTOREC_SIG); +#ifdef __FRAMAC__ + home="/home/user"; +#endif + len_home=strlen(home); + /*@ assert len_home == strlen(home); */ + filename=(char*)MALLOC(len_home + len_sig + 1); + /*@ assert \valid(filename + (0 .. len_home + len_sig)); */ + strcpy(filename, home); + /*@ assert len_home == strlen(filename); */ + strcat(filename, DOT_PHOTOREC_SIG); + handle=fopen(filename,"rb"); + if(handle!=NULL) + { +#ifndef __FRAMAC__ + log_info("Open signature file %s\n", filename); +#endif + free(filename); + return handle; + } + free(filename); + } + } +#endif + { + FILE *handle=fopen(PHOTOREC_SIG,"rb"); + if(handle!=NULL) + { +#ifndef __FRAMAC__ + log_info("Open signature file %s\n", PHOTOREC_SIG); +#endif + return handle; + } + } + return NULL; +} + +/*@ + @ requires valid_read_string(src); + @ requires \valid(resptr); + @ requires \separated(src+(..), resptr); + @ ensures valid_read_string(\result); + @ assigns *resptr; + @*/ +static char *str_uint_hex(char *src, unsigned int *resptr) +{ + unsigned int res=0; + /*@ + @ loop invariant valid_read_string(src); + @ loop invariant res < 0x10000000; + @ loop assigns src, res; + @*/ + for(;;src++) + { + const char c=*src; + if(c>='0' && c<='9') + res=res*16+(c-'0'); + else if(c>='A' && c<='F') + res=res*16+(c-'A'+10); + else if(c>='a' && c<='f') + res=res*16+(c-'a'+10); + else + { + *resptr=res; + return src; + } + if(res >= 0x10000000) + { + *resptr=res; + return src; + } + } +} + +/*@ + @ requires valid_read_string(src); + @ requires \valid(resptr); + @ requires \separated(src+(..), resptr); + @ ensures valid_read_string(\result); + @ assigns *resptr; + @*/ +static char *str_uint_dec(char *src, unsigned int *resptr) +{ + unsigned int res=0; + /*@ + @ loop invariant valid_read_string(src); + @ loop invariant res < 0x10000000; + @ loop assigns src, res; + @*/ + for(;*src>='0' && *src<='9';src++) + { + res=res*10+(*src)-'0'; + if(res >= 0x10000000) + { + *resptr=res; + return src; + } + } + *resptr=res; + return src; +} + +/*@ + @ requires valid_read_string(src); + @ requires \valid(resptr); + @ requires \separated(src+(..), resptr); + @ ensures valid_read_string(\result); + @ assigns *resptr; + @*/ +static char *str_uint(char *src, unsigned int *resptr) +{ + if(*src=='0' && (*(src+1)=='x' || *(src+1)=='X')) + return str_uint_hex(src+2, resptr); + return str_uint_dec(src, resptr); +} + +/*@ + @ requires valid_register_header_check(file_stat); + @ requires valid_file_stat(file_stat); + @ requires valid_string((char *)pos); + @ ensures valid_string((char *)\result); + @*/ +static unsigned char *parse_signature_file(file_stat_t *file_stat, unsigned char *pos) +{ + const unsigned int signatures_empty=td_list_empty(&signatures.list); +#ifndef __FRAMAC__ + while(*pos!='\0') +#endif + { + /* skip comments */ + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos; + @*/ + while(*pos=='#') + { + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos; + @*/ + while(*pos!='\0' && *pos!='\n') + pos++; + if(*pos=='\0') + return pos; + pos++; + } + /* each line is composed of "extension offset signature" */ + { + char *extension; + unsigned int offset=0; + unsigned char *tmp=NULL; + unsigned int signature_max_size=512; + unsigned int signature_size=0; + { + const char *extension_start=(const char *)pos; + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos; + @*/ + while(*pos!='\0' && !isspace(*pos)) + pos++; + if(*pos=='\0') + return pos; + *pos='\0'; + pos++; + /*@ assert valid_string((char *)pos); */ + extension=td_strdup(extension_start); + if(extension == NULL) + return pos; + /*@ assert valid_read_string(extension); */ + /*@ assert extension==\null || \freeable(extension); */ + } + /* skip space */ + /*@ assert valid_string((char *)pos); */ + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos; + @*/ + while(*pos=='\t' || *pos==' ') + { + /*@ assert *pos == '\t' || *pos== ' '; */ + /*@ assert valid_string((char *)pos); */ + pos++; + /*@ assert valid_string((char *)pos); */ + } + /* read offset */ + pos=(char *)str_uint((char *)pos, &offset); + if(offset > PHOTOREC_MAX_SIG_OFFSET) + { + /* Invalid offset */ + free(extension); + return pos; + } + /*@ assert offset <= PHOTOREC_MAX_SIG_OFFSET; */ + /* read signature */ + tmp=(unsigned char *)MALLOC(signature_max_size); + /*@ assert valid_string((char *)pos); */ +#ifdef __FRAMAC__ + if(*pos!='\n' && *pos!='\0') +#else + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos, signature_size, tmp[0 .. signature_max_size-1]; + @*/ + while(*pos!='\n' && *pos!='\0') +#endif + { + if(signature_size>=signature_max_size) + { +#ifdef __FRAMAC__ + free(tmp); + free(extension); + return pos; +#else + unsigned char *tmp_old=tmp; + signature_max_size*=2; + tmp=(unsigned char *)realloc(tmp, signature_max_size); + if(tmp==NULL) + { + free(tmp_old); + free(extension); + return pos; + } +#endif + } + /*@ assert signature_size < signature_max_size; */ + if(signature_size > PHOTOREC_MAX_SIG_SIZE) + { + free(tmp); + free(extension); + return pos; + } + /*@ assert signature_size <= PHOTOREC_MAX_SIG_SIZE; */ + if(isspace(*pos) || *pos=='\r' || *pos==',') + pos++; + else if(*pos== '\'') + { + pos++; + if(*pos=='\0') + { + free(extension); + free(tmp); + return pos; + } + else if(*pos=='\\') + { + pos++; + if(*pos=='\0') + { + free(extension); + free(tmp); + return pos; + } + else if(*pos=='b') + tmp[signature_size++]='\b'; + else if(*pos=='n') + tmp[signature_size++]='\n'; + else if(*pos=='t') + tmp[signature_size++]='\t'; + else if(*pos=='r') + tmp[signature_size++]='\r'; + else if(*pos=='0') + tmp[signature_size++]='\0'; + else + tmp[signature_size++]=*pos; + pos++; + } + else + { + tmp[signature_size++]=*pos; + pos++; + } + if(*pos!='\'') + { + free(tmp); + free(extension); + return pos; + } + pos++; + } + else if(*pos=='"') + { + pos++; + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos, extension, signature_size, tmp[0 .. signature_max_size-1]; + @*/ + for(; *pos!='"' && *pos!='\0'; pos++) + { + if(signature_size>=signature_max_size) + { +#ifdef __FRAMAC__ + free(tmp); + free(extension); + return pos; +#else + unsigned char *tmp_old=tmp; + signature_max_size*=2; + tmp=(unsigned char *)realloc(tmp, signature_max_size); + if(tmp==NULL) + { + free(tmp_old); + free(extension); + return pos; + } +#endif + } + if(*pos=='\\') + { + pos++; + if(*pos=='\0') + { + free(tmp); + free(extension); + return pos; + } + else if(*pos=='b') + tmp[signature_size++]='\b'; + else if(*pos=='n') + tmp[signature_size++]='\n'; + else if(*pos=='r') + tmp[signature_size++]='\r'; + else if(*pos=='t') + tmp[signature_size++]='\t'; + else if(*pos=='0') + tmp[signature_size++]='\0'; + else + tmp[signature_size++]=*pos; + } + else + tmp[signature_size++]=*pos;; + } + if(*pos!='"') + { + free(tmp); + free(extension); + return pos; + } + pos++; + } + else if(*pos=='0' && (*(pos+1)=='x' || *(pos+1)=='X')) + { + pos+=2; + /*@ assert valid_string((char *)pos); */ +#ifdef __FRAMAC__ + if(signature_size < signature_max_size-1 && + *pos!='\0' && + isxdigit(*pos) && + isxdigit(*(pos+1))) +#else + /*@ + @ loop invariant valid_string((char *)pos); + @ loop assigns pos, signature_size, tmp[0 .. signature_max_size-1]; + @*/ + while(signature_size < signature_max_size-1 && + isxdigit(*pos) && + isxdigit(*(pos+1))) +#endif + { + unsigned int val; + unsigned char c; + c=*pos; + if(c>='0' && c<='9') + val=c-'0'; + else if(c>='A' && c<='F') + val=c-'A'+10; + else if(c>='a' && c<='f') + val=c-'a'+10; +#ifdef __FRAMAC__ + else + { + free(tmp); + free(extension); + return pos; + } +#endif + /*@ assert 0 <= val < 16; */ + /*@ assert valid_string((char *)pos); */ + /*@ assert *pos != 0; */ + pos++; + /*@ assert valid_string((char *)pos); */ + val*=16; + /*@ assert 0 <= val <= 240; */ + c=*pos; + if(c>='0' && c<='9') + val+=c-'0'; + else if(c>='A' && c<='F') + val+=c-'A'+10; + else if(c>='a' && c<='f') + val+=c-'a'+10; +#ifdef __FRAMAC__ + else + { + free(tmp); + free(extension); + return pos; + } +#endif + /*@ assert valid_string((char *)pos); */ + /*@ assert *pos != 0; */ + pos++; + /*@ assert valid_string((char *)pos); */ + tmp[signature_size++]=val; + } + } + else + { + free(tmp); + free(extension); + return pos; + } + /*@ assert valid_string((char *)pos); */ + } + if(*pos=='\n') + pos++; + if(signature_size>0 && offset + signature_size <= PHOTOREC_MAX_SIG_OFFSET ) + { + /*@ assert signature_size > 0; */ + /*@ assert offset + signature_size <= PHOTOREC_MAX_SIG_OFFSET; */ +#ifndef __FRAMAC__ + /* FIXME: Small memory leak */ + unsigned char *signature=(unsigned char *)MALLOC(signature_size); + /*@ assert \valid(signature + (0 .. signature_size - 1)); */ +#ifndef __FRAMAC__ + log_info("register a signature for %s\n", extension); +#endif + memcpy(signature, tmp, signature_size); + /*@ assert \valid_read(signature + (0 .. signature_size - 1)); */ + register_header_check(offset, signature, signature_size, &header_check_sig, file_stat); + if(signatures_empty) + signature_insert(extension, offset, signature, signature_size); +#endif + } + else + { + free(extension); + } + free(tmp); + } + } + return pos; +} + +static void register_header_check_sig(file_stat_t *file_stat) +{ + unsigned char *pos; + char *buffer; + size_t buffer_size; + struct stat stat_rec; + FILE *handle; + handle=open_signature_file(); + if(!handle) + return; +#ifdef __FRAMAC__ + buffer_size=1024*1024; +#else + if(fstat(fileno(handle), &stat_rec)<0 || stat_rec.st_size>100*1024*1024) + { + fclose(handle); + return; + } + buffer_size=stat_rec.st_size; +#endif + buffer=(char *)MALLOC(buffer_size+1); + if(fread(buffer,1,buffer_size,handle)!=buffer_size) + { + fclose(handle); + free(buffer); + return; + } + fclose(handle); +#if defined(__FRAMAC__) + Frama_C_make_unknown(buffer, buffer_size); +#endif + buffer[buffer_size]='\0'; + pos=buffer; + pos=parse_signature_file(file_stat, pos); + if(*pos!='\0') + { +#ifndef __FRAMAC__ + log_warning("Can't parse signature: %s\n", pos); +#endif + } + free(buffer); +} +#endif diff --git a/subprojects/lib/src/file_sit.c b/subprojects/lib/src/file_sit.c new file mode 100644 index 0000000..b504c63 --- /dev/null +++ b/subprojects/lib/src/file_sit.c @@ -0,0 +1,65 @@ +/* + + File: file_sit.c + + Copyright (C) 2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sit) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sit(file_stat_t *file_stat); + +const file_hint_t file_hint_sit= { + .extension="sit", + .description="Mikron image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sit +}; + +/*@ + @ requires separation: \separated(&file_hint_sit, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sit(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sit.extension; + return 1; +} + +static void register_header_check_sit(file_stat_t *file_stat) +{ + static const unsigned char sit_header[14] = { '7','1','0','0',' ','3','.','3','D',' ','7','1','0','0'}; + register_header_check(0, sit_header,sizeof(sit_header), &header_check_sit, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_skd.c b/subprojects/lib/src/file_skd.c new file mode 100644 index 0000000..26331a8 --- /dev/null +++ b/subprojects/lib/src/file_skd.c @@ -0,0 +1,68 @@ +/* + + File: file_skd.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_skd) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_skd(file_stat_t *file_stat); + +const file_hint_t file_hint_skd= { + .extension="skd", + .description="AutoSketch drawing", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_skd +}; + +/*@ + @ requires separation: \separated(&file_hint_skd, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_skd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_skd.extension; + return 1; +} + +static void register_header_check_skd(file_stat_t *file_stat) +{ + static const unsigned char skd_header[29]= { + 'A', 'u', 't', 'o', 'S', 'k', 'e', 't', + 'c', 'h', 0x20, 'd', 'r', 'a', 'w', 'i', + 'n', 'g', 0x20, 'd', 'a', 't', 'a', 'b', + 'a', 's', 'e', 0x0d, 0x0a + }; + register_header_check(0, skd_header,sizeof(skd_header), &header_check_skd, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_skp.c b/subprojects/lib/src/file_skp.c new file mode 100644 index 0000000..81fee5f --- /dev/null +++ b/subprojects/lib/src/file_skp.c @@ -0,0 +1,66 @@ +/* + + File: file_skp.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_skp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_skp(file_stat_t *file_stat); + +const file_hint_t file_hint_skp= { + .extension="skp", + .description="SketchUp", + .max_filesize=500*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_skp +}; + +/*@ + @ requires separation: \separated(&file_hint_skp, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_skp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_skp.extension; + return 1; +} + +static void register_header_check_skp(file_stat_t *file_stat) +{ + static const unsigned char skp_header[32]= { + 0xff, 0xfe, 0xff, 0x0e, 'S', 0x00, 'k', 0x00, 'e', 0x00, 't', 0x00, 'c', 0x00, 'h', 0x00, + 'U', 0x00, 'p', 0x00, ' ', 0x00, 'M', 0x00, 'o', 0x00, 'd', 0x00, 'e', 0x00, 'l', 0x00 }; + register_header_check(0, skp_header,sizeof(skp_header), &header_check_skp, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_snag.c b/subprojects/lib/src/file_snag.c new file mode 100644 index 0000000..c9797b6 --- /dev/null +++ b/subprojects/lib/src/file_snag.c @@ -0,0 +1,79 @@ +/* + + File: file_snag.c + + Copyright (C) 2018 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_snag) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "file_doc.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_snag(file_stat_t *file_stat); + +const file_hint_t file_hint_snag= { + .extension="snag", + .description="Snagit", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_snag +}; + +/*@ + @ requires file_recovery->file_check == &file_check_snag; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @*/ +static void file_check_snag(file_recovery_t *file_recovery) +{ + file_check_doc_aux(file_recovery, 24); +} + +/*@ + @ requires separation: \separated(&file_hint_snag, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_snag(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_snag.extension; + file_recovery_new->file_check=&file_check_snag; + file_recovery_new->min_filesize=24+512; + return 1; +} + +static void register_header_check_snag(file_stat_t *file_stat) +{ + static const unsigned char snag_header[8]= { + 0xcb, 'T' , 'S' , 'C' , 'S' , 'N' , 'A' , 'G' + }; + register_header_check(0, snag_header, sizeof(snag_header), &header_check_snag, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sp3.c b/subprojects/lib/src/file_sp3.c new file mode 100644 index 0000000..ec6f062 --- /dev/null +++ b/subprojects/lib/src/file_sp3.c @@ -0,0 +1,157 @@ +/* + + File: file_sp3.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sp3) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "file_sp3.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sp3(file_stat_t *file_stat); + +const file_hint_t file_hint_sp3= { + .extension="sp3", + .description="Sisporto SP3/SPM", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sp3 +}; + +/*@ assigns \nothing; */ +static uint64_t file_offset_end(const uint32_t offset, const uint32_t len) +{ + return(offset==0 && len==0?0:(uint64_t)offset+len-1); +} + +/*@ + @ requires \valid_read(h); + @ assigns \nothing; + @*/ +static time_t get_time_from_sp3(const struct SP3FileInfo *h) +{ + const unsigned int DataExameAno=le16(h->DataExameAno); + if(DataExameAno>1960 && DataExameAno<2100 && + h->DataExameMes>=1 && h->DataExameMes<=12 && + h->DataExameDia>=1 && h->DataExameDia<=31) + { + /*@ assert DataExameAno>1960; */ + struct tm tm_time; +// memset(&tm_time, 0, sizeof(tm_time)); + tm_time.tm_sec=h->DataExameSegundos; + tm_time.tm_min=h->DataExameMinutos; + tm_time.tm_hour=h->DataExameHora; + tm_time.tm_mday=h->DataExameDia-1; + tm_time.tm_mon=h->DataExameMes-1; + tm_time.tm_year=DataExameAno-1900; + tm_time.tm_isdst = -1; /* unknown daylight saving time */ + return mktime(&tm_time); + } + return (time_t)0; +} + +/*@ + @ requires \valid_read(h); + @ assigns \nothing; + @*/ +static uint64_t get_size_from_sp3(const struct SP3FileInfo *h) +{ + uint64_t filesize=10240; + filesize=td_max(filesize, file_offset_end(le32(h->TimeBaseDelta_POS), le32(h->TimeBaseDelta_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->ExtraInfoFlag_POS), le32(h->ExtraInfoFlag_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->FHRa_POS), le32(h->FHRa_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->FHRb_POS), le32(h->FHRb_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->UC_POS), le32(h->UC_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->FM_POS), le32(h->FM_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->MHR_POS), le32(h->MHR_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Fetal_SpO2_POS_POS), le32(h->Fetal_SpO2_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Fetal_SpO2_POS), le32(h->Fetal_SpO2_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Pressure_POS_POS), le32(h->Pressure_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Pressure_Systolic_BP_POS), le32(h->Pressure_Systolic_BP_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Pressure_Diastolic_BP_POS), le32(h->Pressure_Diastolic_BP_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Pressure_Mean_BP_POS), le32(h->Pressure_Mean_BP_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Pressure_NIBP_MHR_POS), le32(h->Pressure_NIBP_MHR_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Maternal_POS_POS), le32(h->Maternal_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Maternal_SpO2_POS), le32(h->Maternal_SpO2_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Maternal_HR_POS), le32(h->Maternal_HR_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Event_POS_POS), le32(h->Event_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Event_TYPE_POS), le32(h->Event_TYPE_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Event_DESC_POS), le32(h->Event_DESC_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->TQRS_POS_POS), le32(h->TQRS_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->TQRS_Status_POS), le32(h->TQRS_Status_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->TQRS_Value_POS), le32(h->TQRS_Value_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->TQRS_Biphasic_POS), le32(h->TQRS_Biphasic_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Error_POS_POS), le32(h->Error_POS_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Error_TYPE_POS), le32(h->Error_TYPE_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Error_DESC_POS), le32(h->Error_DESC_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->CommBUFFER_POS), le32(h->CommBUFFER_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Prove_FHRa_POS), le32(h->Prove_FHRa_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Prove_FHRb_POS), le32(h->Prove_FHRb_LEN))); + filesize=td_max(filesize, file_offset_end(le32(h->Prove_UC_POS), le32(h->Prove_UC_LEN))); + return filesize; +} + +/*@ + @ requires buffer_size >= sizeof(struct SP3FileInfo); + @ requires separation: \separated(&file_hint_sp3, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sp3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct SP3FileInfo *h=(const struct SP3FileInfo *)buffer; + /*@ assert \valid_read(h); */ + const time_t time=get_time_from_sp3(h); + if(time==0 || time==-1) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sp3.extension; + file_recovery_new->min_filesize=10240; + file_recovery_new->time=time; + file_recovery_new->calculated_file_size=get_size_from_sp3(h); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_sp3(file_stat_t *file_stat) +{ + static const unsigned char sp31_header[8]= { 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static const unsigned char sp32_header[8]= { 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + register_header_check(0, sp31_header, sizeof(sp31_header), &header_check_sp3, file_stat); +#ifndef __FRAMAC__ + register_header_check(0, sp32_header, sizeof(sp32_header), &header_check_sp3, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_sp3.h b/subprojects/lib/src/file_sp3.h new file mode 100644 index 0000000..7ef11d4 --- /dev/null +++ b/subprojects/lib/src/file_sp3.h @@ -0,0 +1,317 @@ +/* + + File: file_sp3.h + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +/* Special thanks to Paulo Sousa for providing the information */ + +#ifndef file_SP3_H +#define file_SP3_H +#ifdef __cplusplus +extern "C" { +#endif + +struct SP3FileInfo +{ + uint8_t Versao; + uint8_t Revisao; + char zzReserved001[6]; + uint16_t DataExameAno; /* 2 bytes ( 9 - 10 ) */ + uint8_t DataExameMes; /* 1 bytes ( 11 ) */ + uint8_t DataExameDia; /* 1 bytes ( 12 ) */ + uint8_t DataExameHora; /* 1 bytes ( 13 ) */ + uint8_t DataExameMinutos; /* 1 bytes ( 14 ) */ + uint8_t DataExameSegundos; /* 1 bytes ( 15 ) */ + uint8_t zzReserved002; /* 1 bytes ( 16 ) */ + uint32_t DuracaoExameMilisegundos; /* 4 bytes ( 17 - 20 ) */ + char zzReserved003[6]; /* 6 bytes ( 21 - 26 ) */ + uint32_t TipoDeMonitorFetal; /* 4 bytes ( 27 - 30 ) */ + char zzReserved004[2]; /* 2 bytes ( 31 - 32 ) */ + + char LocalCod[6]; /* 6 bytes ( 33 - 38 ) */ + + char zzReserved005[2]; /* 2 bytes ( 39 - 40 ) */ + + char LocalNome[128]; /* 128 bytes ( 41 - 168 ) */ + char LocalServicePlace[6]; /* 6 bytes ( 169 - 174 ) */ + + char zzReserved006[2]; /* 2 bytes ( 175 - 176 ) */ + + char FileName[64]; /* 64 bytes ( 177 - 240 ) */ + + char LocalBedOrDevice[4]; /* 4 bytes ( 241 - 244 ) */ + + char zzReserved007[12]; /* 12 bytes ( 245 - 256 ) */ + + char NumeroDoente[16]; /* 16 bytes ( 257 - 272 ) */ + char zzReserved008[8]; /* 8 bytes ( 273 - 280 ) */ + + char NomeDoente[128]; /* 128 bytes ( 281 - 408 ) */ + uint16_t DataNascimentoAnoDoente; /* 2 bytes ( 409 - 410 ) */ + uint8_t DataNascimentoMesDoente; /* 1 bytes ( 411 ) */ + uint8_t DataNascimentoDiaDoente; /* 1 bytes ( 412 ) */ + uint8_t zzReserved009; /* 1 bytes ( 413 ) */ + uint8_t IdadeDoente; /* 1 bytes ( 414 ) */ + char zzReserved010[3]; /* 3 bytes ( 415 - 417 ) */ + uint8_t NumeroFetos; /* 1 bytes ( 418 ) */ + uint8_t zzReserved011; /* 1 bytes ( 419 ) */ + uint8_t NumeroMeses; /* 1 bytes ( 420 ) */ + char zzReserved012[5]; /* 5 bytes ( 421 - 425 ) */ + uint8_t InvalidPointsA; /* 1 bytes ( 426 ) */ + uint8_t zzReserved013; /* 1 bytes ( 427 ) */ + uint8_t GoodConfidencePointsA; /* 1 bytes ( 428 ) */ + uint8_t zzReserved014; /* 1 bytes ( 429 ) */ + uint8_t ExcelentConfidencePointsA; /* 1 bytes ( 430 ) */ + char zzReserved015[3]; /* 3 bytes ( 431 - 433 ) */ + uint8_t InvalidPointsB; /* 1 bytes ( 434 ) */ + uint8_t zzReserved016; /* 1 bytes ( 435 ) */ + uint8_t GoodConfidencePointsB; /* 1 bytes ( 436 ) */ + uint8_t zzReserved017; /* 1 bytes ( 437 ) */ + uint8_t ExcelentConfidencePointsB; /* 1 bytes ( 438 ) */ + + char NumeroEpisodioUrgencia[16]; /* 16 bytes ( 439 - 454 ) */ + char NumeroEpisodioInternamento[16]; /* 16 bytes ( 455 - 470 ) */ + char NumeroEpisodioConsulta[16]; /* 16 bytes ( 471 - 486 ) */ + char NumeroEpisodioAdicional[16]; /* 16 bytes ( 487 - 502 ) */ + + char TipoDePesquisa_OLD; /* 1 bytes ( 503 ) */ + + uint16_t idTipoDePesquisa; /* 2 bytes ( 504 - 505) */ + + char zzReserved018[11]; /* 11 bytes ( 506 - 516 ) */ + + uint32_t ScaleFactorUc; /* 4 bytes ( 517 - 520 ) */ + + uint32_t ProbeTypeFHR_A; /* 4 bytes ( 521 - 524 ) */ + uint32_t ProbeTypeFHR_B; /* 4 bytes ( 525 - 528 ) */ + + uint32_t InternalDataBaseKey_OLD; /* 4 bytes ( 529 - 532) */ + + char zzReserved019[4]; /* 4 bytes ( 533 - 536) */ + + /*------------------------------------------------------------------------*/ + /*Tamanho Antigo*/ + char ExternalDataBaseKey[38]; /* 38 bytes ( 537 - 574) */ + /*------------------------------------------------------------------------*/ + + + /* UID PACIENTE INTERNO*/ + /* {480B57BB-CD71-4D48-A912-000000000000}*/ + /* 123456789 123456789 123456789 12345678 - Tamanho 38*/ + char InternalDataBaseKey__NEW[38]; /* 38 bytes ( 575 - 612) */ + + char zzReserved0201[2]; /* 2 bytes ( 613 - 614) */ + + /* UID EXAME CODE INTERNO */ + /* {480B57BB-CD71-4D48-A000-000000000000} */ + char ExameDataBase_UID[38]; /* 38 bytes ( 612 - 652) */ + + char zzReserved0202[2]; /* 2 bytes ( 653 - 654) */ + + char PartogramaDataBase_UID[38]; /* 38 bytes ( 655 - 692) */ + + char zzReserved0203[8]; /* 30 bytes ( 693 - 700) */ + + uint32_t TimeBaseDelta_POS; /* 4 bytes ( 701 - 704) */ + uint32_t TimeBaseDelta_LEN; /* 4 bytes ( 705 - 708) */ + uint32_t TimeBaseDelta_CRC32; /* 4 bytes ( 709 - 712) */ + char zzReserved021[8]; /* 8 bytes ( 713 - 720) */ + + + uint32_t ExtraInfoFlag_POS; /* 4 bytes ( 721 - 724) */ + uint32_t ExtraInfoFlag_LEN; /* 4 bytes ( 725 - 728) */ + uint32_t ExtraInfoFlag_CRC32; /* 4 bytes ( 729 - 732) */ + char zzReserved022[8]; /* 8 bytes ( 733 - 740) */ + + uint32_t FHRa_POS; + uint32_t FHRa_LEN; + uint32_t FHRa_CRC32; + char zzReserved023[8]; /* 8 bytes ( --- - 760) */ + + uint32_t FHRb_POS; + uint32_t FHRb_LEN; + uint32_t FHRb_CRC32; + char zzReserved024[8]; /* 8 bytes ( --- - 780) */ + + uint32_t UC_POS; + uint32_t UC_LEN; + uint32_t UC_CRC32; + char zzReserved025[8]; /* 8 bytes ( --- - 800) */ + + + uint32_t FM_POS; + uint32_t FM_LEN; + uint32_t FM_CRC32; + char zzReserved026[8]; /* 8 bytes ( --- - 820) */ + + uint32_t MHR_POS; + uint32_t MHR_LEN; + uint32_t MHR_CRC32; + char zzReserved027[8]; /* 8 bytes ( --- - 840) */ + + /*-----------------------------------------------------------------------------------*/ + + uint32_t Fetal_SpO2_POS_POS; + uint32_t Fetal_SpO2_POS_LEN; + uint32_t Fetal_SpO2_POS_CRC32; + char zzReserved028[8]; /* 8 bytes ( --- - 860) */ + + uint32_t Fetal_SpO2_POS; + uint32_t Fetal_SpO2_LEN; + uint32_t Fetal_SpO2_CRC32; + char zzReserved029[8]; /* 8 bytes ( --- - 880) */ + + + /*-----------------------------------------------------------------------------------*/ + + + uint32_t Pressure_POS_POS; + uint32_t Pressure_POS_LEN; + uint32_t Pressure_POS_CRC32; + char zzReserved030[8]; /* 8 bytes ( --- - 900) */ + + uint32_t Pressure_Systolic_BP_POS; + uint32_t Pressure_Systolic_BP_LEN; + uint32_t Pressure_Systolic_BP_CRC32; + char zzReserved031[8]; /* 8 bytes ( --- - 920) */ + + uint32_t Pressure_Diastolic_BP_POS; + uint32_t Pressure_Diastolic_BP_LEN; + uint32_t Pressure_Diastolic_BP_CRC32; + char zzReserved032[8]; /* 8 bytes ( --- - 940) */ + + + uint32_t Pressure_Mean_BP_POS; + uint32_t Pressure_Mean_BP_LEN; + uint32_t Pressure_Mean_BP_CRC32; + char zzReserved033[8]; /* 8 bytes ( --- - 960) */ + + uint32_t Pressure_NIBP_MHR_POS; + uint32_t Pressure_NIBP_MHR_LEN; + uint32_t Pressure_NIBP_MHR_CRC32; + char zzReserved034[8]; /* 8 bytes ( --- - 980) */ + + /*-----------------------------------------------------------------------------------*/ + + uint32_t Maternal_POS_POS; + uint32_t Maternal_POS_LEN; + uint32_t Maternal_POS_CRC32; + char zzReserved035[8]; /* 8 bytes ( ---- - 1000) */ + + uint32_t Maternal_SpO2_POS; + uint32_t Maternal_SpO2_LEN; + uint32_t Maternal_SpO2_CRC32; + char zzReserved036[8]; /* 8 bytes ( ---- - 1020) */ + + uint32_t Maternal_HR_POS; + uint32_t Maternal_HR_LEN; + uint32_t Maternal_HR_CRC32; + char zzReserved037[8]; /* 8 bytes ( ---- - 1040) */ + + /*-----------------------------------------------------------------------------*/ + + uint32_t Event_POS_POS; + uint32_t Event_POS_LEN; + uint32_t Event_POS_CRC32; + char zzReserved038[8]; /* 8 bytes ( ---- - 1060) */ + + uint32_t Event_TYPE_POS; + uint32_t Event_TYPE_LEN; + uint32_t Event_TYPE_CRC32; + char zzReserved039[8]; /* 8 bytes ( ---- - 1080) */ + + uint32_t Event_DESC_POS; + uint32_t Event_DESC_LEN; + uint32_t Event_DESC_CRC32; + char zzReserved040[8]; /* 4 bytes ( ---- - 1100) */ + + /*-----------------------------------------------------------------------------*/ + + uint32_t TQRS_POS_POS; + uint32_t TQRS_POS_LEN; + uint32_t TQRS_POS_CRC32; + char zzReserved041[8]; /* 8 bytes ( ---- - 1120) */ + + uint32_t TQRS_Status_POS; + uint32_t TQRS_Status_LEN; + uint32_t TQRS_Status_CRC32; + char zzReserved042[8]; /* 8 bytes ( ---- - 1140) */ + + uint32_t TQRS_Value_POS; + uint32_t TQRS_Value_LEN; + uint32_t TQRS_Value_CRC32; + char zzReserved043[8]; /* 8 bytes ( ---- - 1160) */ + + uint32_t TQRS_Biphasic_POS; + uint32_t TQRS_Biphasic_LEN; + uint32_t TQRS_Biphasic_CRC32; + char zzReserved044[8]; /* 8 bytes ( ---- - 1180) */ + + /*-----------------------------------------------------------------------------*/ + + uint32_t Error_POS_POS; + uint32_t Error_POS_LEN; + uint32_t Error_POS_CRC32; + char zzReserved045[8]; /* 8 bytes ( ---- - 1200) */ + + uint32_t Error_TYPE_POS; + uint32_t Error_TYPE_LEN; + uint32_t Error_TYPE_CRC32; + char zzReserved046[8]; /* 8 bytes ( ---- - 1220) */ + + uint32_t Error_DESC_POS; + uint32_t Error_DESC_LEN; + uint32_t Error_DESC_CRC32; + char zzReserved047[8]; /* 8 bytes ( ---- - 1240) */ + + /*-----------------------------------------------------------------------------*/ + /*CommBUFFER*/ + + uint32_t CommBUFFER_POS; + uint32_t CommBUFFER_LEN; + uint32_t CommBUFFER_CRC32; + char zzReserved048[8]; /* 8 bytes ( ---- - 1260) */ + + /*-----------------------------------------------------------------------------*/ + + + uint32_t Prove_FHRa_POS; + uint32_t Prove_FHRa_LEN; + uint32_t Prove_FHRa_CRC32; + + char zzReserved049[8]; /* 8 bytes ( ---- - 1280) */ + + uint32_t Prove_FHRb_POS; + uint32_t Prove_FHRb_LEN; + uint32_t Prove_FHRb_CRC32; + + char zzReserved050[8]; /* 8 bytes ( ---- - 1300) */ + + uint32_t Prove_UC_POS; + uint32_t Prove_UC_LEN; + uint32_t Prove_UC_CRC32; + + char zzReserved999[1024*10-1312]; +} __attribute__ ((gcc_struct, __packed__)); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_spe.c b/subprojects/lib/src/file_spe.c new file mode 100644 index 0000000..c875ffe --- /dev/null +++ b/subprojects/lib/src/file_spe.c @@ -0,0 +1,406 @@ +/* + + File: file_spe.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spe) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_spe(file_stat_t *file_stat); + +const file_hint_t file_hint_spe= { + .extension="spe", + .description="WinSpec bitmap image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_spe +}; + +struct header_spe +{ + uint16_t dioden; /* 0 num of physical pixels (X axis) */ + int16_t avgexp; /* 2 number of accumulations per scan */ + /* if > 32767, set to -1 and */ + /* see lavgexp below (668) */ + int16_t exposure; /* 4 exposure time (in milliseconds) */ + /* if > 32767, set to -1 and */ + /* see lexpos below (660) */ + uint16_t xDimDet; /* 6 Detector x dimension of chip */ + int16_t mode; /* 8 timing mode */ + float exp_sec; /* 10 alternative exposure, in secs. */ + int16_t asyavg; /* 14 number of asynchron averages */ + int16_t asyseq; /* 16 number of asynchron sequential */ + uint16_t yDimDet; /* 18 y dimension of CCD or detector. */ + char date[10]; /* 20 date as MM/DD/YY */ + int16_t ehour; /* 30 Experiment Time: Hours (as binary) */ + int16_t eminute; /* 32 Experiment Time: Minutes(as binary)*/ + int16_t noscan; /* 34 number of multiple scans */ + /* if noscan == -1 use lnoscan */ + int16_t fastacc; /* 36 */ + int16_t seconds; /* 38 Experiment Time: Seconds(as binary)*/ + int16_t DetType; /* 40 CCD/DiodeArray type */ + uint16_t xdim; /* 42 actual # of pixels on x axis */ + int16_t stdiode; /* 44 trigger diode */ + float nanox; /* 46 */ + float calibdio[10]; /* 50 calibration diodes */ + char fastfile[16]; /* 90 name of pixel control file */ + int16_t asynen; /* 106 asynchron enable flag 0 = off */ + int16_t datatype; /* 108 experiment data type */ + /* 0 = FLOATING POINT */ + /* 1 = LONG INTEGER */ + /* 2 = INTEGER */ + /* 3 = UNSIGNED INTEGER */ + float calibnan[10]; /* 110 calibration nanometer */ + int16_t BackGrndApplied; /* 150 set to 1 if background sub done */ + int16_t astdiode; /* 152 */ + uint16_t minblk; /* 154 min. # of strips per skips */ + uint16_t numminblk; /* 156 # of min-blocks before geo skps */ + double calibpol[4]; /* 158 calibration coeffients */ + uint16_t ADCrate; /* 190 ADC rate */ + uint16_t ADCtype; /* 192 ADC type */ + uint16_t ADCresolution; /* 194 ADC resolution */ + uint16_t ADCbitAdjust; /* 196 ADC bit adjust */ + uint16_t gain; /* 198 gain */ + char exprem[5][80]; /* 200 experiment remarks */ + uint16_t geometric; /* 600 geometric operations rotate 0x01 */ + /* reverse 0x02, flip 0x04 */ + char xlabel[16]; /* 602 Intensity display string */ + uint16_t cleans; /* 618 cleans */ + uint16_t NumSkpPerCln; /* 620 number of skips per clean. */ + char califile[16]; /* 622 calibration file name (CSMA) */ + char bkgdfile[16]; /* 638 background file name */ + int16_t srccmp; /* 654 number of source comp. diodes */ + uint16_t ydim; /* 656 y dimension of raw data. */ + int16_t scramble; /* 658 0 = scrambled, 1 = unscrambled */ + int32_t lexpos; /* 660 int32_t exposure in milliseconds */ + /* used if exposure set to -1 */ + int32_t lnoscan; /* 664 int32_t num of scans */ + /* used if noscan set to -1 */ + int32_t lavgexp; /* 668 int32_t num of accumulations */ + /* used if avgexp set to -1 */ + char stripfil[16]; /* 672 stripe file (st130) */ + char sw_version[16]; /* 688 Version of SW creating this file */ + int16_t type; /* 704 1 = new120 (Type II) */ + /* 2 = old120 (Type I ) */ + /* 3 = ST130 */ + /* 4 = ST121 */ + /* 5 = ST138 */ + /* 6 = DC131 (PentaMax) */ + /* 7 = ST133 (MicroMax/SpectroMax), */ + /* 8 = ST135 (GPIB) */ + /* 9 = VICCD */ + /* 10 = ST116 (GPIB) */ + /* 11 = OMA3 (GPIB) */ + /* 12 = OMA4 */ + int16_t flatFieldApplied; /* 706 Set to 1 if flat field was applied */ + int16_t spare[8]; /* 708 reserved */ + int16_t kin_trig_mode; /* 724 Kinetics Trigger Mode */ + char dlabel[16]; /* 726 Data label. */ + char empty[686]; /* 742 EMPTY BLOCK FOR EXPANSION */ + float clkspd_us; /* 1428 Vert Clock Speed in micro-sec */ + int16_t HWaccumFlag; /* 1432 set to 1 if accum done by Hardware */ + int16_t StoreSync; /* 1434 set to 1 if store sync used. */ + int16_t BlemishApplied; /* 1436 set to 1 if blemish removal applied */ + int16_t CosmicApplied; /* 1438 set to 1 if cosmic ray removal done */ + int16_t CosmicType; /* 1440 if cosmic ray applied, this is type */ + float CosmicThreshold; /* 1442 Threshold of cosmic ray removal. */ + int32_t NumFrames; /* 1446 number of frames in file. */ + float MaxIntensity; /* 1450 max intensity of data (future) */ + float MinIntensity; /* 1454 min intensity of data (future) */ + char ylabel[16]; /* 1458 y axis label. */ + uint16_t ShutterType; /* 1474 shutter type. */ + float shutterComp; /* 1476 shutter compensation time. */ + uint16_t readoutMode; /* 1480 Readout mode, full,kinetics, etc */ + uint16_t WindowSize; /* 1482 window size for kinetics only. */ + uint16_t clkspd; /* 1484 clock speed for kinetics & */ + /* frame transfer. */ + uint16_t interface_type; /* 1486 computer interface (isa-taxi, */ + /* pci, eisa, etc.) */ + uint32_t ioAdd1; /* 1488 I/O address of inteface card. */ + uint32_t ioAdd2; /* 1492 if more than one address for card. */ + uint32_t ioAdd3; /* 1496 */ + uint16_t intLevel; /* 1500 interrupt level interface card */ + uint16_t GPIBadd; /* 1502 GPIB address (if used) */ + uint16_t ControlAdd; /* 1504 GPIB controller address (if used) */ + uint16_t controllerNum; /* 1506 if multiple controller system will */ + /* have controller # data came from. */ + /* (Future Item) */ + uint16_t SWmade; /* 1508 Software which created this file */ + int16_t NumROI; /* 1510 number of ROIs used. if 0 assume 1 */ + /* 1512 - 1630 ROI information */ + struct ROIinfo { /* */ + uint16_t startx; /* left x start value. */ + uint16_t endx; /* right x value. */ + uint16_t groupx; /* amount x is binned/grouped in hw. */ + uint16_t starty; /* top y start value. */ + uint16_t endy; /* bottom y value. */ + uint16_t groupy; /* amount y is binned/grouped in hw. */ + } ROIinfoblk[10]; /* ROI Starting Offsets: */ + /* ROI 1 = 1512 */ + /* ROI 2 = 1524 */ + /* ROI 3 = 1536 */ + /* ROI 4 = 1548 */ + /* ROI 5 = 1560 */ + /* ROI 6 = 1572 */ + /* ROI 7 = 1584 */ + /* ROI 8 = 1596 */ + /* ROI 9 = 1608 */ + /* ROI 10 = 1620 */ + char FlatField[120]; /* 1632 Flat field file name. */ + char background[120]; /* 1752 Background sub. file name. */ + char blemish[120]; /* 1872 Blemish file name. */ + float file_header_ver; /* 1992 Version of this file header */ + char UserInfo[1000]; /* 1996-2995 user data. */ + int32_t WinView_id; /* 2996 Set to 0x01234567L if file was */ + /* created by WinX */ + + /* START OF X CALIBRATION STRUCTURE */ + + double xcal_offset; /* 3000 offset for absolute data scaling */ + double xcal_factor; /* 3008 factor for absolute data scaling */ + char xcal_current_unit; /* 3016 selected scaling unit */ + char xcal_reserved1; /* 3017 reserved */ + char xcal_string[40]; /* 3018 special string for scaling */ + char xcal_reserved2[40]; /* 3058 reserved */ + char xcal_calib_valid; /* 3098 flag if calibration is valid */ + char xcal_input_unit; /* 3099 current input units for */ + /* "calib_value" */ + char xcal_polynom_unit; /* 3100 linear UNIT and used */ + /* in the "polynom_coeff" */ + char xcal_polynom_order; /* 3101 ORDER of calibration POLYNOM */ + char xcal_calib_count; /* 3102 valid calibration data pairs */ + double xcal_pixel_position[10];/* 3103 pixel pos. of calibration data */ + double xcal_calib_value[10]; /* 3183 calibration VALUE at above pos */ + double xcal_polynom_coeff[6]; /* 3263 polynom COEFFICIENTS */ + double xcal_laser_position; /* 3311 laser wavenumber for relativ WN */ + char xcal_reserved3; /* 3319 reserved */ + unsigned char xcal_new_calib_flag; /* 3320 If set to 200, valid label below */ + char xcal_calib_label[81]; /* 3321 Calibration label (NULL term'd) */ + char xcal_expansion[87]; /* 3402 Calibration Expansion area */ + + /* START OF Y CALIBRATION STRUCTURE */ + + double ycal_offset; /* 3489 offset for absolute data scaling */ + double ycal_factor; /* 3497 factor for absolute data scaling */ + char ycal_current_unit; /* 3505 selected scaling unit */ + char ycal_reserved1; /* 3506 reserved */ + char ycal_string[40]; /* 3507 special string for scaling */ + char ycal_reserved2[40]; /* 3547 reserved */ + char ycal_calib_valid; /* 3587 flag if calibration is valid */ + char ycal_input_unit; /* 3588 current input units for */ + /* "calib_value" */ + char ycal_polynom_unit; /* 3589 linear UNIT and used */ + /* in the "polynom_coeff" */ + char ycal_polynom_order; /* 3590 ORDER of calibration POLYNOM */ + char ycal_calib_count; /* 3591 valid calibration data pairs */ + double ycal_pixel_position[10];/* 3592 pixel pos. of calibration data */ + double ycal_calib_value[10]; /* 3672 calibration VALUE at above pos */ + double ycal_polynom_coeff[6]; /* 3752 polynom COEFFICIENTS */ + double ycal_laser_position; /* 3800 laser wavenumber for relativ WN */ + char ycal_reserved3; /* 3808 reserved */ + unsigned char ycal_new_calib_flag; /* 3809 If set to 200, valid label below */ + char ycal_calib_label[81]; /* 3810 Calibration label (NULL term'd) */ + char ycal_expansion[87]; /* 3891 Calibration Expansion area */ + + /* END OF CALIBRATION STRUCTURES */ + + char Istring[40]; /* 3978 special Intensity scaling string */ + char empty3[80]; /* 4018 empty block to reach 4100 bytes */ + int16_t lastvalue; /* 4098 Always the LAST value in the header */ +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ requires separation: \separated(&file_hint_spe, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_spe.extension); + @ ensures (\result == 1) ==> (file_recovery_new->time == 0); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 4100); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 4100); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ assigns file_recovery_new->filename[0]; + @ assigns file_recovery_new->time; + @ assigns file_recovery_new->file_stat; + @ assigns file_recovery_new->handle; + @ assigns file_recovery_new->file_size; + @ assigns file_recovery_new->location.list.prev; + @ assigns file_recovery_new->location.list.next; + @ assigns file_recovery_new->location.end; + @ assigns file_recovery_new->location.data; + @ assigns file_recovery_new->extension; + @ assigns file_recovery_new->min_filesize; + @ assigns file_recovery_new->calculated_file_size; + @ assigns file_recovery_new->data_check; + @ assigns file_recovery_new->file_check; + @ assigns file_recovery_new->file_rename; + @ assigns file_recovery_new->offset_error; + @ assigns file_recovery_new->offset_ok; + @ assigns file_recovery_new->checkpoint_status; + @ assigns file_recovery_new->checkpoint_offset; + @ assigns file_recovery_new->flags; + @ assigns file_recovery_new->extra; + @ assigns file_recovery_new->data_check_tmp; + @*/ +static int header_check_spe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + uint64_t tmp; + const struct header_spe *spe; + if(buffer_size < 4100) + return 0; + /*@ assert buffer_size >= 4100; */ + spe=(const struct header_spe*)buffer; + /*@ assert \valid_read(spe); */ + if(le32(spe->WinView_id)!=0x01234567L || le16(spe->lastvalue)!=0x5555 || le32(spe->NumFrames)<0) + return 0; + tmp=(uint64_t)le16(spe->xdim)*le16(spe->ydim)*le32(spe->NumFrames); + if((tmp&0xc000000000000000)!=0) + return 0; + tmp*=(le16(spe->datatype)<=1?4:2); + if((tmp&0x8000000000000000)!=0) + return 0; + tmp+=4100; + + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_spe.extension; + file_recovery_new->min_filesize=4100; + file_recovery_new->calculated_file_size=tmp; +#ifndef __FRAMAC__ + log_debug("spe xdim=%u ydim=%u NumFrames=%u datatype=%u size=%llu\n", + le16(spe->xdim), le16(spe->ydim), (unsigned int)le32(spe->NumFrames), le16(spe->datatype), + (long long unsigned) file_recovery_new->calculated_file_size); +#endif + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_spe(file_stat_t *file_stat) +{ + static const unsigned char spe_header[4]= {0x67, 0x45, 0x23, 0x01}; + register_header_check(0xbb4, spe_header,sizeof(spe_header), &header_check_spe, file_stat); +} +#endif + +#if defined(MAIN_spe) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.spe"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + /*@ assert file_recovery.file_stat == \null; */ + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_spe; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_spe(&file_stats); + if(header_check_spe(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.extension == file_hint_spe.extension; */ + /*@ assert file_recovery_new.calculated_file_size >= 4100; */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.min_filesize == 4100; */ + /*@ assert file_recovery_new.file_check == &file_check_size; */ + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */ + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_size == 0; */; + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + { + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + header_check_spe(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_recovery_new.handle=fopen(fn, "rb"); + /*@ assert file_recovery_new.file_check == &file_check_size; */ + if(file_recovery_new.handle!=NULL) + { + file_check_size(&file_recovery_new); + fclose(file_recovery_new.handle); + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_spf.c b/subprojects/lib/src/file_spf.c new file mode 100644 index 0000000..1fd1d83 --- /dev/null +++ b/subprojects/lib/src/file_spf.c @@ -0,0 +1,123 @@ +/* + + File: file_spf.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_spf(file_stat_t *file_stat); + +const file_hint_t file_hint_spf= { + .extension="spf", + .description="ShadowProtect", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_spf +}; + +enum { READ_SIZE=32*512 }; + +/*@ + @ requires file_recovery->file_check == &file_check_spf; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, file_recovery->file_size, Frama_C_entropy_source, errno; + @*/ +static void file_check_spf(file_recovery_t *file_recovery) +{ + file_recovery->file_size=0; + if(my_fseek(file_recovery->handle, 0, SEEK_SET)<0) + { + return; + } + /*@ loop assigns *file_recovery->handle, file_recovery->file_size; + @ loop assigns Frama_C_entropy_source, errno; */ + while(1) + { + int i; + char buffer[READ_SIZE]; + const int taille=fread(buffer,1,READ_SIZE,file_recovery->handle); + if(taille<512 || taille%512!=0) + { + file_recovery->file_size=0; + return ; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(buffer, READ_SIZE); +#endif + /*@ loop assigns i, file_recovery->file_size; */ + for(i=0; ifile_size+=512; + if(file_recovery->file_size >= PHOTOREC_MAX_FILE_SIZE) + { + return; + } + /*@ loop assigns j, is_valid; */ + for(j=0; j<8; j++) + if(buffer[i+j]!=0) + is_valid=1; + /*@ loop assigns j; */ + for(j=8; j<512 && buffer[i+j]==0; j++); + if(is_valid > 0 && j==512) + { + return; + } + } + } +} + +/*@ + @ requires separation: \separated(&file_hint_spf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_spf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_spf.extension; + file_recovery_new->file_check=&file_check_spf; + return 1; +} + +static void register_header_check_spf(file_stat_t *file_stat) +{ + static const unsigned char spf_header[12]= { + 'S', 'P', 'F', 'I', 0x00, 0x02, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00 + }; + register_header_check(0, spf_header,sizeof(spf_header), &header_check_spf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_spss.c b/subprojects/lib/src/file_spss.c new file mode 100644 index 0000000..470f1ab --- /dev/null +++ b/subprojects/lib/src/file_spss.c @@ -0,0 +1,64 @@ +/* + + File: file_spss.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_spss) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_spss(file_stat_t *file_stat); + +const file_hint_t file_hint_spss= { + .extension="sav", + .description="SPSS (Statistical Package for the Social Sciences) saved data", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_spss +}; + +/*@ + @ requires separation: \separated(&file_hint_spss, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_spss(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_spss.extension; + return 1; +} + +static void register_header_check_spss(file_stat_t *file_stat) +{ + /* Check record type + beginning of product name*/ + register_header_check(0, "$FL2@(#) SPSS DATA FILE", 23, &header_check_spss, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sql.c b/subprojects/lib/src/file_sql.c new file mode 100644 index 0000000..16b426f --- /dev/null +++ b/subprojects/lib/src/file_sql.c @@ -0,0 +1,112 @@ +/* + + File: file_sqlite.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sqlite) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sqlite(file_stat_t *file_stat); + +const file_hint_t file_hint_sqlite= { + .extension="sqlite", + .description="SQLite", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sqlite +}; + +/* http://www.sqlite.org/fileformat.html */ +struct db_header +{ + char magic[16]; + uint16_t pagesize; + uint8_t ffwrite; + uint8_t ffread; + uint8_t reserved; + uint8_t max_emb_payload_frac; + uint8_t min_emb_payload_frac; + uint8_t leaf_payload_frac; + uint32_t file_change_counter; + uint32_t filesize_in_page; + uint32_t first_freelist_page; + uint32_t freelist_pages; + uint32_t schema_cookie; + uint32_t schema_format; + uint32_t default_page_cache_size; + uint32_t largest_root_btree; + uint32_t text_encoding; + uint32_t user_version; + uint32_t inc_vacuum_mode; + uint32_t app_id; + char reserved_for_expansion[20]; + uint32_t version_valid_for; + uint32_t version; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct db_header); + @ requires separation: \separated(&file_hint_sqlite, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sqlite(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct db_header *hdr=(const struct db_header *)buffer; + unsigned int pagesize=be16(hdr->pagesize); + const unsigned int filesize_in_page=be32(hdr->filesize_in_page); + /* Must be a power of two between 512 and 32768 inclusive, or the value 1 representing a page size of 65536. */ + if(pagesize==1) + pagesize=65536; + if(pagesize<512 || ((pagesize-1) & pagesize)!=0) + return 0; + reset_file_recovery(file_recovery_new); +#ifdef DJGPP + file_recovery_new->extension="sql"; +#else + file_recovery_new->extension=file_hint_sqlite.extension; +#endif + file_recovery_new->min_filesize=sizeof(struct db_header); + if(filesize_in_page!=0 && be32(hdr->file_change_counter)==be32(hdr->version_valid_for)) + { + file_recovery_new->calculated_file_size=(uint64_t)filesize_in_page * pagesize; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_sqlite(file_stat_t *file_stat) +{ + register_header_check(0, "SQLite format 3", 16, &header_check_sqlite, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_sqm.c b/subprojects/lib/src/file_sqm.c new file mode 100644 index 0000000..2ad2fcf --- /dev/null +++ b/subprojects/lib/src/file_sqm.c @@ -0,0 +1,64 @@ +/* + + File: file_sqm.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_sqm) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_sqm(file_stat_t *file_stat); + +const file_hint_t file_hint_sqm= { + .extension="sqm", + .description="Windows Live Messenger Log File", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_sqm +}; + +/*@ + @ requires separation: \separated(&file_hint_sqm, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_sqm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_sqm.extension; + return 1; +} + +static void register_header_check_sqm(file_stat_t *file_stat) +{ + static const unsigned char sqm_header[6]= { 'M', 'S', 'Q', 'M', 'x', 0x00}; + register_header_check(0, sqm_header, sizeof(sqm_header), &header_check_sqm, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_steuer2014.c b/subprojects/lib/src/file_steuer2014.c new file mode 100644 index 0000000..a116845 --- /dev/null +++ b/subprojects/lib/src/file_steuer2014.c @@ -0,0 +1,119 @@ +/* + + File: file_steuer2014.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_steuer2014) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +#if defined(__FRAMAC__) +#undef HAVE_STRPTIME +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_steuer(file_stat_t *file_stat); +static const char *extension_steuer2014="steuer2014"; +static const char *extension_steuer2015="steuer2015"; +static const char *extension_steuer2016="steuer2016"; +static const char *extension_steuer2017="steuer2017"; +static const char *extension_steuer2018="steuer2018"; +static const char *extension_steuer2019="steuer2019"; +static const char *extension_steuer2020="steuer2020"; + +const file_hint_t file_hint_steuer2014= { + .extension="steuer2014", + .description="Steuer 2014/...", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_steuer +}; + +struct steuer_header +{ + uint8_t magic[8]; + uint32_t version1; + uint32_t version2; + char date_string[0x18]; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct steuer_header); + @ requires separation: \separated(&file_hint_steuer2014, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_steuer(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct steuer_header *h=(const struct steuer_header *)buffer; + struct tm tm_time; + if(h->version1!=h->version2) + return 0; + reset_file_recovery(file_recovery_new); + switch(le32(h->version1)) + { + case 0x00 ... 0x12: + file_recovery_new->extension=extension_steuer2014; + break; + case 0x13: + file_recovery_new->extension=extension_steuer2015; + break; + case 0x14: + file_recovery_new->extension=extension_steuer2016; + break; + case 0x15: + file_recovery_new->extension=extension_steuer2017; + break; + case 0x16: + file_recovery_new->extension=extension_steuer2018; + break; + case 0x17: + file_recovery_new->extension=extension_steuer2019; + break; + default: + file_recovery_new->extension=extension_steuer2020; + break; + } +#ifdef HAVE_STRPTIME + strptime(h->date_string, "%b %d %Y %H:%M:%S", &tm_time); + file_recovery_new->time=mktime(&tm_time); +#endif + return 1; +} + +static void register_header_check_steuer(file_stat_t *file_stat) +{ + static const unsigned char steuer_header[8]= { + 'R' , 0x26, 'S' , 0x1a, 0x11, 0x01, 0x01, 0x00 + }; + register_header_check(0, steuer_header, sizeof(steuer_header), &header_check_steuer, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_stl.c b/subprojects/lib/src/file_stl.c new file mode 100644 index 0000000..cb312a8 --- /dev/null +++ b/subprojects/lib/src/file_stl.c @@ -0,0 +1,83 @@ +/* + + File: file_stl.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_stl) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_stl(file_stat_t *file_stat); + +const file_hint_t file_hint_stl= { + .extension="stl", + .description="Stereolithography CAD (Binary format)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_stl +}; + +/*@ + @ requires buffer_size >= 84; + @ requires separation: \separated(&file_hint_stl, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_stl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* STL Binary format + * http://www.ennex.com/~fabbers/StL.asp */ + unsigned int i; + const uint32_t *fs_ptr=(const uint32_t *)&buffer[80]; + const uint64_t filesize=80+4+(uint64_t)le32(*fs_ptr)*50; + /*@ assert filesize < PHOTOREC_MAX_FILE_SIZE; */ + /*@ loop assigns i; */ + for(i=0; i<80 && buffer[i]!='\0'; i++); + if(i>64) + return 0; + /*@ loop assigns i; */ + for(i++; i<80 && buffer[i]==' '; i++); + if(i!=80) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_stl.extension; + file_recovery_new->calculated_file_size=filesize; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +static void register_header_check_stl(file_stat_t *file_stat) +{ + /* Note: STL Ascii format is recovered in file_txt.c */ + register_header_check(0, "solid ", 6, &header_check_stl, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_stu.c b/subprojects/lib/src/file_stu.c new file mode 100644 index 0000000..635dd64 --- /dev/null +++ b/subprojects/lib/src/file_stu.c @@ -0,0 +1,65 @@ +/* + + File: file_stuffit.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_stuffit) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_stuffit(file_stat_t *file_stat); + +const file_hint_t file_hint_stuffit= { + .extension="sit", + .description="StuffIt Archive", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_stuffit +}; + +/*@ + @ requires separation: \separated(&file_hint_stuffit, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_stuffit(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_stuffit.extension; + return 1; +} + +static void register_header_check_stuffit(file_stat_t *file_stat) +{ + static const unsigned char stuffit_header[7] = { 'S', 't', 'u', 'f', 'f', 'I', 't'}; + register_header_check(0, stuffit_header,sizeof(stuffit_header), &header_check_stuffit, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_studio.c b/subprojects/lib/src/file_studio.c new file mode 100644 index 0000000..94d8c40 --- /dev/null +++ b/subprojects/lib/src/file_studio.c @@ -0,0 +1,77 @@ +/* + + File: file_studio.c + + Copyright (C) 2016 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_studio) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_studio(file_stat_t *file_stat); + +const file_hint_t file_hint_studio= { + .extension="studio", + .description="Silhouette Cameo cutting machine", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_studio +}; + +struct silhouette_header +{ + char magic[12]; + char unk[2]; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires buffer_size >= sizeof(struct silhouette_header); + @ requires separation: \separated(&file_hint_studio, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_studio(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct silhouette_header *hdr=(const struct silhouette_header *)buffer; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_studio.extension; + file_recovery_new->calculated_file_size=(uint64_t)le32(hdr->size)+77; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + file_recovery_new->min_filesize=77; + return 1; +} + +static void register_header_check_studio(file_stat_t *file_stat) +{ + register_header_check(0, "silhouette04;", 13, &header_check_studio, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_swf.c b/subprojects/lib/src/file_swf.c new file mode 100644 index 0000000..7253fcb --- /dev/null +++ b/subprojects/lib/src/file_swf.c @@ -0,0 +1,372 @@ +/* + + File: file_swf.c + + Copyright (C) 2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_swf) +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(__FRAMAC__) || defined(SINGLE_FORMAT) || defined(MAIN_photorec) || defined(MAIN_fidentify) +#undef HAVE_ZLIB_H +#undef HAVE_LIBZ +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#ifdef HAVE_ZLIB_H +#include +#endif +#include "filegen.h" +#include "common.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +static const char *extension_swc="swc"; +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_swf(file_stat_t *file_stat); + +const file_hint_t file_hint_swf= { + .extension="swf", + .description="Macromedia Flash (Compiled)", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_swf +}; + +struct swf_header +{ + char magic[3]; + unsigned char version; + uint32_t size; +} __attribute__ ((gcc_struct, __packed__)); + +struct swfz_header +{ + char magic[3]; + unsigned char version; + uint32_t scriptLen; + uint32_t compressedLen; + uint8_t LZMA_props[5]; +} __attribute__ ((gcc_struct, __packed__)); +// followed by LZMA data and 6 bytes for LZMA end marker +// scriptLen is the uncompressed length of the SWF data. Includes 4 bytes SWF header and +// 4 bytes for scriptLen it +// compressedLen does not include header (4+4+4 bytes) or lzma props (5 bytes) +// compressedLen does include LZMA end marker (6 bytes) + +/*@ + @ requires \valid(data); + @ requires \valid_read(*data + (0..3)); + @ requires \valid(offset_bit); + @ requires 0 <= *offset_bit <= 7; + @ requires 2 <= nbit <= 31; + @ requires separation: \separated(data, offset_bit, *data + (0..(nbit+*offset_bit)/8)); + @ ensures 0 <= *offset_bit <= 7; + @ assigns *data, *offset_bit; + @*/ +static int read_SB(const unsigned char **data, unsigned int *offset_bit, unsigned int nbit) +{ + int res=0; + const unsigned int sign=((**data) >>(7 - (*offset_bit)))&1; + /*@ + loop unroll 31; + loop assigns nbit, *offset_bit, *data, res; + loop variant nbit; + */ + while(nbit>1) + { + /*@ assert 0 <= *offset_bit <= 7; */ + (*offset_bit)++; + /*@ assert 1 <= *offset_bit <= 8; */ + if(*offset_bit==8) + { + (*data)++; + *offset_bit=0; + } + /*@ assert 0 <= *offset_bit <= 7; */ + res=(res<<1)|((**data>>(7 - *offset_bit))&1); + nbit--; + } + if(sign) + res=-res; + return res; +} + +/*@ + @ requires buffer_size >= 512; + @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size_max); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_swc); + @ assigns *file_recovery_new; + @*/ +static int header_check_swfc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct swf_header *hdr=(const struct swf_header *)buffer; + /* Compressed flash with Z_DEFLATED */ + if(!(buffer[3]>=6 && buffer[3]<=20 && (buffer[8]&0x0f)==8)) + return 0; + if(le32(hdr->size) < 9) + return 0; +#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) + { + const unsigned char *buffer_compr=buffer+8; + unsigned char buffer_uncompr[512]; + const unsigned int comprLen=(buffer_size<512?buffer_size:512)-8; + const unsigned int uncomprLen=512-1; + int err; + const unsigned char *data=(const unsigned char *)&buffer_uncompr; + unsigned int offset_bit=5; + unsigned int nbit; + /* a twip is 1/20th of a logical pixel */ + int Xmin, Xmax, Ymin, Ymax; + z_stream d_stream; /* decompression stream */ + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = (Bytef*)buffer_compr; + d_stream.avail_in = 0; + d_stream.next_out = buffer_uncompr; + + err = inflateInit(&d_stream); + if(err!=Z_OK) + return 0; + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if(err!=Z_OK) + { + /* Decompression has failed, free ressources */ + inflateEnd(&d_stream); + return 0; + } + } + err = inflateEnd(&d_stream); + if(err!=Z_OK) + { + return 0; + } + /* Probably too small to be a file */ + if(d_stream.total_out < 16) + return 0; + nbit=(*data)>>3; + /* assert nbit <= 31; */ + if(nbit<=1) + return 0; + /* assert 2 <= nbit <= 31; */ + Xmin=read_SB(&data, &offset_bit, nbit); + Xmax=read_SB(&data, &offset_bit, nbit); + Ymin=read_SB(&data, &offset_bit, nbit); + Ymax=read_SB(&data, &offset_bit, nbit); + if(Xmin!=0 || Ymin!=0 || Xmax<=0 || Ymax<=0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=extension_swc; + file_recovery_new->calculated_file_size=le32(hdr->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size_max; + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(struct swf_header); + @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_swf.extension); + @ assigns *file_recovery_new; + @*/ +static int header_check_swf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + /* http://www.adobe.com/go/swfspec */ + const struct swf_header *hdr=(const struct swf_header *)buffer; + const unsigned char *data=&buffer[8]; + unsigned int offset_bit=5; + unsigned int nbit; + /* a twip is 1/20th of a logical pixel */ + int Xmin, Xmax, Ymin, Ymax; + if(!(buffer[3]>=3 && buffer[3]<=20)) + return 0; + if(le32(hdr->size) < 9) + return 0; + nbit=(*data)>>3; + if(nbit<=1) + return 0; + Xmin=read_SB(&data, &offset_bit, nbit); + Xmax=read_SB(&data, &offset_bit, nbit); + Ymin=read_SB(&data, &offset_bit, nbit); + Ymax=read_SB(&data, &offset_bit, nbit); + if(Xmin!=0 || Ymin!=0 || Xmax<=0 || Ymax<=0) + return 0; +#if 0 + data=&buffer[8+(5+4*nbit+8-1)/8]; +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_swf.extension; + file_recovery_new->calculated_file_size=le32(hdr->size); + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(struct swfz_header); + @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size_max); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_swf.extension); + @ assigns *file_recovery_new; + @*/ +static int header_check_swfz(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct swfz_header *hdr=(const struct swfz_header *)buffer; + const unsigned int compressedLen=le32(hdr->compressedLen); + const unsigned int scriptLen=le32(hdr->scriptLen); + /* ZWS file compression is permitted in SWF 13 or later only. */ + if(hdr->version < 13 || hdr->version > 50 || scriptLen < 8 || compressedLen < 6) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_swf.extension; + file_recovery_new->calculated_file_size=(uint64_t)4+4+4+5+compressedLen; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size_max; + return 1; +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_swf(file_stat_t *file_stat) +{ + register_header_check(0, "CWS", 3, &header_check_swfc, file_stat); + register_header_check(0, "FWS", 3, &header_check_swf, file_stat); + register_header_check(0, "ZWS", 3, &header_check_swfz, file_stat); +} +#endif + +#if defined(MAIN_swf) +#define BLOCKSIZE 65536u +int main(void) +{ + const char fn[] = "recup_dir.1/f0000000.swf"; + unsigned char buffer[BLOCKSIZE]; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + /*@ assert file_recovery.file_stat == \null; */ + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_swf; + file_stats.not_recovered=0; + file_stats.recovered=0; + register_header_check_swf(&file_stats); + if(header_check_swf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1 || + header_check_swfc(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1 || + header_check_swfz(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.extension == file_hint_swf.extension || file_recovery_new.extension == extension_swc; */ + /*@ assert file_recovery_new.file_size == 0; */ + /*@ assert file_recovery_new.file_check == &file_check_size || file_recovery_new.file_check == &file_check_size_max; */ + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */ + { + unsigned char big_buffer[2*BLOCKSIZE]; + data_check_t res_data_check=DC_CONTINUE; + memset(big_buffer, 0, BLOCKSIZE); + memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE); + /*@ assert file_recovery_new.data_check == &data_check_size; */ + /*@ assert file_recovery_new.file_size == 0; */; + /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */; + res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + file_recovery_new.file_size+=BLOCKSIZE; + if(res_data_check == DC_CONTINUE) + { + memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE); +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE); +#endif + data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new); + } + } + { + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + header_check_swf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + file_recovery_new.handle=fopen(fn, "rb"); + /*@ assert file_recovery_new.file_check == &file_check_size || file_recovery_new.file_check == &file_check_size_max; */ + if(file_recovery_new.handle!=NULL) + { + if(file_recovery_new.file_check == &file_check_size) + file_check_size(&file_recovery_new); + else + file_check_size_max(&file_recovery_new); + fclose(file_recovery_new.handle); + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_tar.c b/subprojects/lib/src/file_tar.c new file mode 100644 index 0000000..35001ca --- /dev/null +++ b/subprojects/lib/src/file_tar.c @@ -0,0 +1,141 @@ +/* + + File: file_tar.c + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tar) || defined(MAIN_photorec) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" +#include "file_tar.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tar(file_stat_t *file_stat); +static const unsigned char tar_header_gnu[6] = { 'u', 's', 't', 'a', 'r', 0x00 }; +static const unsigned char tar_header_posix[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0x00 }; + +const file_hint_t file_hint_tar = { + .extension = "tar", + .description = "tar archive", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_tar +}; + +/*@ + @ requires \valid_read(h); + @ assigns \nothing; + @*/ +static int is_valid_checksum_format(const struct tar_posix_header *h) +{ + unsigned int i; + int space_allowed = 1; + int all_null = 1; + /* No checksum ? */ + /*@ + @ loop assigns i,all_null; + @*/ + for(i = 0; i < 8; i++) + if(h->chksum[i] != 0) + all_null = 0; + if(all_null != 0) + return 1; + /* + * Checksum should be stored as a six digit octal number with leading zeroes followed by a NUL and then a space. + * Various implementations do not adhere to this format, try to handle them + */ + /*@ + @ loop assigns i,space_allowed; + @*/ + for(i = 0; i < 6; i++) + { + if(h->chksum[i] >= '0' || h->chksum[i] <= '7') + { + space_allowed = 0; + continue; + } + if(h->chksum[i] == ' ') + { + if(space_allowed == 0) + return 0; + } + else + return 0; + } + if(h->chksum[6] == 0 || h->chksum[7] == ' ') + return 1; + if((h->chksum[6] >= '0' || h->chksum[6] <= '7') && h->chksum[7] == ' ') + return 1; + return 0; +} + +int is_valid_tar_header(const struct tar_posix_header *h) +{ + /* Do not remove this check. */ + if(memcmp(&h->magic, tar_header_gnu, sizeof(tar_header_gnu)) != 0 && memcmp(&h->magic, tar_header_posix, sizeof(tar_header_posix)) != 0) + return 0; + if(is_valid_checksum_format(h) == 0) + return 0; + return 1; +} + +/*@ + @ requires buffer_size >= sizeof(struct tar_posix_header); + @ requires separation: \separated(&file_hint_tar, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tar(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct tar_posix_header *h = (const struct tar_posix_header *)buffer; + if(is_valid_tar_header(h) == 0) + return 0; + if(file_recovery->file_stat != NULL && file_recovery->file_stat->file_hint == &file_hint_tar) + { + /* header_ignored(file_recovery_new); is useless as there is no file check */ + return 0; + } + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_tar.extension; + file_recovery_new->min_filesize = 512; + /*@ assert valid_file_recovery(file_recovery_new); */ + return 1; +} + +/*@ + @ requires valid_register_header_check(file_stat); + @*/ +static void register_header_check_tar(file_stat_t *file_stat) +{ + register_header_check(0x101, tar_header_gnu, sizeof(tar_header_gnu), &header_check_tar, file_stat); +#ifndef __FRAMAC__ + register_header_check(0x101, tar_header_posix, sizeof(tar_header_posix), &header_check_tar, file_stat); +#endif +} +#endif diff --git a/subprojects/lib/src/file_tar.h b/subprojects/lib/src/file_tar.h new file mode 100644 index 0000000..85e02c4 --- /dev/null +++ b/subprojects/lib/src/file_tar.h @@ -0,0 +1,58 @@ +/* + + File: file_tar.h + + Copyright (C) 1998-2005,2007 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_TAR_H +#define _FILE_TAR_H +#ifdef __cplusplus +extern "C" { +#endif + +struct tar_posix_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +/*@ + @ requires \valid_read(h); + @ assigns \nothing; + @*/ +int is_valid_tar_header(const struct tar_posix_header *h); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_tax.c b/subprojects/lib/src/file_tax.c new file mode 100644 index 0000000..ed29356 --- /dev/null +++ b/subprojects/lib/src/file_tax.c @@ -0,0 +1,65 @@ +/* + + File: file_tax.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tax) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tax(file_stat_t *file_stat); + +const file_hint_t file_hint_tax= { + .extension="tax", + .description="Turbo Tax", + .max_filesize=100*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_tax +}; + +/*@ + @ requires separation: \separated(&file_hint_tax, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tax(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tax.extension; + return 1; +} + +static void register_header_check_tax(file_stat_t *file_stat) +{ + static const unsigned char tax_header[6]= { 'T', 'T', 'F', 'N', 0x01, 0x01}; + register_header_check(0, tax_header, sizeof(tax_header), &header_check_tax, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_tg.c b/subprojects/lib/src/file_tg.c new file mode 100644 index 0000000..579a1ac --- /dev/null +++ b/subprojects/lib/src/file_tg.c @@ -0,0 +1,72 @@ +/* + + File: file_tg.c + + Copyright (C) 2015 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tg) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tg(file_stat_t *file_stat); + +const file_hint_t file_hint_tg= { + .extension="tg", + .description="Tux Guitar 1.2", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_tg +}; + +/*@ + @ requires separation: \separated(&file_hint_tg, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tg.extension; + return 1; +} + +static void register_header_check_tg(file_stat_t *file_stat) +{ + static const unsigned char tg_header[0x38]= { + 0x1b, 0x00, 'T' , 0x00, 'u' , 0x00, 'x' , 0x00, + 'G' , 0x00, 'u' , 0x00, 'i' , 0x00, 't' , 0x00, + 'a' , 0x00, 'r' , 0x00, ' ' , 0x00, 'F' , 0x00, + 'i' , 0x00, 'l' , 0x00, 'e' , 0x00, ' ' , 0x00, + 'F' , 0x00, 'o' , 0x00, 'r' , 0x00, 'm' , 0x00, + 'a' , 0x00, 't' , 0x00, ' ' , 0x00, 0x2d, 0x00, + ' ' , 0x00, '1' , 0x00, '.' , 0x00, '2' , 0x00, + }; + register_header_check(0, tg_header, sizeof(tg_header), &header_check_tg, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_tib.c b/subprojects/lib/src/file_tib.c new file mode 100644 index 0000000..c044ce3 --- /dev/null +++ b/subprojects/lib/src/file_tib.c @@ -0,0 +1,168 @@ +/* + + File: file_tib.c + + Copyright (C) 2007-2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tib) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tib(file_stat_t *file_stat); + +const file_hint_t file_hint_tib= { + .extension="tib", + .description="Acronis True Image", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_tib +}; + +static const unsigned char tib2_footer[7]= {0x00, 0x00, 0x20, 0xa2, 0xb9, 0x24, 0xce}; + +/*@ + @ requires file_recovery->data_check==&data_check_tib2; + @ requires valid_data_check_param(buffer, buffer_size, file_recovery); + @ ensures valid_data_check_result(\result, file_recovery); + @ assigns file_recovery->calculated_file_size; + @*/ +static data_check_t data_check_tib2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery) +{ + /*@ loop assigns file_recovery->calculated_file_size; */ + while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size && + file_recovery->calculated_file_size + 512 <= file_recovery->file_size + buffer_size/2) + { + const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size; + /*@ assert 0 <= i <= buffer_size - 512; */ + file_recovery->calculated_file_size+=512; + if(memcmp(&buffer[i + 512 - sizeof(tib2_footer)], tib2_footer, sizeof(tib2_footer))==0) + return DC_STOP; + } + return DC_CONTINUE; +} + +/*@ + @ requires file_recovery->file_check == &file_check_tib2; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_tib2(file_recovery_t *file_recovery) +{ + int64_t file_size; + if(file_recovery->calculated_file_size < 512) + { + file_recovery->file_size=0; + return ; + } + file_size=file_recovery->calculated_file_size-512; + file_recovery->file_size = file_recovery->calculated_file_size; + { + char buffer[512]; + if(my_fseek(file_recovery->handle, file_size, SEEK_SET) < 0 || + fread(buffer, 1, 512, file_recovery->handle) != 512) + { + file_recovery->file_size=0; + return; + } +#ifdef __FRAMAC__ + Frama_C_make_unknown(buffer, 512); +#endif + if(memcmp(&buffer[512 - sizeof(tib2_footer)], tib2_footer, sizeof(tib2_footer))==0) + { + return; + } + } + +/*@ + @ loop assigns *file_recovery->handle, errno, file_size; + @ loop assigns Frama_C_entropy_source; + @*/ + for(; file_size>0; file_size-=512) + { + unsigned int i; + char buffer[512]; + if(my_fseek(file_recovery->handle, file_size, SEEK_SET) < 0 || + fread(buffer, 1, 512, file_recovery->handle) != 512) + { + file_recovery->file_size=0; + return; + } + /*@ loop assigns i; */ + for(i=0; i<512 && buffer[i]==0; i++); + if(i!=512) + { + file_recovery->file_size=file_size + 512; + return ; + } + } +} + +/*@ + @ requires separation: \separated(&file_hint_tib, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tib(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tib.extension; + return 1; +} + +/*@ + @ requires separation: \separated(&file_hint_tib, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tib2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tib.extension; + if(file_recovery_new->blocksize < 512) + return 1; + file_recovery_new->file_check=&file_check_tib2; + file_recovery_new->data_check=&data_check_tib2; + return 1; +} + +static void register_header_check_tib(file_stat_t *file_stat) +{ + static const unsigned char tib_header[4]= { 0xb4, 0x6e, 0x68, 0x44}; + static const unsigned char tib2_header[7]= { 0xce, 0x24, 0xb9, 0xa2, 0x20, 0x00, 0x00}; + register_header_check(0, tib_header,sizeof(tib_header), &header_check_tib, file_stat); + register_header_check(0, tib2_header,sizeof(tib2_header), &header_check_tib2, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_tiff.c b/subprojects/lib/src/file_tiff.c new file mode 100644 index 0000000..a5f00cf --- /dev/null +++ b/subprojects/lib/src/file_tiff.c @@ -0,0 +1,197 @@ +/* + + File: file_tiff.c + + Copyright (C) 1998-2005,2007-2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tiff) || defined(SINGLE_FORMAT_jpg) || defined(SINGLE_FORMAT_rw2) || defined(SINGLE_FORMAT_orf) || defined(SINGLE_FORMAT_wdp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "file_tiff.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tiff(file_stat_t *file_stat); + +const file_hint_t file_hint_tiff= { + .extension="tif", + .description="Tag Image File Format and some raw file formats (pef/nef/dcr/sr2/cr2)", + .max_filesize=1024*1024*1024, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_tiff +}; + +unsigned int tiff_type2size(const unsigned int type) +{ + switch(type) + { + case 1: /* TIFF_BYTE */ + case 2: /* TIFF_ASCII */ + case 6: /* TIFF_SBYTE */ + case 7: /* TIFF_UNDEFINED */ + return 1; + case 3: /* TIFF_SHORT */ + case 8: /* TIFF_SSHORT */ + return 2; + case 4: /* TIFF_LONG */ + case 9: /* TIFF_SLONG */ + case 11: /* TIFF_FLOAT */ + case 13: /* TIFF_IFD */ + return 4; + case 5: /* TIFF_RATIONAL */ + case 10: /* TIFF_SRATIONAL */ + case 12: /* TIFF_DOUBLE */ + case 16: /* TIFF_LONG8 */ + case 17: /* TIFF_SLONG8 */ + case 18: /* TIFF_IFD8 */ + return 8; +#if 0 + case 14: /* TIFF_UNICODE */ + case 15: /* TIFF_COMPLEX */ +#endif + default: + return 1; + } +} + +#ifdef DEBUG_TIFF +const char *tag_name(unsigned int tag) +{ + switch(tag) + { + case TIFFTAG_IMAGEDESCRIPTION: + return "IMAGEDESCRIPTION"; + case TIFFTAG_MAKE: + return "MAKE"; + case TIFFTAG_MODEL: + return "TIFFTAG_MODEL"; + case TIFFTAG_SUBIFD: + return "SUBIFD"; + case TIFFTAG_EXIFIFD: + return "EXIFIFD"; + case TIFFTAG_STRIPOFFSETS: + return "STRIPOFFSETS"; + case TIFFTAG_STRIPBYTECOUNTS: + return "STRIPBYTECOUNTS"; + case TIFFTAG_KODAKIFD: + return "KODAKIFD"; + case TIFFTAG_JPEGIFOFFSET: + return "JPEGIFOFFSET"; + case TIFFTAG_JPEGIFBYTECOUNT: + return "JPEGIFBYTECOUNT"; + case TIFFTAG_DNGPRIVATEDATA: + return "DNGPRIVATEDATA"; + case EXIFTAG_MAKERNOTE: + return "EXIFTAG_MAKERNOTE"; + case TIFFTAG_PRINTIM: + return "PrintIM"; + case TIFFTAG_IMAGEOFFSET: + return "IMAGEOFFSET"; + case TIFFTAG_IMAGEBYTECOUNT: + return "IMAGEBYTECOUNT"; + case TIFFTAG_ALPHAOFFSET: + return "ALPHAOFFSET"; + case TIFFTAG_ALPHABYTECOUNT: + return "ALPHABYTECOUNT"; + case TIFFTAG_TILEOFFSETS: + return "TileOffsets"; + case TIFFTAG_TILEBYTECOUNTS: + return "TileByteCounts"; + default: + return ""; + } +} +#endif + +unsigned int find_tag_from_tiff_header(const unsigned char*buffer, const unsigned int buffer_size, const unsigned int tag, const unsigned char **potential_error) +{ + const TIFFHeader *tiff=(const TIFFHeader *)buffer; + /*@ assert sizeof(TIFFHeader) <= sizeof(struct ifd_header); */ + if(buffer_size < sizeof(struct ifd_header)) + return 0; + /*@ assert buffer_size >= sizeof(TIFFHeader); */ + /*@ assert buffer_size >= sizeof(struct ifd_header); */ +#ifndef MAIN_tiff_le + if(tiff->tiff_magic==TIFF_BIGENDIAN) + return find_tag_from_tiff_header_be(buffer, buffer_size, tag, potential_error); +#endif +#ifndef MAIN_tiff_be + if(tiff->tiff_magic==TIFF_LITTLEENDIAN) + return find_tag_from_tiff_header_le(buffer, buffer_size, tag, potential_error); +#endif + return 0; +} + +time_t get_date_from_tiff_header(const unsigned char *buffer, const unsigned int buffer_size) +{ + const unsigned char *potential_error=NULL; + unsigned int date_asc=0; + time_t tmp; + /*@ assert \valid_read(buffer+(0..buffer_size-1)); */ + /*@ assert sizeof(TIFFHeader) <= sizeof(struct ifd_header); */ + if(buffer_size < sizeof(struct ifd_header) || buffer_size < 19) + return (time_t)0; + /*@ assert buffer_size >= sizeof(TIFFHeader); */ + /*@ assert buffer_size >= sizeof(struct ifd_header); */ + /* DateTimeOriginal */ + date_asc=find_tag_from_tiff_header(buffer, buffer_size, 0x9003, &potential_error); + /* DateTimeDigitalized*/ + if(date_asc==0 || date_asc > buffer_size - 19) + date_asc=find_tag_from_tiff_header(buffer, buffer_size, 0x9004, &potential_error); + if(date_asc==0 || date_asc > buffer_size - 19) + date_asc=find_tag_from_tiff_header(buffer, buffer_size, 0x132, &potential_error); + if(date_asc==0 || date_asc > buffer_size - 19) + return (time_t)0; + tmp=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[date_asc]); + /*@ assert \valid_read(buffer+(0..buffer_size-1)); */ + return tmp; +} + +static void register_header_check_tiff(file_stat_t *file_stat) +{ + static const unsigned char tiff_header_be[4]= { 'M','M',0x00, 0x2a}; + static const unsigned char tiff_header_le[4]= { 'I','I',0x2a, 0x00}; +#if !defined(SINGLE_FORMAT_jpg) && !defined(SINGLE_FORMAT_rw2) && !defined(SINGLE_FORMAT_orf) && !defined(SINGLE_FORMAT_wdp) +#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg) + register_header_check(0, tiff_header_be, sizeof(tiff_header_be), &header_check_tiff_be, file_stat); +#endif +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) + register_header_check(0, tiff_header_le, sizeof(tiff_header_le), &header_check_tiff_le, file_stat); +#endif +#endif +} +#endif diff --git a/subprojects/lib/src/file_tiff.h b/subprojects/lib/src/file_tiff.h new file mode 100644 index 0000000..12df816 --- /dev/null +++ b/subprojects/lib/src/file_tiff.h @@ -0,0 +1,168 @@ +/* + + File: file_tiff.h + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifndef _FILE_TIFF_H +#define _FILE_TIFF_H +#ifdef __cplusplus +extern "C" { +#endif + +#define TIFF_ERROR 0xffffffffffffffffull + +#define TIFF_BIGENDIAN 0x4d4d +#define TIFF_LITTLEENDIAN 0x4949 +#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */ +#define TIFFTAG_MAKE 271 /* scanner manufacturer name */ +#define TIFFTAG_MODEL 272 /* scanner model name/number */ +#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */ +#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */ +#define TIFFTAG_TILEOFFSETS 324 +#define TIFFTAG_TILEBYTECOUNTS 325 +#define TIFFTAG_SUBIFD 330 +#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */ +#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */ +#define TIFFTAG_KODAKIFD 33424 +#define TIFFTAG_EXIFIFD 34665 +#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */ +#define TIFFTAG_SONY_FILEFORMAT 0xb000 +#define TIFFTAG_IMAGEOFFSET 0xbcc0 +#define TIFFTAG_IMAGEBYTECOUNT 0xbcc1 +#define TIFFTAG_ALPHAOFFSET 0xbcc2 +#define TIFFTAG_ALPHABYTECOUNT 0xbcc3 +#define TIFFTAG_PRINTIM 50341 +#define TIFFTAG_DNGVERSION 50706 +#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */ + +typedef struct { + uint16_t tiff_magic; /* magic number (defines byte order) */ + uint16_t tiff_version; /* TIFF version number */ + uint32_t tiff_diroff; /* byte offset to first directory */ +} TIFFHeader; + +typedef struct { + uint16_t tdir_tag; /* see below */ + uint16_t tdir_type; /* data type; see below */ + uint32_t tdir_count; /* number of items; length in spec */ + uint32_t tdir_offset; /* byte offset to field data */ +} TIFFDirEntry; + +/* Work around a gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 */ +struct ifd_header { + uint16_t nbr_fields; + TIFFDirEntry ifd; +} __attribute__ ((gcc_struct, __packed__)); + +/*@ + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ ensures \valid_read(buffer+(0..buffer_size-1)); + @ assigns \nothing; + @*/ +time_t get_date_from_tiff_header(const unsigned char*buffer, const unsigned int buffer_size); + +/*@ + @ requires \valid_read(buffer+(0..buffer_size-1)); + @ requires \separated(potential_error, buffer); + @ assigns *potential_error; + @*/ +unsigned int find_tag_from_tiff_header(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int tag, const unsigned char **potential_error); + +#if !defined(MAIN_tiff_be) +/*@ + @ requires tiff_size >= sizeof(TIFFHeader); + @ requires tiff_size >= sizeof(struct ifd_header); + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ requires \valid(potential_error); + @ requires \separated(potential_error, buffer); + @ assigns *potential_error; + @*/ +unsigned int find_tag_from_tiff_header_le(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error); +#endif + +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) +/*@ + @ requires fr->file_check==&file_check_tiff_le; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns errno; + @ assigns fr->file_size; + @ assigns *fr->handle; + @ assigns Frama_C_entropy_source; + @*/ +void file_check_tiff_le(file_recovery_t *fr); +#endif + +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) && !defined(SINGLE_FORMAT_rw2) && !defined(SINGLE_FORMAT_orf) && !defined(SINGLE_FORMAT_wdp) +/*@ + @ requires buffer_size >= 15; + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension != \null); + @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_le); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null); + @*/ +int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new); +#endif + +#if !defined(MAIN_tiff_le) +/*@ + @ requires tiff_size >= sizeof(TIFFHeader); + @ requires tiff_size >= sizeof(struct ifd_header); + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ requires \valid(potential_error); + @ requires \separated(potential_error, buffer); + @ assigns *potential_error; + @*/ +unsigned int find_tag_from_tiff_header_be(const unsigned char*buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error); +#endif + +#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) && !defined(SINGLE_FORMAT_rw2) && !defined(SINGLE_FORMAT_orf) && !defined(SINGLE_FORMAT_wdp) +/*@ + @ requires buffer_size >= 15; + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->extension != \null); + @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension); + @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0); + @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null); + @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null); + @*/ +int header_check_tiff_be(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new); +#endif + +/*@ + @ ensures \result == 1 || \result == 2 || \result == 4 || \result == 8; + @ assigns \nothing; + @*/ +unsigned int tiff_type2size(const unsigned int type); + +#ifdef DEBUG_TIFF +const char *tag_name(unsigned int tag); +#endif + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/subprojects/lib/src/file_tiff_be.c b/subprojects/lib/src/file_tiff_be.c new file mode 100644 index 0000000..3a3d990 --- /dev/null +++ b/subprojects/lib/src/file_tiff_be.c @@ -0,0 +1,887 @@ +/* + + File: file_tiff_be.c + + Copyright (C) 1998-2005,2007-2009, 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tiff) || defined(SINGLE_FORMAT_jpg) || defined(SINGLE_FORMAT_rw2) || defined(SINGLE_FORMAT_orf) || defined(SINGLE_FORMAT_wdp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "file_tiff.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) +extern const file_hint_t file_hint_jpg; +#endif +extern const file_hint_t file_hint_tiff; +static const char *extension_dcr="dcr"; +static const char *extension_dng="dng"; +static const char *extension_nef="nef"; +static const char *extension_pef="pef"; + +#ifndef MAIN_tiff_le +/*@ + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ ensures \result <= 0xffff; + @ assigns \nothing; + @ */ +static unsigned int get_nbr_fields_be(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int offset_hdr) +{ + const unsigned char *ptr_hdr; + const struct ifd_header *hdr; + if(sizeof(struct ifd_header) > tiff_size) + return 0; + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + if(offset_hdr > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */ + ptr_hdr=&buffer[offset_hdr]; + /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */ + hdr=(const struct ifd_header *)ptr_hdr; + /*@ assert \valid_read(hdr); */ + return be16(hdr->nbr_fields); +} + +/*@ + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ requires \valid(potential_error); + @ requires \separated(potential_error, buffer+(..)); + @ assigns *potential_error; + @ + */ +static unsigned int find_tag_from_tiff_header_be_aux(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error, const unsigned int offset_hdr) +{ + const unsigned char *ptr_hdr; + const struct ifd_header *hdr; + unsigned int i; + unsigned int nbr_fields; + if(sizeof(struct ifd_header) > tiff_size) + return 0; + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + if(offset_hdr > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */ + ptr_hdr=&buffer[offset_hdr]; + /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */ + hdr=(const struct ifd_header *)ptr_hdr; + /*@ assert \valid_read(hdr); */ + nbr_fields=be16(hdr->nbr_fields); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + /*@ + @ loop assigns i, *potential_error; + @ loop variant nbr_fields - i; + @*/ + for(i=0; i < nbr_fields; i++) + { + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + const unsigned int offset_entry=offset_hdr + 2 + i * sizeof(TIFFDirEntry); + const unsigned char *ptr_entry; + const TIFFDirEntry *tmp; + if(offset_entry + sizeof(TIFFDirEntry) > tiff_size) + return 0; + /*@ assert offset_entry + sizeof(TIFFDirEntry) <= tiff_size; */ + /*X assert \valid_read(buffer + (0 .. offset_entry + sizeof(TIFFDirEntry)-1)); */ + /*X assert \valid_read((buffer + offset_entry) + (0 .. sizeof(TIFFDirEntry)-1)); */ + ptr_entry=buffer + offset_entry; + /*@ assert \valid_read(ptr_entry + (0 .. sizeof(TIFFDirEntry)-1)); */ + tmp=(const TIFFDirEntry *)ptr_entry; + /*@ assert \valid_read(tmp); */ + if(be16(tmp->tdir_type) > 18 && (*potential_error==NULL || *potential_error > (const unsigned char*)&tmp->tdir_type)) + { + *potential_error = (const unsigned char*)&tmp->tdir_type; + } + if(be16(tmp->tdir_tag)==tag) + { + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return be32(tmp->tdir_offset); + } + } + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return 0; +} + +unsigned int find_tag_from_tiff_header_be(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error) +{ + /*@ assert tiff_size >= sizeof(TIFFHeader); */ + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + const TIFFHeader *tiff=(const TIFFHeader *)buffer; + unsigned int offset_ifd0; + unsigned int offset_exififd; + /*@ assert \valid_read(tiff); */ + offset_ifd0=be32(tiff->tiff_diroff); + if(offset_ifd0 >= tiff_size) + return 0; + /*@ assert offset_ifd0 < tiff_size; */ + if(offset_ifd0 > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + /*@ assert offset_ifd0 + sizeof(struct ifd_header) <= tiff_size; */ + { + const unsigned int tmp=find_tag_from_tiff_header_be_aux(buffer, tiff_size, tag, potential_error, offset_ifd0); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(tmp) + return tmp; + } + offset_exififd=find_tag_from_tiff_header_be_aux(buffer, tiff_size, TIFFTAG_EXIFIFD, potential_error, offset_ifd0); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(offset_exififd <= tiff_size - sizeof(struct ifd_header)) + { + /* Exif */ + const unsigned int tmp=find_tag_from_tiff_header_be_aux(buffer, tiff_size, tag, potential_error, offset_exififd); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(tmp) + return tmp; + } + { + const unsigned int nbr_fields=get_nbr_fields_be(buffer, tiff_size, offset_ifd0); + unsigned int offset_tiff_next_diroff; + offset_tiff_next_diroff=offset_ifd0 + 2 + nbr_fields * sizeof(TIFFDirEntry); + /*@ assert tiff_size >= 4; */ + if(offset_tiff_next_diroff < tiff_size - 4) + { + const unsigned char *ptr_hdr; + const uint32_t *tiff_next_diroff; + unsigned int offset_ifd1; + /*@ assert offset_tiff_next_diroff + 4 <= tiff_size; */ + ptr_hdr=&buffer[offset_tiff_next_diroff]; + /*@ assert \valid_read(ptr_hdr + (0 .. 4-1)); */ + tiff_next_diroff=(const uint32_t *)ptr_hdr; + /*@ assert \valid_read(tiff_next_diroff); */ + /* IFD1 */ + offset_ifd1=be32(*tiff_next_diroff); + if(offset_ifd1 > 0) + return find_tag_from_tiff_header_be_aux(buffer, tiff_size, tag, potential_error, offset_ifd1); + } + } + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return 0; +} + +#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg) +/*@ + @ requires \valid(handle); + @ requires \valid_read(entry_strip_offsets); + @ requires \valid_read(entry_strip_bytecounts); + @ requires \separated(handle, &errno, &Frama_C_entropy_source, &__fc_heap_status, \union(entry_strip_offsets, entry_strip_bytecounts)); + @*/ +static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_offsets, const TIFFDirEntry *entry_strip_bytecounts) +{ + const unsigned int nbr=(be32(entry_strip_offsets->tdir_count)<2048? + be32(entry_strip_offsets->tdir_count): + 2048); + /*@ assert nbr <= 2048; */ + unsigned int i; + uint32_t *offsetp; + uint32_t *sizep; + uint64_t max_offset=0; + /* be32() isn't required to compare the 2 values */ + if(entry_strip_offsets->tdir_count != entry_strip_bytecounts->tdir_count) + return TIFF_ERROR; + /*@ assert entry_strip_offsets->tdir_count == entry_strip_bytecounts->tdir_count; */ + if(nbr==0 || + be16(entry_strip_offsets->tdir_type)!=4 || + be16(entry_strip_bytecounts->tdir_type)!=4) + return TIFF_ERROR; + /*@ assert 0 < nbr <= 2048; */ +#ifdef __FRAMAC__ + offsetp=(uint32_t *)MALLOC(2048*sizeof(*offsetp)); +#else + offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp)); +#endif + if(fseek(handle, be32(entry_strip_offsets->tdir_offset), SEEK_SET) < 0 || + fread(offsetp, sizeof(*offsetp), nbr, handle) != nbr) + { + free(offsetp); + return TIFF_ERROR; + } +#ifdef __FRAMAC__ + sizep=(uint32_t *)MALLOC(2048*sizeof(*sizep)); +#else + sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep)); +#endif + if(fseek(handle, be32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 || + fread(sizep, sizeof(*sizep), nbr, handle) != nbr) + { + free(sizep); + free(offsetp); + return TIFF_ERROR; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)offsetp, nbr*sizeof(*offsetp)); + Frama_C_make_unknown((char *)sizep, nbr*sizeof(*sizep)); +#endif + /*@ + @ loop assigns i, max_offset; + @*/ + for(i=0; i= 2; */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + /*@ assert 2 <= data_read <= sizeof(buffer); */ + if( memcmp(buffer, sign_nikon1, sizeof(sign_nikon1))==0 || + memcmp(buffer, sign_nikon2, sizeof(sign_nikon2))==0 || + memcmp(buffer, sign_pentax, sizeof(sign_pentax))==0 ) + return tiff_diroff; + entry=(const TIFFDirEntry *)&buffer[2]; + n=(buffer[0]<<8)+buffer[1]; +#ifdef DEBUG_TIFF + log_info("tiff_be_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n); +#endif + //sizeof(TIFFDirEntry)=12; + if(n > (unsigned int)(data_read-2)/12) + n=(data_read-2)/12; + if(n==0) + return TIFF_ERROR; + for(i=0;itdir_count) * tiff_type2size(be16(entry->tdir_type)); +#ifdef DEBUG_TIFF + log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx)\n", + i, + be16(entry->tdir_tag), + be16(entry->tdir_tag), + tag_name(be16(entry->tdir_tag)), + be16(entry->tdir_type), + (long unsigned)be32(entry->tdir_count), + (long unsigned)be32(entry->tdir_offset), + (long unsigned)be32(entry->tdir_offset)); +#endif + if(val>4) + { + const uint64_t new_offset=be32(entry->tdir_offset)+val; + if(new_offset==0) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + if(be32(entry->tdir_count)==1) + { + const unsigned int tmp=tiff_be_read(&entry->tdir_offset, be16(entry->tdir_type)); + switch(be16(entry->tdir_tag)) + { + case TIFFTAG_JPEGIFOFFSET: jpegifoffset=tmp; break; + case TIFFTAG_JPEGIFBYTECOUNT: jpegifbytecount=tmp; break; + case TIFFTAG_ALPHAOFFSET: alphaoffset=tmp; break; + case TIFFTAG_ALPHABYTECOUNT: alphabytecount=tmp; break; + case TIFFTAG_IMAGEOFFSET: imageoffset=tmp; break; + case TIFFTAG_IMAGEBYTECOUNT: imagebytecount=tmp; break; + case TIFFTAG_STRIPOFFSETS: strip_offsets=tmp; break; + case TIFFTAG_STRIPBYTECOUNTS: strip_bytecounts=tmp; break; + case TIFFTAG_TILEBYTECOUNTS: tile_bytecounts=tmp; break; + case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break; + } + } + entry++; + } + if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount) + max_offset = alphaoffset + alphabytecount; + if(imagebytecount > 0 && max_offset < imageoffset + imagebytecount) + max_offset = imageoffset + imagebytecount; + if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount) + max_offset = jpegifoffset + jpegifbytecount; + if(strip_bytecounts > 0 && strip_offsets!=0xffffffff && + max_offset < strip_offsets + strip_bytecounts) + max_offset = strip_offsets + strip_bytecounts; + if(tile_bytecounts > 0 && tile_offsets!=0xffffffff && + max_offset < tile_offsets + tile_bytecounts) + max_offset = tile_offsets + tile_bytecounts; + return max_offset; +} +#endif +#endif + +#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) && !defined(SINGLE_FORMAT_rw2) && !defined(SINGLE_FORMAT_orf) && !defined(SINGLE_FORMAT_wdp) +static uint64_t file_check_tiff_be_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count); + +/*@ + @ requires \valid(fr); + @ requires \valid(fr->handle); + @ requires valid_file_recovery(fr); + @ requires \valid_read(&fr->extension); + @ requires valid_read_string(fr->extension); + @ requires separation: \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @ requires \valid_read(buffer + (0 .. buffer_size - 1)); + @ ensures \valid(fr); + @ ensures \valid(fr->handle); + @ ensures valid_read_string(fr->extension); + @*/ +static uint64_t file_check_tiff_be_aux_next(file_recovery_t *fr, const unsigned int depth, const unsigned int count, const unsigned char *buffer, const unsigned int buffer_size, const unsigned int offset_ptr_offset) +{ + if(buffer_size < 4) + return 0; + /*@ assert buffer_size >= 4; */ + if(offset_ptr_offset > buffer_size-4) + return 0; + { + /*@ assert offset_ptr_offset <= buffer_size - 4; */ + /*@ assert offset_ptr_offset + 4 <= buffer_size; */ + /*@ assert \valid_read(buffer + (0 .. offset_ptr_offset + 4 - 1)); */ + const unsigned char *ptr_offset=&buffer[offset_ptr_offset]; + /*@ assert \valid_read(ptr_offset + (0 .. 4 - 1)); */ + const uint32_t *ptr32_offset=(const uint32_t *)ptr_offset; + /*@ assert \valid_read(ptr32_offset); */ + const unsigned int next_diroff=be32(*ptr32_offset); + if(next_diroff == 0) + return 0; + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + return file_check_tiff_be_aux(fr, next_diroff, depth+1, count+1); + } +} + +/*@ + @ requires \valid(fr); + @ requires \valid(fr->handle); + @ requires valid_file_recovery(fr); + @ requires \valid_read(&fr->extension); + @ requires valid_read_string(fr->extension); + @ requires separation: \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @ ensures \valid(fr); + @ ensures \valid(fr->handle); + @ ensures valid_read_string(fr->extension); + @*/ +static uint64_t file_check_tiff_be_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count) +{ + unsigned char buffer[8192]; + unsigned int i,n; + int data_read; + uint64_t alphabytecount=0; + uint64_t alphaoffset=0; + uint64_t imagebytecount=0; + uint64_t imageoffset=0; + uint64_t jpegifbytecount=0; + uint64_t jpegifoffset=0; + uint64_t max_offset=0; + uint64_t strip_bytecounts=0; + uint64_t strip_offsets=0; + uint64_t tile_bytecounts=0; + uint64_t tile_offsets=0; + unsigned int sorted_tag_error=0; + unsigned int tdir_tag_old=0; + const TIFFDirEntry *entries=(const TIFFDirEntry *)&buffer[2]; + const TIFFDirEntry *entry_strip_offsets=NULL; + const TIFFDirEntry *entry_strip_bytecounts=NULL; + const TIFFDirEntry *entry_tile_offsets=NULL; + const TIFFDirEntry *entry_tile_bytecounts=NULL; + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ +#ifdef DEBUG_TIFF + log_info("file_check_tiff_be_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count); +#endif + if(depth>4) + return TIFF_ERROR; + if(count>16) + return TIFF_ERROR; + if(tiff_diroff < sizeof(TIFFHeader)) + return TIFF_ERROR; + if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0) + return TIFF_ERROR; + data_read=fread(buffer, 1, sizeof(buffer), fr->handle); +#if defined(__FRAMAC__) + data_read = Frama_C_interval(0, sizeof(buffer)); + /*@ assert 0 <= data_read <= sizeof(buffer); */ + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + if(data_read<2) + return TIFF_ERROR; + /*@ assert 2 <= data_read <= sizeof(buffer); */ + n=(buffer[0]<<8)+buffer[1]; +#ifdef DEBUG_TIFF + log_info("file_check_tiff_be_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n); +#endif + if(n==0) + return TIFF_ERROR; + /*@ assert 0 < n <= 65535; */ + /*@ assert sizeof(TIFFDirEntry)==12; */ + /*X + X loop invariant 0 <= i <=n && i <= (data_read-2)/12; + X loop variant n-i; + X*/ + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @*/ + for(i=0; i < n && i < (unsigned int)(data_read-2)/12; i++) + { + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const TIFFDirEntry *entry=&entries[i]; + /*@ assert 0 <= i < n; */ + /*@ assert \valid_read(entry); */ + const unsigned int tdir_count=be32(entry->tdir_count); + const unsigned int tdir_tag=be16(entry->tdir_tag); + const uint64_t val=(uint64_t)tdir_count * tiff_type2size(be16(entry->tdir_type)); +#ifdef DEBUG_TIFF + log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx) val=%lu\n", + i, + tdir_tag, + tdir_tag, + tag_name(tdir_tag), + be16(entry->tdir_type), + (long unsigned)tdir_count, + (long unsigned)be32(entry->tdir_offset), + (long unsigned)be32(entry->tdir_offset), + (long unsigned)val); +#endif + if(tdir_tag_old > tdir_tag) + { /* Entries must be sorted by tag */ + if(sorted_tag_error > 0) + { + return TIFF_ERROR; + } + else + sorted_tag_error=1; + } + if(val>4) + { + const uint64_t new_offset=be32(entry->tdir_offset)+val; + if(new_offset==0) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + if(tdir_count==1 && val<=4) + { + const unsigned int tmp=tiff_be_read(&entry->tdir_offset, be16(entry->tdir_type)); + switch(tdir_tag) + { + case TIFFTAG_ALPHABYTECOUNT: alphabytecount=tmp; break; + case TIFFTAG_ALPHAOFFSET: alphaoffset=tmp; break; + case TIFFTAG_IMAGEBYTECOUNT: imagebytecount=tmp; break; + case TIFFTAG_IMAGEOFFSET: imageoffset=tmp; break; + case TIFFTAG_JPEGIFBYTECOUNT: jpegifbytecount=tmp; break; + case TIFFTAG_JPEGIFOFFSET: jpegifoffset=tmp; break; + case TIFFTAG_STRIPBYTECOUNTS: strip_bytecounts=tmp; break; + case TIFFTAG_STRIPOFFSETS: strip_offsets=tmp; break; + case TIFFTAG_TILEBYTECOUNTS: tile_bytecounts=tmp; break; + case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break; + case TIFFTAG_EXIFIFD: + case TIFFTAG_KODAKIFD: + { + /*@ assert \valid(fr); */ + /*@ assert valid_file_recovery(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; + case TIFFTAG_SUBIFD: + { + /*@ assert \valid(fr); */ + /*@ assert valid_file_recovery(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; +#ifdef ENABLE_TIFF_MAKERNOTE + case EXIFTAG_MAKERNOTE: + { + const uint64_t new_offset=tiff_be_makernote(fr->handle, tmp); + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; +#endif + } + } + else if(tdir_count > 1) + { + /*@ assert tdir_count > 1; */ + switch(tdir_tag) + { + case TIFFTAG_EXIFIFD: + case TIFFTAG_KODAKIFD: + case TIFFTAG_SUBIFD: + if(be16(entry->tdir_type)==4) + { + const unsigned int nbr=(tdir_count<32?tdir_count:32); + /*@ assert 2 <= nbr <= 32; */ + uint32_t subifd_offsetp[32]; + unsigned int j; + if(fseek(fr->handle, be32(entry->tdir_offset), SEEK_SET) < 0) + { + return TIFF_ERROR; + } + if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr) + { + return TIFF_ERROR; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp)); +#endif + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @*/ + for(j=0; jhandle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_be_aux(fr, be32(subifd_offsetp[j]), depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + { + return TIFF_ERROR; + } + if(max_offset < new_offset) + max_offset = new_offset; + } + } + break; + case TIFFTAG_STRIPOFFSETS: + entry_strip_offsets=entry; + break; + case TIFFTAG_STRIPBYTECOUNTS: + entry_strip_bytecounts=entry; + break; + case TIFFTAG_TILEBYTECOUNTS: + entry_tile_bytecounts=entry; + break; + case TIFFTAG_TILEOFFSETS: + entry_tile_offsets=entry; + break; + } + } + tdir_tag_old=tdir_tag; + } + if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount) + max_offset = alphaoffset + alphabytecount; + if(imagebytecount > 0 && max_offset < imageoffset + imagebytecount) + max_offset = imageoffset + imagebytecount; + if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount) + max_offset = jpegifoffset + jpegifbytecount; + if(strip_bytecounts > 0 && strip_offsets!=0xffffffff && + max_offset < strip_offsets + strip_bytecounts) + max_offset = strip_offsets + strip_bytecounts; + if(tile_bytecounts > 0 && tile_offsets!=0xffffffff && + max_offset < tile_offsets + tile_bytecounts) + max_offset = tile_offsets + tile_bytecounts; + if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL) + { + const uint64_t tmp=parse_strip_be(fr->handle, entry_strip_offsets, entry_strip_bytecounts); + if(tmp==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < tmp) + max_offset=tmp; + } + if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL) + { + const uint64_t tmp=parse_strip_be(fr->handle, entry_tile_offsets, entry_tile_bytecounts); + if(tmp==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < tmp) + max_offset=tmp; + } + { + const unsigned int offset_ptr_offset=2+12*n; + const uint64_t new_offset=file_check_tiff_be_aux_next(fr, depth, count, buffer, data_read, offset_ptr_offset); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset != TIFF_ERROR && max_offset < new_offset) + max_offset=new_offset; + } + return max_offset; +} + +/*@ + @ requires fr->file_check==&file_check_tiff_be; + @ requires valid_file_check_param(fr); + @ ensures valid_file_check_result(fr); + @ assigns errno; + @ assigns fr->file_size; + @ assigns *fr->handle; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_tiff_be(file_recovery_t *fr) +{ + static uint64_t calculated_file_size=0; + char buffer[sizeof(TIFFHeader)]; + const TIFFHeader *header=(const TIFFHeader *)&buffer; + calculated_file_size = 0; + if(fseek(fr->handle, 0, SEEK_SET) < 0 || + fread(&buffer, sizeof(TIFFHeader), 1, fr->handle) != 1) + { + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(TIFFHeader)); +#endif + if(header->tiff_magic==TIFF_BIGENDIAN) + calculated_file_size=file_check_tiff_be_aux(fr, be32(header->tiff_diroff), 0, 0); + /*@ assert \valid(fr->handle); */ +#ifdef DEBUG_TIFF + log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size); + log_info("TIFF Estimated %llu %llx\n", (unsigned long long)calculated_file_size, (unsigned long long)calculated_file_size); +#endif + if(fr->file_size < calculated_file_size || calculated_file_size==0 || calculated_file_size==TIFF_ERROR) + fr->file_size=0; + /* PhotoRec isn't yet capable to find the correct filesize for + * Sony arw and dng, + * Panasonic raw/rw2, + * Minolta tif + * Sony sr2 + * so don't truncate them */ + else if(strcmp(fr->extension,"cr2")==0 || + strcmp(fr->extension,"dcr")==0 || + strcmp(fr->extension,"nef")==0 || + strcmp(fr->extension,"orf")==0 || + strcmp(fr->extension,"pef")==0 || + (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) || + strcmp(fr->extension,"wdp")==0) + fr->file_size=calculated_file_size; +} + +/*@ + @ requires separation: \separated(&file_hint_tiff, buffer+(..), file_recovery, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_be); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_tiff.extension || + file_recovery_new->extension == extension_dcr || + file_recovery_new->extension == extension_dng || + file_recovery_new->extension == extension_nef || + file_recovery_new->extension == extension_pef); + @*/ +int header_check_tiff_be(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char *potential_error=NULL; + const TIFFHeader *header=(const TIFFHeader *)buffer; + if((uint32_t)be32(header->tiff_diroff) < sizeof(TIFFHeader)) + return 0; +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) + if(file_recovery->file_stat!=NULL && + file_recovery->file_stat->file_hint==&file_hint_jpg) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tiff.extension; + if(find_tag_from_tiff_header_be(buffer, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=0) + { + /* Adobe Digital Negative, ie. PENTAX K-30 */ + file_recovery_new->extension=extension_dng; + } + else + { + const unsigned int tag_make=find_tag_from_tiff_header_be(buffer, buffer_size, TIFFTAG_MAKE, &potential_error); + if(tag_make!=0 && tag_make < buffer_size - 20) + { + if( memcmp(&buffer[tag_make], "PENTAX Corporation ", 20)==0 || + memcmp(&buffer[tag_make], "PENTAX ", 20)==0) + file_recovery_new->extension=extension_pef; + else if(memcmp(&buffer[tag_make], "NIKON CORPORATION", 18)==0) + file_recovery_new->extension=extension_nef; + else if(memcmp(&buffer[tag_make], "Kodak", 6)==0) + file_recovery_new->extension=extension_dcr; + } + } + file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size); + file_recovery_new->file_check=&file_check_tiff_be; + return 1; +} +#endif +#endif + +#if defined(MAIN_tiff_be) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.tif"; + unsigned char buffer[BLOCKSIZE]; + int res; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.extension=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_tiff; + file_stats.not_recovered=0; + file_stats.recovered=0; + file_hint_tiff.register_header_check(&file_stats); + if(header_check_tiff_be(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.file_check == &file_check_tiff_be; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert (file_recovery_new.extension == file_hint_tiff.extension || + file_recovery_new.extension == extension_dcr || + file_recovery_new.extension == extension_dng || + file_recovery_new.extension == extension_nef || + file_recovery_new.extension == extension_pef); */ + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string(file_recovery_new.extension); */ + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.data_check == \null; */ + /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */ + { + /*@ assert valid_read_string(file_recovery_new.extension); */ + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + header_check_tiff_be(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert file_recovery_new.file_check == &file_check_tiff_be; */ + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_tiff_be(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_tiff_le.c b/subprojects/lib/src/file_tiff_le.c new file mode 100644 index 0000000..f597d46 --- /dev/null +++ b/subprojects/lib/src/file_tiff_le.c @@ -0,0 +1,911 @@ +/* + + File: file_tiff_le.c + + Copyright (C) 1998-2005,2007-2009, 2017 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tiff) || defined(SINGLE_FORMAT_jpg) || defined(SINGLE_FORMAT_rw2) || defined(SINGLE_FORMAT_orf) || defined(SINGLE_FORMAT_wdp) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" +#include "common.h" +#include "file_tiff.h" +#include "log.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#if !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_raf; +#endif +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) +extern const file_hint_t file_hint_jpg; +#endif +extern const file_hint_t file_hint_tiff; +static const char *extension_arw="arw"; +static const char *extension_cr2="cr2"; +static const char *extension_dng="dng"; +static const char *extension_nef="nef"; +static const char *extension_sr2="sr2"; + +#ifndef MAIN_tiff_be +/*@ + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ ensures \result <= 0xffff; + @ assigns \nothing; + @ */ +static unsigned int get_nbr_fields_le(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int offset_hdr) +{ + const unsigned char *ptr_hdr; + const struct ifd_header *hdr; + if(sizeof(struct ifd_header) > tiff_size) + return 0; + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + if(offset_hdr > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */ + ptr_hdr=&buffer[offset_hdr]; + /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */ + hdr=(const struct ifd_header *)ptr_hdr; + /*@ assert \valid_read(hdr); */ + return le16(hdr->nbr_fields); +} + +/*@ + @ requires \valid_read(buffer+(0..tiff_size-1)); + @ requires \valid(potential_error); + @ requires \separated(potential_error, buffer+(..)); + @ assigns *potential_error; + @ + */ +static unsigned int find_tag_from_tiff_header_le_aux(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error, const unsigned int offset_hdr) +{ + const unsigned char *ptr_hdr; + const struct ifd_header *hdr; + unsigned int i; + unsigned int nbr_fields; + if(sizeof(struct ifd_header) > tiff_size) + return 0; + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + if(offset_hdr > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */ + ptr_hdr=&buffer[offset_hdr]; + /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */ + hdr=(const struct ifd_header *)ptr_hdr; + /*@ assert \valid_read(hdr); */ + nbr_fields=le16(hdr->nbr_fields); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + /*@ + @ loop assigns i, *potential_error; + @ loop variant nbr_fields - i; + @*/ + for(i=0; i < nbr_fields; i++) + { + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + const unsigned int offset_entry=offset_hdr + 2 + i * sizeof(TIFFDirEntry); + const unsigned char *ptr_entry; + const TIFFDirEntry *tmp; + if(offset_entry + sizeof(TIFFDirEntry) > tiff_size) + return 0; + /*@ assert offset_entry + sizeof(TIFFDirEntry) <= tiff_size; */ + /*X assert \valid_read(buffer + (0 .. offset_entry + sizeof(TIFFDirEntry)-1)); */ + /*X assert \valid_read((buffer + offset_entry) + (0 .. sizeof(TIFFDirEntry)-1)); */ + ptr_entry=buffer + offset_entry; + /*@ assert \valid_read(ptr_entry + (0 .. sizeof(TIFFDirEntry)-1)); */ + tmp=(const TIFFDirEntry *)ptr_entry; + /*@ assert \valid_read(tmp); */ + if(le16(tmp->tdir_type) > 18 && (*potential_error==NULL || *potential_error > (const unsigned char*)&tmp->tdir_type)) + { + *potential_error = (const unsigned char*)&tmp->tdir_type; + } + if(le16(tmp->tdir_tag)==tag) + { + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return le32(tmp->tdir_offset); + } + } + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return 0; +} + +unsigned int find_tag_from_tiff_header_le(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error) +{ + /*@ assert tiff_size >= sizeof(TIFFHeader); */ + /*@ assert tiff_size >= sizeof(struct ifd_header); */ + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + const TIFFHeader *tiff=(const TIFFHeader *)buffer; + unsigned int offset_ifd0; + unsigned int offset_exififd; + /*@ assert \valid_read(tiff); */ + offset_ifd0=le32(tiff->tiff_diroff); + if(offset_ifd0 >= tiff_size) + return 0; + /*@ assert offset_ifd0 < tiff_size; */ + if(offset_ifd0 > tiff_size - sizeof(struct ifd_header)) + return 0; + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + /*@ assert offset_ifd0 + sizeof(struct ifd_header) <= tiff_size; */ + { + const unsigned int tmp=find_tag_from_tiff_header_le_aux(buffer, tiff_size, tag, potential_error, offset_ifd0); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(tmp) + return tmp; + } + offset_exififd=find_tag_from_tiff_header_le_aux(buffer, tiff_size, TIFFTAG_EXIFIFD, potential_error, offset_ifd0); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(offset_exififd <= tiff_size - sizeof(struct ifd_header)) + { + /* Exif */ + const unsigned int tmp=find_tag_from_tiff_header_le_aux(buffer, tiff_size, tag, potential_error, offset_exififd); + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + if(tmp) + return tmp; + } + { + const unsigned int nbr_fields=get_nbr_fields_le(buffer, tiff_size, offset_ifd0); + unsigned int offset_tiff_next_diroff; + offset_tiff_next_diroff=offset_ifd0 + 2 + nbr_fields * sizeof(TIFFDirEntry); + /*@ assert tiff_size >= 4; */ + if(offset_tiff_next_diroff < tiff_size - 4) + { + const unsigned char *ptr_hdr; + const uint32_t *tiff_next_diroff; + unsigned int offset_ifd1; + /*@ assert offset_tiff_next_diroff + 4 <= tiff_size; */ + ptr_hdr=&buffer[offset_tiff_next_diroff]; + /*@ assert \valid_read(ptr_hdr + (0 .. 4-1)); */ + tiff_next_diroff=(const uint32_t *)ptr_hdr; + /*@ assert \valid_read(tiff_next_diroff); */ + /* IFD1 */ + offset_ifd1=le32(*tiff_next_diroff); + if(offset_ifd1 > 0) + return find_tag_from_tiff_header_le_aux(buffer, tiff_size, tag, potential_error, offset_ifd1); + } + } + /*@ assert \valid_read(buffer+(0..tiff_size-1)); */ + return 0; +} + +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) +/*@ + @ requires \valid(handle); + @ requires \valid_read(entry_strip_offsets); + @ requires \valid_read(entry_strip_bytecounts); + @ requires \separated(handle, &errno, &Frama_C_entropy_source, &__fc_heap_status, \union(entry_strip_offsets, entry_strip_bytecounts)); + @*/ +static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_offsets, const TIFFDirEntry *entry_strip_bytecounts) +{ + const unsigned int nbr=(le32(entry_strip_offsets->tdir_count)<2048? + le32(entry_strip_offsets->tdir_count): + 2048); + /*@ assert nbr <= 2048; */ + unsigned int i; + uint32_t *offsetp; + uint32_t *sizep; + uint64_t max_offset=0; + /* le32() isn't required to compare the 2 values */ + if(entry_strip_offsets->tdir_count != entry_strip_bytecounts->tdir_count) + return TIFF_ERROR; + /*@ assert entry_strip_offsets->tdir_count == entry_strip_bytecounts->tdir_count; */ + if(nbr==0 || + le16(entry_strip_offsets->tdir_type)!=4 || + le16(entry_strip_bytecounts->tdir_type)!=4) + return TIFF_ERROR; + /*@ assert 0 < nbr <= 2048; */ +#ifdef __FRAMAC__ + offsetp=(uint32_t *)MALLOC(2048*sizeof(*offsetp)); +#else + offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp)); +#endif + if(fseek(handle, le32(entry_strip_offsets->tdir_offset), SEEK_SET) < 0 || + fread(offsetp, sizeof(*offsetp), nbr, handle) != nbr) + { + free(offsetp); + return TIFF_ERROR; + } +#ifdef __FRAMAC__ + sizep=(uint32_t *)MALLOC(2048*sizeof(*sizep)); +#else + sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep)); +#endif + if(fseek(handle, le32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 || + fread(sizep, sizeof(*sizep), nbr, handle) != nbr) + { + free(sizep); + free(offsetp); + return TIFF_ERROR; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)offsetp, nbr*sizeof(*offsetp)); + Frama_C_make_unknown((char *)sizep, nbr*sizeof(*sizep)); +#endif + /*@ + @ loop assigns i, max_offset; + @*/ + for(i=0; i= 2; */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + /*@ assert 2 <= data_read <= sizeof(buffer); */ + if( memcmp(buffer, sign_nikon1, sizeof(sign_nikon1))==0 || + memcmp(buffer, sign_nikon2, sizeof(sign_nikon2))==0 || + memcmp(buffer, sign_pentax, sizeof(sign_pentax))==0 ) + return tiff_diroff; + entry=(const TIFFDirEntry *)&buffer[2]; + n=buffer[0]+(buffer[1]<<8); +#ifdef DEBUG_TIFF + log_info("tiff_le_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n); +#endif + //sizeof(TIFFDirEntry)=12; + if(n > (unsigned int)(data_read-2)/12) + n=(data_read-2)/12; + if(n==0) + return TIFF_ERROR; + for(i=0;itdir_count) * tiff_type2size(le16(entry->tdir_type)); +#ifdef DEBUG_TIFF + log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx)\n", + i, + le16(entry->tdir_tag), + le16(entry->tdir_tag), + tag_name(le16(entry->tdir_tag)), + le16(entry->tdir_type), + (long unsigned)le32(entry->tdir_count), + (long unsigned)le32(entry->tdir_offset), + (long unsigned)le32(entry->tdir_offset)); +#endif + if(val>4) + { + const uint64_t new_offset=le32(entry->tdir_offset)+val; + if(new_offset==0) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + if(le32(entry->tdir_count)==1) + { + const unsigned int tmp=tiff_le_read(&entry->tdir_offset, le16(entry->tdir_type)); + switch(le16(entry->tdir_tag)) + { + case TIFFTAG_JPEGIFOFFSET: jpegifoffset=tmp; break; + case TIFFTAG_JPEGIFBYTECOUNT: jpegifbytecount=tmp; break; + case TIFFTAG_ALPHAOFFSET: alphaoffset=tmp; break; + case TIFFTAG_ALPHABYTECOUNT: alphabytecount=tmp; break; + case TIFFTAG_IMAGEOFFSET: imageoffset=tmp; break; + case TIFFTAG_IMAGEBYTECOUNT: imagebytecount=tmp; break; + case TIFFTAG_STRIPOFFSETS: strip_offsets=tmp; break; + case TIFFTAG_STRIPBYTECOUNTS: strip_bytecounts=tmp; break; + case TIFFTAG_TILEBYTECOUNTS: tile_bytecounts=tmp; break; + case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break; + } + } + entry++; + } + if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount) + max_offset = alphaoffset + alphabytecount; + if(imagebytecount > 0 && max_offset < imageoffset + imagebytecount) + max_offset = imageoffset + imagebytecount; + if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount) + max_offset = jpegifoffset + jpegifbytecount; + if(strip_bytecounts > 0 && strip_offsets!=0xffffffff && + max_offset < strip_offsets + strip_bytecounts) + max_offset = strip_offsets + strip_bytecounts; + if(tile_bytecounts > 0 && tile_offsets!=0xffffffff && + max_offset < tile_offsets + tile_bytecounts) + max_offset = tile_offsets + tile_bytecounts; + return max_offset; +} +#endif +#endif + +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) +static uint64_t file_check_tiff_le_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count); + +/*@ + @ requires \valid(fr); + @ requires \valid(fr->handle); + @ requires valid_file_recovery(fr); + @ requires \valid_read(&fr->extension); + @ requires valid_read_string(fr->extension); + @ requires separation: \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @ requires \valid_read(buffer + (0 .. buffer_size - 1)); + @ ensures \valid(fr); + @ ensures \valid(fr->handle); + @ ensures valid_read_string(fr->extension); + @*/ +static uint64_t file_check_tiff_le_aux_next(file_recovery_t *fr, const unsigned int depth, const unsigned int count, const unsigned char *buffer, const unsigned int buffer_size, const unsigned int offset_ptr_offset) +{ + if(buffer_size < 4) + return 0; + /*@ assert buffer_size >= 4; */ + if(offset_ptr_offset > buffer_size-4) + return 0; + { + /*@ assert offset_ptr_offset <= buffer_size - 4; */ + /*@ assert offset_ptr_offset + 4 <= buffer_size; */ + /*@ assert \valid_read(buffer + (0 .. offset_ptr_offset + 4 - 1)); */ + const unsigned char *ptr_offset=&buffer[offset_ptr_offset]; + /*@ assert \valid_read(ptr_offset + (0 .. 4 - 1)); */ + const uint32_t *ptr32_offset=(const uint32_t *)ptr_offset; + /*@ assert \valid_read(ptr32_offset); */ + const unsigned int next_diroff=le32(*ptr32_offset); + if(next_diroff == 0) + return 0; + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + return file_check_tiff_le_aux(fr, next_diroff, depth+1, count+1); + } +} + +/*@ + @ requires \valid(fr); + @ requires \valid(fr->handle); + @ requires valid_file_recovery(fr); + @ requires \valid_read(&fr->extension); + @ requires valid_read_string(fr->extension); + @ requires separation: \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @ ensures \valid(fr); + @ ensures \valid(fr->handle); + @ ensures valid_read_string(fr->extension); + @*/ +static uint64_t file_check_tiff_le_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count) +{ + unsigned char buffer[8192]; + unsigned int i,n; + int data_read; + uint64_t alphabytecount=0; + uint64_t alphaoffset=0; + uint64_t imagebytecount=0; + uint64_t imageoffset=0; + uint64_t jpegifbytecount=0; + uint64_t jpegifoffset=0; + uint64_t max_offset=0; + uint64_t strip_bytecounts=0; + uint64_t strip_offsets=0; + uint64_t tile_bytecounts=0; + uint64_t tile_offsets=0; + unsigned int sorted_tag_error=0; + unsigned int tdir_tag_old=0; + const TIFFDirEntry *entries=(const TIFFDirEntry *)&buffer[2]; + const TIFFDirEntry *entry_strip_offsets=NULL; + const TIFFDirEntry *entry_strip_bytecounts=NULL; + const TIFFDirEntry *entry_tile_offsets=NULL; + const TIFFDirEntry *entry_tile_bytecounts=NULL; + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ +#ifdef DEBUG_TIFF + log_info("file_check_tiff_le_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count); +#endif + if(depth>4) + return TIFF_ERROR; + if(count>16) + return TIFF_ERROR; + if(tiff_diroff < sizeof(TIFFHeader)) + return TIFF_ERROR; + if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0) + return TIFF_ERROR; + data_read=fread(buffer, 1, sizeof(buffer), fr->handle); +#if defined(__FRAMAC__) + data_read = Frama_C_interval(0, sizeof(buffer)); + /*@ assert 0 <= data_read <= sizeof(buffer); */ + Frama_C_make_unknown((char *)buffer, sizeof(buffer)); +#endif + if(data_read<2) + return TIFF_ERROR; + /*@ assert 2 <= data_read <= sizeof(buffer); */ + n=buffer[0] | (buffer[1]<<8); +#ifdef DEBUG_TIFF + log_info("file_check_tiff_le_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n); +#endif + if(n==0) + return TIFF_ERROR; + /*@ assert 0 < n <= 65535; */ + /*@ assert sizeof(TIFFDirEntry)==12; */ + /*X + X loop invariant 0 <= i <=n && i <= (data_read-2)/12; + X loop variant n-i; + X*/ + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @*/ + for(i=0; i < n && i < (unsigned int)(data_read-2)/12; i++) + { + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const TIFFDirEntry *entry=&entries[i]; + /*@ assert 0 <= i < n; */ + /*@ assert \valid_read(entry); */ + const unsigned int tdir_count=le32(entry->tdir_count); + const unsigned int tdir_tag=le16(entry->tdir_tag); + const uint64_t val=(uint64_t)tdir_count * tiff_type2size(le16(entry->tdir_type)); +#ifdef DEBUG_TIFF + log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx) val=%lu\n", + i, + tdir_tag, + tdir_tag, + tag_name(tdir_tag), + le16(entry->tdir_type), + (long unsigned)tdir_count, + (long unsigned)le32(entry->tdir_offset), + (long unsigned)le32(entry->tdir_offset), + (long unsigned)val); +#endif + if(tdir_tag_old > tdir_tag) + { /* Entries must be sorted by tag, some SR2 files don't respect this rule */ + if(sorted_tag_error > 0) + { + if(fr->extension != extension_sr2) + return TIFF_ERROR; + } + else + sorted_tag_error=1; + } + if(val>4) + { + const uint64_t new_offset=le32(entry->tdir_offset)+val; + if(new_offset==0) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + if(tdir_count==1 && val<=4) + { + const unsigned int tmp=tiff_le_read(&entry->tdir_offset, le16(entry->tdir_type)); + switch(tdir_tag) + { + case TIFFTAG_ALPHABYTECOUNT: alphabytecount=tmp; break; + case TIFFTAG_ALPHAOFFSET: alphaoffset=tmp; break; + case TIFFTAG_IMAGEBYTECOUNT: imagebytecount=tmp; break; + case TIFFTAG_IMAGEOFFSET: imageoffset=tmp; break; + case TIFFTAG_JPEGIFBYTECOUNT: jpegifbytecount=tmp; break; + case TIFFTAG_JPEGIFOFFSET: jpegifoffset=tmp; break; + case TIFFTAG_STRIPBYTECOUNTS: strip_bytecounts=tmp; break; + case TIFFTAG_STRIPOFFSETS: strip_offsets=tmp; break; + case TIFFTAG_TILEBYTECOUNTS: tile_bytecounts=tmp; break; + case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break; + case TIFFTAG_EXIFIFD: + case TIFFTAG_KODAKIFD: + { + /*@ assert \valid(fr); */ + /*@ assert valid_file_recovery(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; + case TIFFTAG_SUBIFD: + if(fr->extension == extension_arw) + { + /* DSLR-A100 is boggus, may be A100DataOffset */ + if(max_offset < tmp) + max_offset=tmp; + } + else + { + /*@ assert \valid(fr); */ + /*@ assert valid_file_recovery(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; +#ifdef ENABLE_TIFF_MAKERNOTE + case EXIFTAG_MAKERNOTE: + { + const uint64_t new_offset=tiff_le_makernote(fr->handle, tmp); + if(new_offset==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < new_offset) + max_offset=new_offset; + } + break; +#endif + } + } + else if(tdir_count > 1) + { + /*@ assert tdir_count > 1; */ + switch(tdir_tag) + { + case TIFFTAG_EXIFIFD: + case TIFFTAG_KODAKIFD: + case TIFFTAG_SUBIFD: + if(le16(entry->tdir_type)==4) + { + const unsigned int nbr=(tdir_count<32?tdir_count:32); + /*@ assert 2 <= nbr <= 32; */ + uint32_t subifd_offsetp[32]; + unsigned int j; + if(fseek(fr->handle, le32(entry->tdir_offset), SEEK_SET) < 0) + { + return TIFF_ERROR; + } + if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr) + { + return TIFF_ERROR; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp)); +#endif + /*@ + @ loop invariant valid_file_recovery(fr); + @ loop invariant \separated(fr, fr->handle, &errno, &Frama_C_entropy_source); + @*/ + for(j=0; jhandle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + const uint64_t new_offset=file_check_tiff_le_aux(fr, le32(subifd_offsetp[j]), depth+1, 0); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset==TIFF_ERROR) + { + return TIFF_ERROR; + } + if(max_offset < new_offset) + max_offset = new_offset; + } + } + break; + case TIFFTAG_STRIPOFFSETS: + entry_strip_offsets=entry; + break; + case TIFFTAG_STRIPBYTECOUNTS: + entry_strip_bytecounts=entry; + break; + case TIFFTAG_TILEBYTECOUNTS: + entry_tile_bytecounts=entry; + break; + case TIFFTAG_TILEOFFSETS: + entry_tile_offsets=entry; + break; + } + } + tdir_tag_old=tdir_tag; + } + if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount) + max_offset = alphaoffset + alphabytecount; + if(imagebytecount > 0 && max_offset < imageoffset + imagebytecount) + max_offset = imageoffset + imagebytecount; + if(jpegifbytecount > 0 && max_offset < jpegifoffset + jpegifbytecount) + max_offset = jpegifoffset + jpegifbytecount; + if(strip_bytecounts > 0 && strip_offsets!=0xffffffff && + max_offset < strip_offsets + strip_bytecounts) + max_offset = strip_offsets + strip_bytecounts; + if(tile_bytecounts > 0 && tile_offsets!=0xffffffff && + max_offset < tile_offsets + tile_bytecounts) + max_offset = tile_offsets + tile_bytecounts; + if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL) + { + const uint64_t tmp=parse_strip_le(fr->handle, entry_strip_offsets, entry_strip_bytecounts); + if(tmp==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < tmp) + max_offset=tmp; + } + if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL) + { + const uint64_t tmp=parse_strip_le(fr->handle, entry_tile_offsets, entry_tile_bytecounts); + if(tmp==TIFF_ERROR) + return TIFF_ERROR; + if(max_offset < tmp) + max_offset=tmp; + } + { + const unsigned int offset_ptr_offset=2+12*n; + const uint64_t new_offset=file_check_tiff_le_aux_next(fr, depth, count, buffer, data_read, offset_ptr_offset); + /*@ assert \valid(fr); */ + /*@ assert \valid(fr->handle); */ + /*@ assert \valid_read(&fr->extension); */ + /*@ assert valid_read_string(fr->extension); */ + if(new_offset != TIFF_ERROR && max_offset < new_offset) + max_offset=new_offset; + } + return max_offset; +} + +void file_check_tiff_le(file_recovery_t *fr) +{ + static uint64_t calculated_file_size=0; + char buffer[sizeof(TIFFHeader)]; + const TIFFHeader *header=(const TIFFHeader *)&buffer; + calculated_file_size = 0; + if(fseek(fr->handle, 0, SEEK_SET) < 0 || + fread(&buffer, sizeof(TIFFHeader), 1, fr->handle) != 1) + { + fr->file_size=0; + return; + } +#if defined(__FRAMAC__) + Frama_C_make_unknown(&buffer, sizeof(TIFFHeader)); +#endif + if(header->tiff_magic==TIFF_LITTLEENDIAN) + calculated_file_size=file_check_tiff_le_aux(fr, le32(header->tiff_diroff), 0, 0); + /*@ assert \valid(fr->handle); */ +#ifdef DEBUG_TIFF + log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size); + log_info("TIFF Estimated %llu %llx\n", (unsigned long long)calculated_file_size, (unsigned long long)calculated_file_size); +#endif + if(fr->file_size < calculated_file_size || calculated_file_size==0 || calculated_file_size==TIFF_ERROR) + fr->file_size=0; + /* PhotoRec isn't yet capable to find the correct filesize for + * Sony arw and dng, + * Panasonic raw/rw2, + * Minolta tif + * Sony sr2 + * so don't truncate them */ + else if(strcmp(fr->extension,"cr2")==0 || + strcmp(fr->extension,"dcr")==0 || + strcmp(fr->extension,"nef")==0 || + strcmp(fr->extension,"orf")==0 || + strcmp(fr->extension,"pef")==0 || + (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) || + strcmp(fr->extension,"wdp")==0) + fr->file_size=calculated_file_size; +} +#endif + +#if !defined(MAIN_tiff_be) && !defined(MAIN_jpg) && !defined(SINGLE_FORMAT_jpg) && !defined(SINGLE_FORMAT_rw2) && !defined(SINGLE_FORMAT_orf) && !defined(SINGLE_FORMAT_wdp) +/*@ + @ requires separation: \separated(&file_hint_tiff, buffer+(..), file_recovery, file_recovery_new); + @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_tiff.extension || + file_recovery_new->extension == extension_arw || + file_recovery_new->extension == extension_cr2 || + file_recovery_new->extension == extension_dng || + file_recovery_new->extension == extension_nef || + file_recovery_new->extension == extension_sr2); + @*/ +int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const unsigned char raf_fp[15]={0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x00, 0x01}; + const unsigned char *potential_error=NULL; + const TIFFHeader *header=(const TIFFHeader *)buffer; + if((uint32_t)le32(header->tiff_diroff) < sizeof(TIFFHeader)) + return 0; + /* Avoid a false positiv with some RAF files */ + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && +#if !defined(SINGLE_FORMAT) + file_recovery->file_stat->file_hint==&file_hint_raf && +#endif + memcmp(buffer, raf_fp, 15)==0) + { + header_ignored(file_recovery_new); + return 0; + } +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_jpg) + if(file_recovery->file_stat!=NULL && + file_recovery->file_check!=NULL && + file_recovery->file_stat->file_hint==&file_hint_jpg) + { + if(header_ignored_adv(file_recovery, file_recovery_new)==0) + return 0; + } +#endif + reset_file_recovery(file_recovery_new); + file_recovery_new->extension=file_hint_tiff.extension; + /* Canon RAW */ + if(buffer[8]=='C' && buffer[9]=='R' && buffer[10]==2) + file_recovery_new->extension=extension_cr2; + else if(find_tag_from_tiff_header_le(buffer, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=0) + { + /* Adobe Digital Negative, ie. NIKON D50 */ + file_recovery_new->extension=extension_dng; + } + else + { + const unsigned int tag_make=find_tag_from_tiff_header_le(buffer, buffer_size, TIFFTAG_MAKE, &potential_error); + if(tag_make!=0 && tag_make < buffer_size - 5) + { + /* TODO + * sr2 if Sony::FileFormat begins by 1 + * arw otherwise */ + if(memcmp(&buffer[tag_make], "SONY", 5)==0) + file_recovery_new->extension=extension_sr2; + else if(memcmp(&buffer[tag_make], "SONY ",5)==0) + file_recovery_new->extension=extension_arw; + else if(tag_make < buffer_size - 18 && memcmp(&buffer[tag_make], "NIKON CORPORATION", 18)==0) + file_recovery_new->extension=extension_nef; + } + } + file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size); + file_recovery_new->file_check=&file_check_tiff_le; + return 1; +} +#endif +#endif + +#if defined(MAIN_tiff_le) +#define BLOCKSIZE 65536u +int main() +{ + const char fn[] = "recup_dir.1/f0000000.tif"; + unsigned char buffer[BLOCKSIZE]; + int res; + file_recovery_t file_recovery_new; + file_recovery_t file_recovery; + file_stat_t file_stats; + + /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + + reset_file_recovery(&file_recovery); + file_recovery.blocksize=BLOCKSIZE; + file_recovery_new.blocksize=BLOCKSIZE; + file_recovery_new.data_check=NULL; + file_recovery_new.extension=NULL; + file_recovery_new.file_stat=NULL; + file_recovery_new.file_check=NULL; + file_recovery_new.file_rename=NULL; + file_recovery_new.calculated_file_size=0; + file_recovery_new.file_size=0; + file_recovery_new.location.start=0; + + file_stats.file_hint=&file_hint_tiff; + file_stats.not_recovered=0; + file_stats.recovered=0; + file_hint_tiff.register_header_check(&file_stats); + if(header_check_tiff_le(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1) + return 0; + /*@ assert file_recovery_new.file_check == &file_check_tiff_le; */ + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert file_recovery_new.extension == file_hint_tiff.extension || + file_recovery_new.extension == extension_arw || + file_recovery_new.extension == extension_cr2 || + file_recovery_new.extension == extension_dng || + file_recovery_new.extension == extension_nef || + file_recovery_new.extension == extension_sr2; */ + /*@ assert valid_read_string((char *)&fn); */ + memcpy(file_recovery_new.filename, fn, sizeof(fn)); + /*@ assert valid_read_string(file_recovery_new.extension); */ + file_recovery_new.file_stat=&file_stats; + /*@ assert valid_read_string(file_recovery_new.extension); */ + /*@ assert valid_read_string((char *)file_recovery_new.filename); */ + /*@ assert file_recovery_new.data_check == \null; */ + /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */ + { + /*@ assert valid_read_string(file_recovery_new.extension); */ + file_recovery_t file_recovery_new2; + file_recovery_new2.blocksize=BLOCKSIZE; + file_recovery_new2.file_stat=NULL; + file_recovery_new2.file_check=NULL; + file_recovery_new2.location.start=BLOCKSIZE; + file_recovery_new.handle=NULL; /* In theory should be not null */ +#if defined(__FRAMAC__) + Frama_C_make_unknown((char *)buffer, BLOCKSIZE); +#endif + header_check_tiff_le(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2); + } + /*@ assert file_recovery_new.file_check == &file_check_tiff_le; */ + { + file_recovery_new.handle=fopen(fn, "rb"); + if(file_recovery_new.handle!=NULL) + { + file_check_tiff_le(&file_recovery_new); + fclose(file_recovery_new.handle); + } + } + return 0; +} +#endif diff --git a/subprojects/lib/src/file_tivo.c b/subprojects/lib/src/file_tivo.c new file mode 100644 index 0000000..efa38b7 --- /dev/null +++ b/subprojects/lib/src/file_tivo.c @@ -0,0 +1,85 @@ +/* + + File: file_tivo.c + + Copyright (C) 2011 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tivo) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tivo(file_stat_t *file_stat); + +const file_hint_t file_hint_tivo = { + .extension = "TiVo", + .description = "TiVo video record", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_tivo +}; + +/*@ + @ requires file_recovery->file_check == &file_check_tivo; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_tivo(file_recovery_t *file_recovery) +{ + const unsigned char tivo_footer[8] = { + 0x00, 0x00, 0x01, 0xb7, 0x00, 0x00, 0x01, 0xb9 + }; + file_search_footer(file_recovery, tivo_footer, sizeof(tivo_footer), 0); +} + +/*@ + @ requires buffer_size >= 0x1c+6; + @ requires separation: \separated(&file_hint_tivo, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tivo(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(memcmp(&buffer[0x1c], "extension = file_hint_tivo.extension; + file_recovery_new->file_check = &file_check_tivo; + return 1; +} + +static void register_header_check_tivo(file_stat_t *file_stat) +{ + static const unsigned char tivo_header[7] = { + 'T', 'i', 'V', 'o', 0x00, 0x04, 0x00 + }; + register_header_check(0, tivo_header, sizeof(tivo_header), &header_check_tivo, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_torrent.c b/subprojects/lib/src/file_torrent.c new file mode 100644 index 0000000..1dc73d1 --- /dev/null +++ b/subprojects/lib/src/file_torrent.c @@ -0,0 +1,66 @@ +/* + + File: file_torrent.c + + Copyright (C) 2010 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_torrent) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_torrent(file_stat_t *file_stat); + +const file_hint_t file_hint_torrent = { + .extension = "torrent", + .description = "Torrent", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_torrent +}; + +/*@ + @ requires buffer_size >= 12; + @ requires separation: \separated(&file_hint_torrent, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_torrent(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(buffer[11] < '0' || buffer[11] > '9') + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_torrent.extension; + return 1; +} + +static void register_header_check_torrent(file_stat_t *file_stat) +{ + register_header_check(0, "d8:announce", 11, &header_check_torrent, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_tph.c b/subprojects/lib/src/file_tph.c new file mode 100644 index 0000000..de18c9f --- /dev/null +++ b/subprojects/lib/src/file_tph.c @@ -0,0 +1,89 @@ +/* + + File: file_tph.c + + Copyright (C) 2008 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tph) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tph(file_stat_t *file_stat); + +const file_hint_t file_hint_tph = { + .extension = "tph", + .description = "Pro/ENGINEER ToolPath", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_tph +}; + +/*@ + @ requires file_recovery->file_check == &file_check_tph; + @ requires valid_file_check_param(file_recovery); + @ ensures valid_file_check_result(file_recovery); + @ assigns *file_recovery->handle, errno, file_recovery->file_size; + @ assigns Frama_C_entropy_source; + @*/ +static void file_check_tph(file_recovery_t *file_recovery) +{ + const unsigned char tph_footer[11] = { + '#', 'E', 'N', 'D', '_', 'O', 'F', '_', + 'U', 'G', 'C' + }; + file_search_footer(file_recovery, tph_footer, sizeof(tph_footer), 1); +} + +/*@ + @ requires buffer_size >= 24; + @ requires separation: \separated(&file_hint_tph, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tph(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + if(!isprint(buffer[20]) || !isprint(buffer[21]) || !isprint(buffer[22]) || !isprint(buffer[23])) + return 0; + reset_file_recovery(file_recovery_new); + file_recovery_new->file_check = &file_check_tph; + file_recovery_new->extension = file_hint_tph.extension; + return 1; +} + +static void register_header_check_tph(file_stat_t *file_stat) +{ + static const unsigned char tph_header[20] = { + '#', 'U', 'G', 'C', ':', '2', ' ', 'M', + 'F', 'G', '_', 'T', 'O', 'O', 'L', '_', + 'P', 'A', 'T', 'H' + }; + register_header_check(0, tph_header, sizeof(tph_header), &header_check_tph, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_tpl.c b/subprojects/lib/src/file_tpl.c new file mode 100644 index 0000000..cfae895 --- /dev/null +++ b/subprojects/lib/src/file_tpl.c @@ -0,0 +1,66 @@ +/* + + File: file_tpl.c + + Copyright (C) 2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tpl) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_tpl(file_stat_t *file_stat); + +const file_hint_t file_hint_tpl = { + .extension = "tpl", + .description = "Adobe Tool Preset", + .max_filesize = PHOTOREC_MAX_FILE_SIZE, + .recover = 1, + .enable_by_default = 1, + .register_header_check = ®ister_header_check_tpl +}; + +/*@ + @ requires separation: \separated(&file_hint_tpl, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_tpl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + reset_file_recovery(file_recovery_new); + file_recovery_new->extension = file_hint_tpl.extension; + return 1; +} + +static void register_header_check_tpl(file_stat_t *file_stat) +{ + static const unsigned char tpl_header[7] = { + '8', 'B', 'T', 'P', 0x00, 0x00, 0x00 + }; + register_header_check(0, tpl_header, sizeof(tpl_header), &header_check_tpl, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_ttf.c b/subprojects/lib/src/file_ttf.c new file mode 100644 index 0000000..897e9c2 --- /dev/null +++ b/subprojects/lib/src/file_ttf.c @@ -0,0 +1,147 @@ +/* + + File: file_ttf.c + + Copyright (C) 2009 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_ttf) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "filegen.h" + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_ttf(file_stat_t *file_stat); + +const file_hint_t file_hint_ttf= { + .extension="ttf", + .description="TrueType Font", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_ttf +}; + +/* + * https://docs.microsoft.com/en-us/typography/opentype/spec/otff + */ + +struct ttf_offset_table +{ + int32_t sfnt_version; + uint16_t numTables; + uint16_t searchRange; + uint16_t entrySelector; + uint16_t rangeShift; +}; + +struct ttf_table_directory +{ + uint32_t tag; + uint32_t checkSum; + uint32_t offset; /* Offset from beginning of TrueType font file. */ + uint32_t length; /* Length of this table. */ +}; + +/*@ + @ assigns \nothing; + @*/ +static unsigned int td_ilog2(unsigned int v) +{ + unsigned int l = 0; + /*@ + @ loop assigns v,l; + @ loop unroll 16; + @*/ + while(v >>= 1) + l++; + return l; +} + +/*@ + @ requires buffer_size >= sizeof(struct ttf_offset_table); + @ requires separation: \separated(&file_hint_ttf, buffer+(..), file_recovery, file_recovery_new); + @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); + @ ensures valid_header_check_result(\result, file_recovery_new); + @ assigns *file_recovery_new; + @*/ +static int header_check_ttf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) +{ + const struct ttf_offset_table *ttf=(const struct ttf_offset_table *)buffer; + const unsigned int numTables=be16(ttf->numTables); + const unsigned int entrySelector=be16(ttf->entrySelector); + const unsigned int searchRange=be16(ttf->searchRange); + const unsigned int rangeShift=be16(ttf->rangeShift); + if(numTables == 0) + return 0; + /* searchRange (Maximum power of 2 <= numTables) x 16. + * entrySelector Log2(maximum power of 2 <= numTables). + * rangeShift NumTables x 16-searchRange. + * */ + if(td_ilog2(numTables) != entrySelector) + return 0; + if((16<extension=file_hint_ttf.extension; + if(sizeof(struct ttf_offset_table) + numTables * sizeof(struct ttf_table_directory) + <= buffer_size) + { + /*@ assert sizeof(struct ttf_offset_table) + numTables * sizeof(struct ttf_table_directory) <= buffer_size; */ + /*@ assert numTables * sizeof(struct ttf_table_directory) <= buffer_size - sizeof(struct ttf_offset_table); */ + /*@ assert numTables <= (buffer_size - sizeof(struct ttf_offset_table)) / sizeof(struct ttf_table_directory); */ + /*@ assert \valid_read(buffer + (0 .. buffer_size - 1)); */ + /*@ assert \valid_read(buffer + (0 .. sizeof(struct ttf_offset_table) + numTables * sizeof(struct ttf_table_directory) - 1)); */ + uint64_t max_offset=0; + unsigned int i; + const struct ttf_table_directory*ttf_dir=(const struct ttf_table_directory*)&buffer[sizeof(struct ttf_offset_table)]; + /*@ assert \valid_read(ttf_dir + (0 .. numTables -1)); */ + /*@ + @ loop assigns i, max_offset; + @*/ + for(i=0; icalculated_file_size=max_offset; + file_recovery_new->data_check=&data_check_size; + file_recovery_new->file_check=&file_check_size; + } + return 1; +} + +static void register_header_check_ttf(file_stat_t *file_stat) +{ + static const unsigned char header_ttf[5]= {0x00 , 0x01, 0x00, 0x00, 0x00}; + register_header_check(0, header_ttf, sizeof(header_ttf), &header_check_ttf, file_stat); +} +#endif diff --git a/subprojects/lib/src/file_txt.c b/subprojects/lib/src/file_txt.c new file mode 100644 index 0000000..005b4d6 --- /dev/null +++ b/subprojects/lib/src/file_txt.c @@ -0,0 +1,3946 @@ +/* + + File: file_txt.c + + Copyright (C) 2005-2012 Christophe GRENIER + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_txt) +#ifdef HAVE_CONFIG_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#include /* tolower */ +#include +#include +#include "types.h" +#include "common.h" +#include "filegen.h" +#include "log.h" +#include "memmem.h" +#include "utfsize.h" +#if defined(__FRAMAC__) +#include "__fc_builtin.h" +#endif + +#if !defined(MAIN_txt) && !defined(SINGLE_FORMAT) +extern const file_hint_t file_hint_doc; +extern const file_hint_t file_hint_jpg; +extern const file_hint_t file_hint_pdf; +extern const file_hint_t file_hint_sld; +extern const file_hint_t file_hint_tiff; +extern const file_hint_t file_hint_zip; +#endif + +typedef struct +{ + const char *string; + const unsigned int len; + const char *extension; +} txt_header_t; + +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_fasttxt(file_stat_t *file_stat); +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_snz(file_stat_t *file_stat); +/*@ requires valid_register_header_check(file_stat); */ +static void register_header_check_txt(file_stat_t *file_stat); + +static const char *extension_asp="asp"; +static const char *extension_bat="bat"; +static const char *extension_c="c"; +static const char *extension_csv="csv"; +static const char *extension_cdxml="cdxml"; +static const char *extension_dc="dc"; +static const char *extension_emlx="emlx"; +static const char *extension_ers="ers"; +static const char *extension_f="f"; +static const char *extension_fb2="fb2"; +static const char *extension_fods="fods"; +static const char *extension_fst="fst"; +static const char *extension_gcs="gcs"; +static const char *extension_ghx="ghx"; +static const char *extension_go="go"; +static const char *extension_gpx="gpx"; +static const char *extension_groovy="groovy"; +static const char *extension_gsb="gsb"; +static const char *extension_h="h"; +#ifdef DJGPP +static const char *extension_html="htm"; +#else +static const char *extension_html="html"; +#endif +static const char *extension_ics="ics"; +static const char *extension_inf="inf"; +static const char *extension_ini="ini"; +#ifdef DJGPP +static const char *extension_java="jav"; +#else +static const char *extension_java="java"; +#endif +static const char *extension_json="json"; +static const char *extension_jsp="jsp"; +static const char *extension_ldif="ldif"; +static const char *extension_ly="ly"; +static const char *extension_mbox="mbox"; +static const char *extension_mol2="mol2"; +static const char *extension_php="php"; +static const char *extension_pl="pl"; +#ifdef DJGPP +static const char *extension_plist="pli"; +#else +static const char *extension_plist="plist"; +#endif +static const char *extension_pm="pm"; +static const char *extension_prproj="prproj"; +static const char *extension_py="py"; +static const char *extension_rb="rb"; +static const char *extension_rtf="rtf"; +static const char *extension_sla="sla"; +static const char *extension_smil="smil"; +static const char *extension_stl="stl"; +static const char *extension_svg="svg"; +static const char *extension_ttd="ttd"; +static const char *extension_tex="tex"; +#ifdef UTF16 +static const char *extension_utf16="utf16"; +#endif +static const char *extension_vb="vb"; +static const char *extension_vbm="vbm"; +static const char *extension_vcf="vcf"; +static const char *extension_xml="xml"; +static const char *extension_xmp="xmp"; + +const file_hint_t file_hint_fasttxt= { + .extension="tx?", + .description="Text files with header: rtf,xml,xhtml,mbox/imm,pm,ram,reg,sh,slk,stp,jad,url", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_fasttxt +}; + +const file_hint_t file_hint_snz= { + .extension="snz", + .description="Olfaction SeeNez odorama", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_snz +}; + +const file_hint_t file_hint_txt= { + .extension="txt", + .description="Other text files: txt,html,asp,bat,C,jsp,perl,php,py/emlx... scripts", + .max_filesize=PHOTOREC_MAX_FILE_SIZE, + .recover=1, + .enable_by_default=1, + .register_header_check=®ister_header_check_txt +}; + +static unsigned char ascii_char[256]; + +static const txt_header_t fasttxt_headers[] = { + /* Unix shell */ + { "#!/bin/bash", 11, "sh"}, + { "#!/bin/ksh", 10, "sh"}, + { "#!/bin/sh", 9, "sh"}, + { "#! /bin/bash", 12, "sh"}, + { "#! /bin/ksh", 11, "sh"}, + { "#! /bin/sh", 10, "sh"}, + { "#!/usr/bin/env groovy", 21, "groovy"}, + { "#!/usr/bin/env perl", 19, "pl"}, + { "#!/usr/bin/env php", 18, "php"}, + { "#!/usr/bin/env python", 21, "py"}, + { "#!/usr/bin/env ruby", 19, "rb"}, + /* Opera Hotlist bookmark/contact list/notes */ + { "Opera Hotlist version 2.0", 25, "adr"}, + /* Microsoft VB Class module */ + { "VERSION 1.0 CLASS\r\nBEGIN", 24, "cls"}, + /* Cue sheet often begins by the music genre + * or by the filename + * http://wiki.hydrogenaudio.org/index.php?title=Cue_sheet */ + { "REM GENRE ", 10, "cue"}, + { "FILE \"", 6, "cue"}, + /* Lotus Data Interchange Format */ + { "TABLE\r\n0,1\r\n", 12, "dif"}, + /* Designer, a Photobook Designer Software */ + { "vSg4q7j8GLrtf", 13, "dp"}, + { "-----BEGIN DSA PRIVATE KEY-----", 31, "dsa"}, + /* EMKA IOX file */ + { "1\t\t\t\t\tthis file\t", 16, +#ifdef DJGPP + "emk" +#else + "emka" +#endif + }, + /* Source code in go language */ + { "package main", 12, "go"}, + /* ENVI */ + { "ENVI\r\ndescription", 17, "hdr"}, + /* Java Application Descriptor + * http://en.wikipedia.org/wiki/JAD_%28file_format%29 */ + { "MIDlet-1:", 9, "jad"}, + { "{\"title\":\"\",\"id\":1,\"dateAdded\":", 31, "json"}, + { "-----BEGIN RSA PRIVATE KEY-----", 31, "key"}, + /* Lyx http://www.lyx.org */ + { "#LyX 1.", 7, "lyx"}, + { "#LyX 2.", 7, "lyx"}, + /* LilyPond http://lilypond.org*/ + { "\n\\version \"", 11, "ly"}, + /* Moving Picture Experts Group Audio Layer 3 Uniform Resource Locator */ + { "#EXTM3U", 7, "m3u"}, + /* http://www.mnemosyne-proj.org/ + * flash-card program to help you memorise question/answer pairs */ + { "--- Mnemosyne Data Base --- Format Version 2 ---", 48, "mem"}, + /* Mozilla, firefox, thunderbird msf (Mail Summary File) */ + { "//