summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml6
-rw-r--r--.whitesource11
-rw-r--r--INFO2
-rw-r--r--Makefile.am9
-rw-r--r--NEWS66
-rw-r--r--README.md4
-rw-r--r--README_dev_photorec.txt2
-rwxr-xr-xautogen.sh3
-rw-r--r--blacklist_cfi.txt5
-rwxr-xr-xcompile.sh7
-rw-r--r--configure.ac10
-rw-r--r--copr/cygwin-testdisk.spec4
-rw-r--r--copr/mingw-testdisk.spec6
-rw-r--r--copr/testdisk.spec4
m---------doc0
-rw-r--r--doc/favicon.icobin2238 -> 0 bytes
-rw-r--r--doc/photorec.icobin2238 -> 0 bytes
-rw-r--r--linux/testdisk.spec.in15
-rw-r--r--sonar-project.properties2
-rw-r--r--src/Makefile.am60
-rw-r--r--src/adv.c89
-rw-r--r--src/alignio.h64
-rw-r--r--src/analyse.c2
-rw-r--r--src/analyse.h2
-rw-r--r--src/askloc.c12
-rw-r--r--src/bfs.c56
-rw-r--r--src/bfs.h2
-rw-r--r--src/bsd.c43
-rw-r--r--src/bsd.h2
-rw-r--r--src/btrfs.c2
-rw-r--r--src/btrfs.h2
-rw-r--r--src/common.c98
-rw-r--r--src/common.h126
-rw-r--r--src/cramfs.c2
-rw-r--r--src/cramfs.h2
-rw-r--r--src/dfxml.c24
-rw-r--r--src/dfxml.h2
-rw-r--r--src/dimage.c5
-rw-r--r--src/dir.c4
-rw-r--r--src/dirn.c14
-rw-r--r--src/ewf.c243
-rw-r--r--src/ewf.h4
-rw-r--r--src/exfatp.c1
-rw-r--r--src/ext2.c2
-rw-r--r--src/ext2.h2
-rw-r--r--src/ext2_dir.c10
-rw-r--r--src/ext2_inc.h4
-rw-r--r--src/ext2_sb.c2
-rw-r--r--src/ext2_sb.h2
-rw-r--r--src/ext2grp.c4
-rw-r--r--src/ext2grp.h4
-rw-r--r--src/ext2p.c8
-rw-r--r--src/fat.c186
-rw-r--r--src/fat1x.c4
-rw-r--r--src/fat_adv.c2
-rw-r--r--src/fat_cluster.c2
-rw-r--r--src/fat_cluster.h2
-rw-r--r--src/fat_common.h24
-rw-r--r--src/fat_dir.c1
-rw-r--r--src/fat_unformat.c11
-rw-r--r--src/fatp.c1
-rw-r--r--src/fidentify.c103
-rw-r--r--src/file_ape.c9
-rw-r--r--src/file_asf.c47
-rw-r--r--src/file_bmp.c169
-rw-r--r--src/file_bz2.c2
-rw-r--r--src/file_doc.c2031
-rw-r--r--src/file_emf.c193
-rw-r--r--src/file_evtx.c80
-rw-r--r--src/file_exe.c992
-rw-r--r--src/file_exr.c58
-rw-r--r--src/file_fp7.c2
-rw-r--r--src/file_gpg.c356
-rw-r--r--src/file_gz.c38
-rw-r--r--src/file_ico.c30
-rw-r--r--src/file_jpg.c1166
-rw-r--r--src/file_list.c12
-rw-r--r--src/file_m2ts.c2
-rw-r--r--src/file_mov.c491
-rw-r--r--src/file_mp3.c793
-rw-r--r--src/file_orf.c4
-rw-r--r--src/file_pdf.c6
-rw-r--r--src/file_pf.c133
-rw-r--r--src/file_raf.c14
-rw-r--r--src/file_rw2.c4
-rw-r--r--src/file_sdsk.c66
-rw-r--r--src/file_sig.c61
-rw-r--r--src/file_skp.c2
-rw-r--r--src/file_spe.c177
-rw-r--r--src/file_steuer2014.c37
-rw-r--r--src/file_swf.c187
-rw-r--r--src/file_tiff.c99
-rw-r--r--src/file_tiff.h105
-rw-r--r--src/file_tiff_be.c598
-rw-r--r--src/file_tiff_le.c604
-rw-r--r--src/file_txt.c3786
-rw-r--r--src/file_txt.h9
-rw-r--r--src/file_wdp.c4
-rw-r--r--src/file_win.c5
-rw-r--r--src/file_wmf.c50
-rw-r--r--src/file_x3f.c8
-rw-r--r--src/file_x3i.c1
-rw-r--r--src/file_zip.c877
-rw-r--r--src/filegen.c318
-rw-r--r--src/filegen.h178
-rw-r--r--src/fuzzerfidentify.cpp6
-rw-r--r--src/gfs2.c4
-rw-r--r--src/gfs2.h2
-rw-r--r--src/godmode.c19
-rw-r--r--src/godmode.h2
-rw-r--r--src/hdaccess.c36
-rw-r--r--src/hfs.c4
-rw-r--r--src/hfs.h26
-rw-r--r--src/hfsp.c5
-rw-r--r--src/hfsp.h4
-rw-r--r--src/hpa_dco.c14
-rw-r--r--src/hpfs.c4
-rw-r--r--src/hpfs.h2
-rw-r--r--src/icon_ph.rc10
-rw-r--r--src/icon_qph.rc10
-rw-r--r--src/icon_tst.rc10
-rw-r--r--src/intrfn.c13
-rw-r--r--src/intrfn.h2
-rw-r--r--src/jfs.c77
-rw-r--r--src/jfs.h2
-rw-r--r--src/lang.h1
-rw-r--r--src/lang/qphotorec.ca.ts86
-rw-r--r--src/lang/qphotorec.cs.ts256
-rw-r--r--src/lang/qphotorec.es.ts133
-rw-r--r--src/lang/qphotorec.fr.ts86
-rw-r--r--src/lang/qphotorec.it.ts86
-rw-r--r--src/lang/qphotorec.ja.ts86
-rw-r--r--src/lang/qphotorec.pt.ts86
-rw-r--r--src/lang/qphotorec.ru.ts86
-rw-r--r--src/lang/qphotorec.tr.ts86
-rw-r--r--src/lang/qphotorec.zh_TW.ts86
-rw-r--r--src/list.h59
-rw-r--r--src/luks.c55
-rw-r--r--src/luks.h2
-rw-r--r--src/lvm.c128
-rw-r--r--src/lvm.h4
-rw-r--r--src/md.c358
-rw-r--r--src/md.h2
-rw-r--r--src/memmem.h8
-rw-r--r--src/misc.c9
-rw-r--r--src/msdos.c16
-rw-r--r--src/netware.c2
-rw-r--r--src/netware.h2
-rw-r--r--src/nodisk.c8
-rw-r--r--src/ntfs.c17
-rw-r--r--src/ntfs.h2
-rw-r--r--src/ntfs_adv.c85
-rw-r--r--src/ntfs_dir.c12
-rw-r--r--src/ntfs_fix.c2
-rw-r--r--src/ntfs_io.c7
-rw-r--r--src/ntfs_udl.c21
-rw-r--r--src/ntfsp.c11
-rw-r--r--src/partgpt.c89
-rw-r--r--src/partgpt.h2
-rw-r--r--src/partgptn.c3
-rw-r--r--src/partgptw.c3
-rw-r--r--src/parthumax.c69
-rw-r--r--src/parthumax.h2
-rw-r--r--src/parti386.c179
-rw-r--r--src/partmac.c10
-rw-r--r--src/partmac.h2
-rw-r--r--src/partnone.c64
-rw-r--r--src/partsun.c72
-rw-r--r--src/partsun.h2
-rw-r--r--src/partxbox.c71
-rw-r--r--src/partxbox.h2
-rw-r--r--src/partxboxn.c6
-rw-r--r--src/pdiskseln.c34
-rw-r--r--src/phbf.c7
-rw-r--r--src/phbs.c9
-rw-r--r--src/phcfg.c33
-rw-r--r--src/phcfg.h2
-rw-r--r--src/phcli.c3
-rw-r--r--src/phmain.c72
-rw-r--r--src/photorec.c26
-rw-r--r--src/photorec.h11
-rw-r--r--src/photorec_check_header.h4
-rw-r--r--src/phrecn.c8
-rw-r--r--src/pnext.h8
-rw-r--r--src/ppartseln.c3
-rw-r--r--src/psearch.h2
-rw-r--r--src/psearchn.c3
-rw-r--r--src/qphotorec.cpp12
-rw-r--r--src/qphotorec_locale.qrc3
-rw-r--r--src/rfs.c2
-rw-r--r--src/rfs.h2
-rw-r--r--src/savehdr.c6
-rw-r--r--src/savehdr.h4
-rw-r--r--src/sessionp.c14
-rw-r--r--src/setdate.c5
-rw-r--r--src/sudo.c31
-rw-r--r--src/sudo.h2
-rw-r--r--src/sun.c2
-rw-r--r--src/sun.h2
-rw-r--r--src/sysv.c2
-rw-r--r--src/sysv.h2
-rw-r--r--src/tdisksel.c8
-rw-r--r--src/testdisk.c64
-rw-r--r--src/texfat.c2
-rw-r--r--src/thfs.c2
-rw-r--r--src/tntfs.c2
-rw-r--r--src/tpartwr.c7
-rw-r--r--src/ufs.c2
-rw-r--r--src/ufs.h2
-rw-r--r--src/vmfs.c46
-rw-r--r--src/vmfs.h2
-rw-r--r--src/wbfs.c34
-rw-r--r--src/wbfs.h2
-rw-r--r--src/win32.c6
-rw-r--r--src/xfs.c112
-rw-r--r--src/xfs.h2
-rw-r--r--src/zfs.c47
-rw-r--r--src/zfs.h2
219 files changed, 13906 insertions, 4664 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8d98afa
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "doc"]
+ path = doc
+ url = https://github.com/cgsecurity/testdisk_documentation.git
diff --git a/.travis.yml b/.travis.yml
index f2c022a..3c9bd38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,14 +2,12 @@ dist: trusty
sudo: true
addons:
- sonarqube:
+ sonarcloud:
organization: "cgsecurity-github"
token:
secure: "HGnOsSSghmeMHCbigtEAgkV6oaJZ1xFUhvZun0oPOv7Y2XCpIPw376G5wTppgzZUZdcSsNcu63FAnWmZZDBH29mAd6K4tIw6MDqAe9UyLzWHMEMWrMQjqSMOaqetLCw4e1Zqa0kSYyZAdg4Fp7NrNjPLho1fVUJBCCrBtU1AxaPmMNkGpSZ1d9YK6rz58jNBnm7dKp0LSUFfcas88aXKuGhGYdttdPmD4/E6XQprFGMzBMk7XXV2guKgziAprhaIAF7QOs24FhAq6IKSu00JH5UAqtgeQ9+K7srv4lHeHz/N2SzLJldrei3+WNo72T8g10enJpcerZ/lS0Tl/J+5YPsC0TAXRqZmWlbSs7CR/N6CTMlckox8tUTeDyptIYhh50xZYwR+WB4ODW5vROz7EKXVfd7YHprnMZuGMw8eJaenTZ8wm/erms38rmZNsRKqoHWXxP4QwjOJumMFJVKyq1/5MkT18lA2Ajy57WcS6SjWGyRhdirV/IGbsFdS8A21PQ0ASDA7UjJrDYclmiEfy7G1OItMv739llM2z23mN/UnKO9ijPPfi3quCSEeozQiOLQpwsdmGUhAkPfBN6dAutqIrgXl/rFV3y2KNhDprWd0GBrtNhcTLWr3/5+0rrh8ntkF904QCBvR1XwOUH4z8nmGq35WXVs4Y2aafrRw1dM="
- branches:
- - master
- - dev
+os: linux
language: c
compiler:
- gcc
diff --git a/.whitesource b/.whitesource
new file mode 100644
index 0000000..004ba82
--- /dev/null
+++ b/.whitesource
@@ -0,0 +1,11 @@
+{
+ "scanSettings": {
+ "baseBranches": []
+ },
+ "checkRunSettings": {
+ "vulnerableCheckRunConclusionLevel": "failure"
+ },
+ "issueSettings": {
+ "minSeverityLevel": "LOW"
+ }
+} \ No newline at end of file
diff --git a/INFO b/INFO
index d85a196..da71e56 100644
--- a/INFO
+++ b/INFO
@@ -1,2 +1,2 @@
TestDisk & PhotoRec , https://www.cgsecurity.org
-Copyright (C) 1998-2018 Christophe GRENIER <grenier@cgsecurity.org>
+Copyright (C) 1998-2019 Christophe GRENIER <grenier@cgsecurity.org>
diff --git a/Makefile.am b/Makefile.am
index a41d194..94e0926 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,4 +59,13 @@ extras:
extrasstatic:
$(MAKE) LDFLAGS="$(LDFLAGS) -static" LIBS="$(PTHREAD_LIBS) $(LIBS)" CFLAGS="$(PTHREAD_CFLAGS) $(CFLAGS)" CXXFLAGS="$(PTHREAD_CFLAGS) $(CXXFLAGS)" extras
+session_%.framac:
+ (cd src && $(MAKE) $@) || exit 1;
+
+frama-c-%:
+ (cd src && $(MAKE) $@) || exit 1;
+
+cppcheck:
+ cppcheck --quiet --enable=all -DHAVE_CONFIG_H -I$(builddir) -I/usr/include $(srcdir)/src
+
DISTCLEANFILES = *~ core
diff --git a/NEWS b/NEWS
index f7ace91..263557d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,43 @@
Current news
-== 7.1-WIP ==
+== 7.1 ==
+== General Improvements ==
+* It should be possible to reproduce, byte for byte, every build of testdisk package in Debian https://wiki.debian.org/ReproducibleBuilds
+* Windows: Identify again the device model (Regression present in 7.0 version)
+
+== TestDisk ==
+=== Improvements ===
+* Ask confirmation when user quits the list of partitions found by TestDisk
+=== Bug fixes ===
+* Various fix for Scripted run
+
+== PhotoRec & QPhotoRec ==
+=== Improvements ===
+* Log the correct filenames in photorec.log file
+* Reduced false positives for tar
+* Fix recovery of mobius camera videos.
+* Fix recovery of progressive jpeg
+* Extract the filesize from sqlite header when available
+* Recover more fragmented files
+
+Extract of the new file formats recovered by PhotoRec:
+* .aes: Synology AES key files
+* .axp: Pinnacle Studio
+* .bdm: AVHCD index
+* .cpi: AVCHD Clip Information
+* .DS_Store: Apple Desktop Services Store
+* .dvr: RT60
+* .gi: Roxio Creator
+* .gpx: Guitar Pro 6
+* .gp4: Guitar Pro 4
+* .iam/.ipt Autodesk Inventor part
+* .icns: Apple Icon Image
+* .jsonlz4: Mozilla bookmarks
+* .lyx LyX 2.X
+* .mpl: AVHCD playlist
+* .tg Tux Guitar 1.2
+* .vdj: VirtualDJ
+* .wee: weecast
+* .xar: XAR Archive
== 7.0 ==
@@ -98,14 +136,14 @@ New file formats:
== 6.13 ==
-Fix UAC manifests for Windows, so users don't need to use right-click "Run As Administrator"
+Fix UAC manifests for Windows, so users don't need to use right-click "Run As Administrator"
TestDisk
- Fix image creation, image.dd file wasn't created (Regression introduced in 6.12)
- Detect Vmware VMFS partition
- Locate lost GFS2 partition but not yet the size
- Log HDD serial number and firmware revision
-- List NTFS Alternate Data Streams (ADS)
+- List NTFS Alternate Data Streams (ADS)
PhotoRec
- Session recovery restarts at the previous location
@@ -113,13 +151,13 @@ PhotoRec
- Better JPG recovery, there should be less cases where thumbnails were recovered instead of the picture itself.
- Handle large avi files using "AVIX" or mov files using 64-bit chunk size.
- Rename recovered pdf using the title (not perfect)
-- Major cleanup of PhotoRec core code
+- Major cleanup of PhotoRec core code
6.12
fidentify, a little utility sharing PhotoRec signature database, is now build by default. It identifies the type of data contained in a file and reports the extension as seen by PhotoRec. It is similar to the Unix file command. Add compatibility with
- libewf 20110312
- ncurses 5.8
-- ntfs-3g
+- ntfs-3g
Fix detection of Encase 6 .ewf files
TestDisk
@@ -127,14 +165,14 @@ TestDisk
- Better HPA/DCO detection: handle the case where native_max is null.
- Image Creation is now faster than previous version when there are bad sectors
- List and copy (experimental) files from exFAT filesystem
-- Improved NTFS undelete interface
+- Improved NTFS undelete interface
PhotoRec
- PhotoRec checks for EFBIG (file too large) error when writing files. It's usefull to avoid erronous message about "no free space available" when recovering to a FAT filesystem.
- Recover files from exFAT unallocated space
- Use doc/xls/ppt title to name recovered Office document, use first filename in zip archive...
- Possibility to add your own extension/custom signature to PhotoRec
-- Generated a report.xml file using Digital Forensics XML
+- Generated a report.xml file using Digital Forensics XML
6.11
TestDisk & PhotoRec 6.11 should use less CPU.
@@ -174,7 +212,7 @@ MacBook and Mac Pro.
be enabled for at least MacOSX, so users won't have to go into a command line.
- Improved Windows disk support, most internal USB card reader should now work.
- Disk model (ie. ATA ST3120026AS, _NEC DVD_RW ND-4550A...) are now reported
-under Linux.
+under Linux.
TestDisk
- New file system support has been added: encrypted LUKS, Mac HFSX, Linux Raid
@@ -243,13 +281,13 @@ InDesign .indd, Matroska .mkv, MP3 with ID3 header, MS cabinet archive
.cab, MSOffice "Open" XML .docx, .pptx, .xlsx, MS executable (PE), MS
Windows Metafile .wmf, NJStar .njx, Quickbooks .qbb and .qbw, Real Audio
.rm, registry config file .reg, RPM package .rpm, Windows registry header
-detection and Event Log .evt
+detection and Event Log .evt
6.6
General Improvements
- Encase Expert Witness Compression Format is now supported, so Computer
Forensic Experts can use TestDisk and PhotoRec more easily.
-- Under new Vista OS, harddisks are now being reported again.
+- Under new Vista OS, harddisks are now being reported again.
TestDisk
- If LBA48 support seems missing (HD bigger than 130 GB not supported by
the OS), TestDisk will warn the user. This problem is common when a user
@@ -258,7 +296,7 @@ reinstalls his OS and forgets to install the latest service patches.
some filesystem corruption has occurred; more importantly, it will allow
the user to copy whatever file data it can as well.
- FAT: Improved heuristics to find the first FAT area during boot sector
-rebuild.
+rebuild.
PhotoRec
- A new method for handling fragmented data is now used, making recovery
more reliable and faster.
@@ -269,7 +307,7 @@ efficient.
- New file formats have been added: .3g2 (Mov video family), .aif Apple
Audio, .all .cpr Cubase Song, .blend Blender, .cam Casio QV Digital Camera
Image, .flac Free Lossless Audio Codec, .mdf Microsoft SQL, .swf
-Macromedia Flash and .vcf VCard (not confused with .txt anymore)
+Macromedia Flash and .vcf VCard (not confused with .txt anymore)
6.5
TestDisk
@@ -282,7 +320,7 @@ partition to a selected directory.
PhotoRec
- New file formats have been added: AppleWorks .cwk, DIF Digital Video .dv,
DjVu .djv, Finale .mus, Incredimail .imm, .imb, iTunes mhbd, MIDI .mid,
-MS Backup, Real Media .rm & .ram, Reason .rns, ruby .rb, .xml
+MS Backup, Real Media .rm & .ram, Reason .rns, ruby .rb, .xml
- File size detection for .bmp, .pdf, .gif, Office document has been improved.
- A endless loop bug and a memory leak have been fixed.
- The I/O cache engine now caches read failure, it will speedup some recovery.
@@ -430,7 +468,7 @@ New features:
- can rebuild NTFS boot sector
- can recover JFS partition
- some advanced FAT32 functions have been added (Expert mode only)
-
+
Improvements:
- Can align partition to cylinder boundary or to head boundary.
- Doesn't abort while writing partitions if read failed.
diff --git a/README.md b/README.md
index a139291..f1a6577 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,10 @@ TestDisk and PhotoRec run under:
Both are under GNU General Public License.
+To build from source, read [INSTALL](INSTALL)
+
+See also [latest documentation](https://github.com/cgsecurity/testdisk_documentation)
+
Christophe GRENIER
[grenier@cgsecurity.org](mailto:grenier@cgsecurity.org)
[https://www.cgsecurity.org/](https://www.cgsecurity.org/)
diff --git a/README_dev_photorec.txt b/README_dev_photorec.txt
index 04d64e9..a080fdf 100644
--- a/README_dev_photorec.txt
+++ b/README_dev_photorec.txt
@@ -3,7 +3,7 @@ PhotoRec - Theory of operation:
Carvers are plugable. Each carver consists of:
struct file_hint_t - describes extension, name, max size, enable by default, etc.
-file_enable_t list_file_enable[] - array with all file hints and whether enabled or not.
+file_enable_t array_file_enable[] - array with all file hints and whether enabled or not.
phmain.c - Contains the main() and driver logic for photorec.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..9022bc3
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+mkdir config
+autoreconf --install -W all -I config
diff --git a/blacklist_cfi.txt b/blacklist_cfi.txt
new file mode 100644
index 0000000..e785280
--- /dev/null
+++ b/blacklist_cfi.txt
@@ -0,0 +1,5 @@
+# https://clang.llvm.org/docs/ControlFlowIntegrity.html
+# export CC="clang -flto -fsanitize=cfi -fvisibility=default -fsanitize-blacklist=blacklist_cfi.txt"
+# export CXX="clang++ -flto -fsanitize=cfi -fvisibility=default -fsanitize-blacklist=blacklist_cfi.txt"
+[cfi-icall]
+fun:jpeg_testdisk_alloc_src
diff --git a/compile.sh b/compile.sh
index bf7b6d3..b3c8cf5 100755
--- a/compile.sh
+++ b/compile.sh
@@ -36,6 +36,7 @@ else
fi
case "$crosscompile_target" in
"")
+ VER_LIBEWF=
;;
*-msdosdjgpp)
VER_LIBNTFS3G="2014.2.15"
@@ -57,10 +58,16 @@ case "$crosscompile_target" in
VER_NTFSPROGS=
VER_E2FSPROGS="1.42.8"
;;
+ arm-none-linux-gnueabi|powerpc-linux-gnuspe)
+ VER_LIBNTFS3G="2014.2.15"
+ VER_NTFSPROGS=
+ VER_E2FSPROGS="1.42.8"
+ ;;
*)
VER_LIBNTFS3G="2014.2.15"
VER_NTFSPROGS=
VER_E2FSPROGS="1.42.8"
+ VER_LIBEWF=
;;
esac
prefix=/usr/$crosscompile_target
diff --git a/configure.ac b/configure.ac
index 28d3240..7769464 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,11 +2,11 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.59])
-AC_INIT([testdisk],[7.1-WIP],[grenier@cgsecurity.org])
+AC_INIT([testdisk],[7.2-WIP],[grenier@cgsecurity.org])
AC_LANG(C)
sinclude(acx_pthread.m4)
sinclude(mkdir.m4)
-TESTDISKDATE="December 2018"
+TESTDISKDATE="May 2020"
AC_SUBST(TESTDISKDATE)
AC_DEFINE_UNQUOTED([TESTDISKDATE],"$TESTDISKDATE",[Date of release])
AC_CONFIG_AUX_DIR(config)
@@ -81,6 +81,10 @@ AC_ARG_WITH(jpeg-includes,
AC_ARG_WITH([ntfs],
AS_HELP_STRING([--without-ntfs],[disabled use of the ntfs library (default is NO)]))
+AC_ARG_WITH([coverity-fix],
+ AS_HELP_STRING([--with-coverity-fix],[Enable a coverity bug workaround]),
+ [CFLAGS="${CFLAGS} -D_Float128=__uint128_t -D_Float32x=int -D_Float32=int -D_Float64x=long -D_Float64=long"])
+
AC_ARG_WITH(ntfs-lib,
AS_HELP_STRING([--with-ntfs-lib=DIR],[location of the ntfs library]),
[ ntfs_lib_a="${withval}/libntfs.a"
@@ -837,7 +841,7 @@ if test "x$have_ewf" != "xyes"; then
fi
fi
#-Wconversion -Wmissing-noreturn -ffunction-sections -Wl,--gc-sections -Wl,--print-gc-sections
-for option in -Wdeclaration-after-statement -Wall -MD -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wwrite-strings -W -Wcast-align -Waggregate-return -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wsign-compare -Wnested-externs -Winline -Wdisabled-optimization -Wfloat-equal -Wmissing-format-attribute -Wmultichar -Wc++-compat -Wformat=2 -Wunreachable-code -Wvla
+for option in -Wdeclaration-after-statement -Wall -Wextra -MD -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wwrite-strings -W -Wcast-align -Waggregate-return -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wsign-compare -Wnested-externs -Winline -Wdisabled-optimization -Wfloat-equal -Wmissing-format-attribute -Wmultichar -Wc++-compat -Wformat=2 -Wunreachable-code -Wvla
do
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $option"
diff --git a/copr/cygwin-testdisk.spec b/copr/cygwin-testdisk.spec
index 83019a2..c9ccf37 100644
--- a/copr/cygwin-testdisk.spec
+++ b/copr/cygwin-testdisk.spec
@@ -1,7 +1,7 @@
%{?cygwin_package_header}
Name: cygwin-testdisk
-Version: 7.1
+Version: 7.2
Release: 0%{?dist}
Summary: TestDisk checks and undeletes partitions, PhotoRec recovers lost files
Summary(pl.UTF8): Narzędzie sprawdzające i odzyskujące partycje
@@ -111,7 +111,7 @@ PhotoRec is a signature based file recovery utility. It handles more than
%{?cygwin_debug_package}
%prep
-%setup -q -n cygwin-testdisk-%{version}
+%setup -q
%build
autoreconf -vif -I config -W all
diff --git a/copr/mingw-testdisk.spec b/copr/mingw-testdisk.spec
index 2080af0..1ae810b 100644
--- a/copr/mingw-testdisk.spec
+++ b/copr/mingw-testdisk.spec
@@ -1,7 +1,7 @@
%{?mingw_package_header}
Name: mingw-testdisk
-Version: 7.1
+Version: 7.2
Release: 0%{?dist}
Summary: TestDisk checks and undeletes partitions, PhotoRec recovers lost files
Summary(pl.UTF8): Narzędzie sprawdzające i odzyskujące partycje
@@ -27,6 +27,7 @@ BuildRequires: mingw32-ntfsprogs
BuildRequires: mingw32-openssl
BuildRequires: mingw32-pdcurses
BuildRequires: mingw32-qt5-qtbase-devel
+BuildRequires: mingw32-qt5-qttools-tools
BuildRequires: mingw32-win-iconv
BuildRequires: mingw32-zlib
@@ -41,6 +42,7 @@ BuildRequires: mingw64-ntfsprogs
BuildRequires: mingw64-openssl
BuildRequires: mingw64-pdcurses
BuildRequires: mingw64-qt5-qtbase-devel
+BuildRequires: mingw64-qt5-qttools-tools
BuildRequires: mingw64-win-iconv
BuildRequires: mingw64-zlib
@@ -116,7 +118,7 @@ PhotoRec is a signature based file recovery utility. It handles more than
%{?mingw_debug_package}
%prep
-%setup -q -n mingw-testdisk-%{version}
+%setup -q
%build
autoreconf -vif -I config -W all
diff --git a/copr/testdisk.spec b/copr/testdisk.spec
index ed612f7..0609124 100644
--- a/copr/testdisk.spec
+++ b/copr/testdisk.spec
@@ -3,7 +3,7 @@ Summary(pl.UTF8): Narzędzie sprawdzające i odzyskujące partycje
Summary(fr.UTF8): Outil pour vérifier et restaurer des partitions
Summary(ru_RU.UTF8): Программа для проверки и восстановления разделов диска
Name: testdisk
-Version: 7.1
+Version: 7.2
Release: 0%{?dist}
License: GPLv2+
Group: Applications/System
@@ -12,7 +12,9 @@ URL: https://www.cgsecurity.org/wiki/TestDisk
BuildRequires: libtool autoconf automake
BuildRequires: desktop-file-utils
BuildRequires: e2fsprogs-devel
+%if 0%{?rhel} < 8
BuildRequires: libewf-devel
+%endif
BuildRequires: libjpeg-devel
BuildRequires: ncurses-devel >= 5.2
BuildRequires: ntfs-3g-devel
diff --git a/doc b/doc
new file mode 160000
+Subproject becbcc35956102e064fc603720182113d887a18
diff --git a/doc/favicon.ico b/doc/favicon.ico
deleted file mode 100644
index d9c1441..0000000
--- a/doc/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/doc/photorec.ico b/doc/photorec.ico
deleted file mode 100644
index 74aa854..0000000
--- a/doc/photorec.ico
+++ /dev/null
Binary files differ
diff --git a/linux/testdisk.spec.in b/linux/testdisk.spec.in
index 2424a15..e47e77b 100644
--- a/linux/testdisk.spec.in
+++ b/linux/testdisk.spec.in
@@ -1,5 +1,5 @@
%define ver_progsreiserfs 0.3.1-rc8
-#% define is_wip 1
+%define is_wip 1
%{?is_wip:%define ver_wip -WIP}
Summary: Tool to check and undelete partition, PhotoRec recovers lost files
@@ -10,7 +10,6 @@ Name: @PACKAGE@
Version: @VERSION@
Release: 1%{?dist}
License: GPLv2+
-Group: Applications/System
Source0: https://www.cgsecurity.org/testdisk-%{version}%{?ver_wip}.tar.bz2
Source1: progsreiserfs-%ver_progsreiserfs.tar.gz
Patch0: progsreiserfs-journal.patch
@@ -62,7 +61,6 @@ PhotoRec is a signature based file recovery utility. It handles more than
%package -n qphotorec
Summary: Signature based file carver. Recover lost files
-Group: Applications/System
%description -n qphotorec
QPhotoRec is a Qt version of PhotoRec. It is a signature based file recovery
@@ -111,10 +109,11 @@ fi
/usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%files
-%doc AUTHORS COPYING ChangeLog NEWS README.md THANKS
-%attr(755,root,root) %{_bindir}/fidentify
-%attr(755,root,root) %{_bindir}/photorec
-%attr(755,root,root) %{_bindir}/testdisk
+%doc AUTHORS ChangeLog NEWS README.md THANKS
+%license COPYING
+%{_bindir}/fidentify
+%{_bindir}/photorec
+%{_bindir}/testdisk
%{_mandir}/man8/fidentify.8*
%{_mandir}/man8/photorec.8*
%{_mandir}/man8/testdisk.8*
@@ -123,7 +122,7 @@ fi
%{_mandir}/zh_CN/man8/testdisk.8*
%files -n qphotorec
-%attr(755,root,root) %{_bindir}/qphotorec
+%{_bindir}/qphotorec
%{_mandir}/man8/qphotorec.8*
%{_mandir}/zh_CN/man8/qphotorec.8*
%{_datadir}/applications/qphotorec.desktop
diff --git a/sonar-project.properties b/sonar-project.properties
index 1cd2e65..e5f70a7 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -2,7 +2,7 @@
sonar.projectKey=testdisk
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=testdisk
-sonar.projectVersion=7.1
+sonar.projectVersion=7.2
# =====================================================
# Meta-data for the project
diff --git a/src/Makefile.am b/src/Makefile.am
index 52ea960..aea1b3b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,3 +1,24 @@
+.PRECIOUS: session_%.framac
+FRAMA_C_FLAGS=-machdep x86_64 \
+ -warn-left-shift-negative \
+ -warn-right-shift-negative \
+ -warn-signed-downcast \
+ -warn-signed-overflow \
+ -warn-unsigned-downcast \
+ -warn-unsigned-overflow \
+ -rte \
+ -eva \
+ -eva-slevel 6 \
+ -eva-warn-undefined-pointer-comparison none \
+ -eva-ignore-recursive-calls \
+ -then \
+ -wp \
+ -wp-dynamic \
+ -wp-steps 100000 \
+ -wp-split -wp-literals \
+ -wp-timeout 10 -pp-annot \
+ -kernel-msg-key pp
+
.rc.o:
$(WINDRES) --include-dir $(srcdir) $< $@
@@ -120,7 +141,9 @@ file_C = filegen.c \
file_emf.c \
file_ess.c \
file_evt.c \
+ file_evtx.c \
file_exe.c \
+ file_exr.c \
file_exs.c \
file_ext.c \
file_ext2.c \
@@ -283,6 +306,7 @@ file_C = filegen.c \
file_rw2.c \
file_rx2.c \
file_save.c \
+ file_sdsk.c \
file_ses.c \
file_sgcta.c \
file_shn.c \
@@ -360,15 +384,16 @@ file_C = filegen.c \
file_H = ext2.h ext2_common.h filegen.h file_doc.h file_jpg.h file_gz.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
-photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c pdisksel.c phcli.c poptions.c sessionp.c setdate.c dfxml.c
+photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c pdisksel.c poptions.c sessionp.c setdate.c dfxml.c
-photorec_H = photorec.h phcfg.h addpart.h chgarch.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h geometry.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h pdisksel.h phcli.h poptions.h sessionp.h setdate.h dfxml.h
+photorec_H = photorec.h phcfg.h addpart.h chgarch.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h geometry.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h pdisksel.h poptions.h sessionp.h setdate.h dfxml.h
-photorec_ncurses_C = addpartn.c askloc.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdiskseln.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartseln.c psearchn.c
-photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h photorec_check_header.h
+photorec_ncurses_C = addpartn.c askloc.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdiskseln.c pfree_whole.c phbf.c phbs.c phcli.c phnc.c phrecn.c ppartseln.c psearchn.c
+photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phcli.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h photorec_check_header.h
QT_TS = \
lang/qphotorec.ca.ts \
+ lang/qphotorec.cs.ts \
lang/qphotorec.es.ts \
lang/qphotorec.fr.ts \
lang/qphotorec.it.ts \
@@ -401,6 +426,33 @@ small: $(sbin_PROGRAMS) $(bin_PROGRAMS)
extras: $(EXTRA_PROGRAMS)
+frama-c-%: session_%.framac
+ frama-c-gui -load $^
+
+session_doc.framac: file_doc.c common.c filegen.c log.c setdate.c
+ gcc $(CFLAGS) -DMAIN_doc -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_doc -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_jpg.framac: file_jpg.c file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c suspend_no.c setdate.c
+ gcc $(CFLAGS) -DMAIN_jpg -DHAVE_CONFIG_H -O -o demo -I.. $^ -ljpeg
+ frama-c $^ -cpp-extra-args="-DMAIN_jpg -DHAVE_CONFIG_H -D__x86_64__ -I/usr/include -I.. -I $(frama-c -print-path)/libc" $(FRAMA_C_FLAGS) -save $@ 2>&1 | tee session_jpg.log
+
+session_tiff_be.framac: file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_be -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_tiff_le.framac: file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_le -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_%.framac: file_%.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_$* -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_$* -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_fidentify.framac: fidentify.c common.c misc.c filegen.c log.c setdate.c file_bmp.c file_list.c
+ gcc $(CFLAGS) -DMAIN_fidentify -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_fidentify -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
moc_qphotorec.cpp: qphotorec.h
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $< -o $@
diff --git a/src/adv.c b/src/adv.c
index 0d53068..163cd68 100644
--- a/src/adv.c
+++ b/src/adv.c
@@ -79,12 +79,43 @@ extern const arch_fnct_t arch_xbox;
#define DEFAULT_IMAGE_NAME "image.dd"
-static int is_exfat(const partition_t *partition);
-static int is_hfs(const partition_t *partition);
-static int is_hfsp(const partition_t *partition);
-static int is_linux(const partition_t *partition);
-static int is_part_hfs(const partition_t *partition);
-static int is_part_hfsp(const partition_t *partition);
+static int is_part_hfs(const partition_t *partition)
+{
+ if( partition->part_type_i386 == P_HFS ||
+ partition->part_type_mac == PMAC_HFS)
+ return 1;
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
+ return 1;
+ return 0;
+}
+
+static int is_part_hfsp(const partition_t *partition)
+{
+ if( partition->part_type_i386 == P_HFSP ||
+ partition->part_type_mac == PMAC_HFS )
+ return 1;
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
+ return 1;
+ return 0;
+}
+
+int is_part_linux(const partition_t *partition)
+{
+ if(partition->arch==&arch_i386 && partition->part_type_i386==P_LINUX)
+ return 1;
+ if(partition->arch==&arch_sun && partition->part_type_sun==PSUN_LINUX)
+ return 1;
+ if(partition->arch==&arch_mac && partition->part_type_mac==PMAC_LINUX)
+ return 1;
+ if(partition->arch==&arch_gpt &&
+ (
+ guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_DATA)==0 ||
+ guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_HOME)==0 ||
+ guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_SRV)==0
+ ))
+ return 1;
+ return 0;
+}
static int is_exfat(const partition_t *partition)
{
@@ -128,46 +159,8 @@ static int is_linux(const partition_t *partition)
return 0;
}
-static int is_part_hfs(const partition_t *partition)
-{
- if( partition->part_type_i386 == P_HFS ||
- partition->part_type_mac == PMAC_HFS)
- return 1;
- if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
- return 1;
- return 0;
-}
-
-static int is_part_hfsp(const partition_t *partition)
-{
- if( partition->part_type_i386 == P_HFSP ||
- partition->part_type_mac == PMAC_HFS )
- return 1;
- if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
- return 1;
- return 0;
-}
-
-int is_part_linux(const partition_t *partition)
-{
- if(partition->arch==&arch_i386 && partition->part_type_i386==P_LINUX)
- return 1;
- if(partition->arch==&arch_sun && partition->part_type_sun==PSUN_LINUX)
- return 1;
- if(partition->arch==&arch_mac && partition->part_type_mac==PMAC_LINUX)
- return 1;
- if(partition->arch==&arch_gpt &&
- (
- guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_DATA)==0 ||
- guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_HOME)==0 ||
- guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_SRV)==0
- ))
- return 1;
- return 0;
-}
-
#ifdef HAVE_NCURSES
-static void interface_adv_ncurses(disk_t *disk, const int rewrite, list_part_t *list_part, list_part_t *current_element, const int offset)
+static void interface_adv_ncurses(disk_t *disk, const int rewrite, list_part_t *list_part, const list_part_t *current_element, const int offset)
{
list_part_t *element;
int i;
@@ -369,7 +362,7 @@ static int adv_menu_boot_selected(disk_t *disk, partition_t *partition, const in
return 0;
}
-static void adv_menu_image_selected(disk_t *disk, partition_t *partition, char **current_cmd)
+static void adv_menu_image_selected(disk_t *disk, const partition_t *partition, char **current_cmd)
{
char *dst_path;
#ifdef HAVE_NCURSES
@@ -398,7 +391,7 @@ static void adv_menu_image_selected(disk_t *disk, partition_t *partition, char *
}
}
-static void adv_menu_undelete_selected(disk_t *disk, partition_t *partition, const int verbose, char **current_cmd)
+static void adv_menu_undelete_selected(disk_t *disk, const partition_t *partition, const int verbose, char **current_cmd)
{
if(partition->sb_offset!=0 && partition->sb_size>0)
{
@@ -424,7 +417,7 @@ static void adv_menu_undelete_selected(disk_t *disk, partition_t *partition, con
}
}
-static void adv_menu_list_selected(disk_t *disk, partition_t *partition, const int verbose, const int expert, char **current_cmd)
+static void adv_menu_list_selected(disk_t *disk, const partition_t *partition, const int verbose, const int expert, char **current_cmd)
{
if(partition->sb_offset!=0 && partition->sb_size>0)
{
diff --git a/src/alignio.h b/src/alignio.h
index 8bd1344..0541f6b 100644
--- a/src/alignio.h
+++ b/src/alignio.h
@@ -19,11 +19,26 @@
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-static int align_pread(int (*fnct_pread)(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset),
+
+/*@
+ @ requires \valid_function(fnct_pread);
+ @ requires \valid(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 disk_car->rbuffer == \null || (\freeable(disk_car->rbuffer) && disk_car->rbuffer_size > 0);
+ @ ensures disk_car->rbuffer == \null || (\freeable(disk_car->rbuffer) && disk_car->rbuffer_size > 0);
+ @*/
+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) &&
@@ -31,24 +46,44 @@ static int align_pread(int (*fnct_pread)(disk_t *disk_car, void *buf, const unsi
)
{
int res;
- if(disk_car->rbuffer==NULL)
- disk_car->rbuffer_size=128*512;
- while(disk_car->rbuffer_size < count_new)
+ if(disk_car->rbuffer_size < count_new)
{
free(disk_car->rbuffer);
disk_car->rbuffer=NULL;
- disk_car->rbuffer_size*=2;
}
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 \freeable(disk_car->rbuffer); */
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; */
return (res < (signed)count ? res : (signed)count );
}
return fnct_pread(disk_car, buf, count, offset_new);
}
-static int align_pwrite(int (*fnct_pread)(disk_t *disk_car, void *buf, const unsigned int count, const uint64_t offset),
+/*@
+ @ requires \valid_function(fnct_pread);
+ @ requires \valid_function(fnct_pwrite);
+ @ requires \valid(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 disk_car->wbuffer == \null || \freeable(disk_car->wbuffer);
+ @ ensures disk_car->wbuffer == \null || \freeable(disk_car->wbuffer);
+ @*/
+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)
{
@@ -60,16 +95,23 @@ static int align_pwrite(int (*fnct_pread)(disk_t *disk_car, void *buf, const uns
)
{
int tmp;
- if(disk_car->wbuffer==NULL)
- disk_car->wbuffer_size=128*512;
- while(disk_car->wbuffer_size < count_new)
+ if(disk_car->wbuffer_size < count_new)
{
free(disk_car->wbuffer);
disk_car->wbuffer=NULL;
- disk_car->wbuffer_size*=2;
}
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 \freeable(disk_car->wbuffer); */
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");
@@ -77,8 +119,8 @@ static int align_pwrite(int (*fnct_pread)(disk_t *disk_car, void *buf, const uns
}
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; */
return (tmp < (signed)count ? tmp : (signed)count);
}
return fnct_pwrite(disk_car, buf, count, offset_new);
}
-
diff --git a/src/analyse.c b/src/analyse.c
index b121986..46cf036 100644
--- a/src/analyse.c
+++ b/src/analyse.c
@@ -220,7 +220,7 @@ int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partit
return 0;
}
-int search_type_1(const unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind)
+int search_type_1(const unsigned char *buffer, const disk_t *disk, partition_t *partition, const int verbose, const int dump_ind)
{
const struct disklabel *bsd_header=(const struct disklabel *)(buffer+0x200);
const struct disk_super_block *beos_block=(const struct disk_super_block*)(buffer+0x200);
diff --git a/src/analyse.h b/src/analyse.h
index 82c1b61..aaf1002 100644
--- a/src/analyse.h
+++ b/src/analyse.h
@@ -24,7 +24,7 @@ extern "C" {
#endif
int search_type_0(const unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
-int search_type_1(const unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_1(const unsigned char *buffer, const disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind);
int search_type_2(const unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
int search_type_8(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
int search_type_16(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
diff --git a/src/askloc.c b/src/askloc.c
index 792ed2b..4ca1130 100644
--- a/src/askloc.c
+++ b/src/askloc.c
@@ -99,7 +99,7 @@ char *get_default_location(void)
static void set_parent_directory(char *dst_directory);
static void dir_aff_entry(WINDOW *window, file_info_t *file_info);
-static int aff_txt(int line, WINDOW *window, const char *_format, ...) __attribute__ ((format (printf, 3, 4)));
+static int aff_txt(const int line, WINDOW *window, const char *_format, ...) __attribute__ ((format (printf, 3, 4)));
#if defined(DJGPP) || defined(__OS2__)
void get_dos_drive_list(struct td_list_head *list);
@@ -229,7 +229,7 @@ char *ask_location(const char*msg, const char *src_dir, const char *dst_org)
break;
/* hide filename beginning by '.' except '.' and '..' */
if(dir_entrie->d_name[0]=='.' &&
- !dir_entrie->d_name[1]=='\0' &&
+ !(dir_entrie->d_name[1]=='\0') &&
!(dir_entrie->d_name[1]=='.' && dir_entrie->d_name[2]=='\0'))
continue;
if(strlen(dst_directory) + 1 + strlen(dir_entrie->d_name) + 1 <= sizeof(current_file)
@@ -519,7 +519,6 @@ char *ask_location(const char*msg, const char *src_dir, const char *dst_org)
file_info=td_list_entry(current_file, file_info_t, list);
if(current_file!=&dir_list.list &&
(LINUX_S_ISDIR(file_info->st_mode) || LINUX_S_ISLNK(file_info->st_mode)))
- if(current_file!=&dir_list.list)
{
if(strcmp(file_info->name, ".")==0)
{
@@ -583,13 +582,14 @@ static void dir_aff_entry(WINDOW *window, file_info_t *file_info)
wprintw(window, " %s %s", datestr, file_info->name);
}
-static int aff_txt(int line, WINDOW *window, const char *_format, ...)
+static int aff_txt(const int line, WINDOW *window, const char *_format, ...)
{
+ int next_line;
va_list ap;
va_start(ap,_format);
- line=vaff_txt(line, window, _format, ap);
+ next_line=vaff_txt(line, window, _format, ap);
va_end(ap);
- return line;
+ return next_line;
}
#endif
diff --git a/src/bfs.c b/src/bfs.c
index 1854ee8..fb8f35d 100644
--- a/src/bfs.c
+++ b/src/bfs.c
@@ -34,8 +34,31 @@
#include "fnctdsk.h"
#include "log.h"
-static void set_BeFS_info(const struct disk_super_block *beos_block, partition_t *partition);
-static int test_BeFS(disk_t *disk_car, const struct disk_super_block*beos_block, const partition_t *partition, const int dump_ind);
+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)
{
@@ -56,37 +79,14 @@ int check_BeFS(disk_t *disk_car,partition_t *partition)
return 0;
}
-int recover_BeFS(disk_t *disk_car, const struct disk_super_block *beos_block, partition_t *partition, const int dump_ind)
+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;
}
-
-static int test_BeFS(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;
-}
-
-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);
-}
diff --git a/src/bfs.h b/src/bfs.h
index 14087a2..9e78446 100644
--- a/src/bfs.h
+++ b/src/bfs.h
@@ -83,7 +83,7 @@ struct disk_super_block /* super block as it is on disk */
#define BFS_BIG_ENDIAN 0x42494745 /* BIGE */
/* int test_beos(struct disk_super_block *,partition_t); */
int check_BeFS(disk_t *disk_car, partition_t *partition);
-int recover_BeFS(disk_t *disk_car, const struct disk_super_block *beos_block, partition_t *partition, const int dump_ind);
+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" */
diff --git a/src/bsd.c b/src/bsd.c
index e67d9b0..13dd9b9 100644
--- a/src/bsd.c
+++ b/src/bsd.c
@@ -33,28 +33,8 @@
#include "bsd.h"
#include "intrf.h"
#include "log.h"
-static int test_BSD(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);
-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;
-}
-
-static int test_BSD(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)
+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;
@@ -125,7 +105,26 @@ static int test_BSD(disk_t *disk_car, const struct disklabel*bsd_header, const p
return 0;
}
-int recover_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind)
+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;
diff --git a/src/bsd.h b/src/bsd.h
index 1a14807..bd94e54 100644
--- a/src/bsd.h
+++ b/src/bsd.h
@@ -169,7 +169,7 @@ struct disklabel {
#define TST_FS_RAID 15 /* RAIDFrame drive */
#define TST_FS_JFS2 21 /* IBM JFS2 */
int check_BSD(disk_t *disk_car,partition_t *partition,const int verbose,const unsigned int max_partitions);
-int recover_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind);
+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
diff --git a/src/btrfs.c b/src/btrfs.c
index 062b52e..4eef0bb 100644
--- a/src/btrfs.c
+++ b/src/btrfs.c
@@ -74,7 +74,7 @@ int check_btrfs(disk_t *disk_car,partition_t *partition)
Primary superblock is at 1024 (SUPERBLOCK_OFFSET)
Group 0 begin at s_first_data_block
*/
-int recover_btrfs(disk_t *disk, const struct btrfs_super_block *sb, partition_t *partition, const int verbose, const int dump_ind)
+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;
diff --git a/src/btrfs.h b/src/btrfs.h
index d28c590..83ad564 100644
--- a/src/btrfs.h
+++ b/src/btrfs.h
@@ -139,7 +139,7 @@ struct btrfs_super_block {
} __attribute__ ((gcc_struct, __packed__));
int check_btrfs(disk_t *disk_car,partition_t *partition);
-int recover_btrfs(disk_t *disk_car, const struct btrfs_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);
+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" */
diff --git a/src/common.c b/src/common.c
index 3b1f45b..04ed1aa 100644
--- a/src/common.c
+++ b/src/common.c
@@ -24,6 +24,11 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#ifdef __FRAMAC__
+#undef HAVE_POSIX_MEMALIGN
+#undef HAVE_MEMALIGN
+#endif
#include <stdio.h>
#include <ctype.h>
@@ -51,8 +56,6 @@
static int32_t secwest=0;
-static unsigned int up2power_aux(const unsigned int number);
-
/* coverity[+alloc] */
void *MALLOC(size_t size)
{
@@ -167,21 +170,16 @@ char * strcasestr (const char *haystack, const char *needle)
}
#endif
-#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__)
+#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__) && !defined(__FRAMAC__)
struct tm *localtime_r(const time_t *timep, struct tm *result)
{
return localtime(timep);
}
#endif
-unsigned int up2power(const unsigned int number)
-{
- /* log_trace("up2power(%u)=>%u\n",number, (1<<up2power_aux(number-1))); */
- if(number==0)
- return 1;
- return (1<<up2power_aux(number-1));
-}
-
+/*@
+ @ assigns \nothing;
+ @*/
static unsigned int up2power_aux(const unsigned int number)
{
if(number==0)
@@ -190,6 +188,13 @@ static unsigned int up2power_aux(const unsigned int number)
return(1+up2power_aux(number/2));
}
+unsigned int up2power(const unsigned int number)
+{
+ if(number==0)
+ return 1;
+ return (1<<up2power_aux(number-1));
+}
+
void set_part_name(partition_t *partition, const char *src, const unsigned int max_size)
{
unsigned int i;
@@ -225,22 +230,53 @@ char* strip_dup(char* 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)
-int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
+time_t date_dos2unix(const unsigned short f_time, const unsigned short f_date)
{
- static const int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ 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 */
- int month,year,secs;
+ unsigned long int day,leap_day,month,year,days;
+ unsigned long int secs;
+ year = f_date >> 9;
+ month = td_max(1, (f_date >> 5) & 0xf);
+ day = td_max(1, f_date & 0x1f) - 1;
+
+ leap_day = (year + 3) / 4;
+ if (year > YEAR_2100) /* 2100 isn't leap year */
+ {
+ /*@ assert year > YEAR_2100 && leap_day > (YEAR_2100 + 3)/4; */
+ leap_day--;
+ }
+ if (IS_LEAP_YEAR(year) && month > 2)
+ leap_day++;
+ 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;
- /* first subtract and mask after that... Otherwise, if
- f_date == 0, bad things happen */
- month = ((f_date >> 5) - 1) & 15;
- year = f_date >> 9;
- secs = (f_time & 31)*2+60*((f_time >> 5) & 63)+(f_time >> 11)*3600+86400*
- ((f_date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
- month < 2 ? 1 : 0)+3653);
- /* days since 1.1.70 plus 80's leap day */
return secs+secwest;
}
@@ -287,23 +323,39 @@ time_t td_ntfs2utc (int64_t ntfstime)
return (ntfstime - (NTFS_TIME_OFFSET)) / 10000000;
}
-int check_command(char **current_cmd, const char *cmd, size_t n)
+int check_command(char **current_cmd, const char *cmd, const size_t n)
{
const int res=strncmp(*current_cmd, cmd, n);
if(res==0)
+ {
(*current_cmd)+=n;
+ /*@ assert valid_read_string(*current_cmd); */
+ return 0;
+ }
+ /*@ assert valid_read_string(*current_cmd); */
return res;
}
void skip_comma_in_command(char **current_cmd)
{
+ /*@
+ loop invariant valid_read_string(*current_cmd);
+ loop assigns *current_cmd;
+ */
while(*current_cmd[0]==',')
+ {
(*current_cmd)++;
+ }
+ /*@ assert valid_read_string(*current_cmd); */
}
uint64_t get_int_from_command(char **current_cmd)
{
uint64_t tmp=0;
+ /*@
+ loop invariant valid_read_string(*current_cmd);
+ loop assigns *current_cmd, tmp;
+ */
while(*current_cmd[0] >='0' && *current_cmd[0] <= '9')
{
tmp = tmp * 10 + *current_cmd[0] - '0';
diff --git a/src/common.h b/src/common.h
index c031222..886d4dd 100644
--- a/src/common.h
+++ b/src/common.h
@@ -24,6 +24,12 @@
#ifdef __cplusplus
extern "C" {
#endif
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_NCURSES
+#endif
+#if defined(__FRAMAC__) && defined(HAVE_STRING_H)
+#include <string.h>
+#endif
typedef struct efi_guid_s efi_guid_t;
struct efi_guid_s
@@ -105,6 +111,7 @@ struct efi_guid_s
#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
@@ -122,6 +129,9 @@ struct efi_guid_s
((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 \
@@ -143,60 +153,66 @@ struct efi_guid_s
((const efi_guid_t){le32(0x516e7cb8),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
-#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_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_METADATA \
- ((const efi_guid_t){le32(0x5808c8aa),le16(0x7e8f),le16(0x42e0),0x85,0xd2,{0xe1,0xe9,0x04,0x34,0xcf,0xb3}})
#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_RAID \
- ((const efi_guid_t){le32(0xa19d880f),le16(0x05fc),le16(0x4d3b),0xa0,0x06,{0x74,0x3f,0x0f,0x84,0x91,0x1e}})
-#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_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_RESERVED \
- ((const efi_guid_t){le32(0x8da63339),le16(0x0007),le16(0x60c0),0xc4,0x36,{0x08,0x3a,0xc8,0x23,0x09,0x08}})
#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_UFS \
- ((const efi_guid_t){le32(0x55465300),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_BOOT \
- ((const efi_guid_t){le32(0x426f6f74),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_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_BACKUP \
- ((const efi_guid_t){le32(0x6a8b642b),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
@@ -217,6 +233,9 @@ struct efi_guid_s
#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
@@ -348,7 +367,7 @@ struct arch_fnct_struct
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)(list_part_t *list_part);
+ 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);
@@ -433,13 +452,42 @@ struct my_data_struct
uint64_t offset;
};
+/*@
+ @ requires size > 0;
+ @ ensures \valid(((char *)\result)+(0..size-1));
+ @ ensures zero_initialization: \subset(((char *)\result)[0..size-1], {0});
+ @*/
void *MALLOC(size_t size);
+
+/*@
+ @ assigns \nothing;
+ @*/
unsigned int up2power(const unsigned int number);
+
+/*@
+ @ requires \valid(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_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);
-int date_dos2unix(const unsigned short f_time,const unsigned short f_date);
+
+/*@ 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
@@ -503,7 +551,11 @@ int strncasecmp(const char * s1, const char * s2, size_t len);
#ifndef HAVE_STRCASESTR
char * strcasestr (const char *haystack, const char *needle);
#endif
-#if ! defined(HAVE_LOCALTIME_R) && ! defined(__MINGW32__)
+#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
/*
@@ -524,8 +576,34 @@ struct tm *localtime_r(const time_t *timep, struct tm *result);
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
-int check_command(char **current_cmd, const char *cmd, size_t n);
+/*@
+ @ requires \valid(current_cmd);
+ @ requires valid_read_string(*current_cmd);
+ @ requires valid_read_string(cmd);
+ @ requires \separated(cmd+(..), current_cmd);
+ @ requires strlen(cmd) == n;
+ @ assigns *current_cmd;
+ @ assigns \result \from indirect:(*current_cmd)[0 .. n-1], indirect:cmd[0 ..n-1], indirect:n;
+ @ ensures valid_read_string(*current_cmd);
+ @ ensures \result == 0 ==> *current_cmd == \old(*current_cmd) + n;
+ @ ensures \result != 0 ==> *current_cmd == \old(*current_cmd);
+ @*/
+int check_command(char **current_cmd, const char *cmd, const size_t n);
+
+/*@
+ @ requires \valid(current_cmd);
+ @ requires valid_read_string(*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);
+ @ 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" */
diff --git a/src/cramfs.c b/src/cramfs.c
index c547fb5..e5afeb0 100644
--- a/src/cramfs.c
+++ b/src/cramfs.c
@@ -76,7 +76,7 @@ static int test_cramfs(const disk_t *disk_car, const struct cramfs_super *sb, co
return 0;
}
-int recover_cramfs(disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind)
+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;
diff --git a/src/cramfs.h b/src/cramfs.h
index c525234..4b9b57f 100644
--- a/src/cramfs.h
+++ b/src/cramfs.h
@@ -83,7 +83,7 @@ struct cramfs_super {
int check_cramfs(disk_t *disk_car,partition_t *partition,const int verbose);
-int recover_cramfs(disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind);
+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" */
diff --git a/src/dfxml.c b/src/dfxml.c
index c9da693..947436e 100644
--- a/src/dfxml.c
+++ b/src/dfxml.c
@@ -24,6 +24,11 @@
#include <config.h>
#endif
+#if defined(__FRAMAC__)
+#undef HAVE_LIBEWF
+#undef HAVE_SYS_UTSNAME_H
+#endif
+
#ifdef ENABLE_DFXML
#include <stdio.h>
#ifdef HAVE_STDLIB_H
@@ -200,11 +205,13 @@ void xml_add_DFXML_creator(const char *package, const char *version)
#ifdef RECORD_COMPILATION_DATE
xml_out2s("compilation_date", get_compilation_date());
#endif
+#ifndef MAIN_photorec
xml_printf("<library name='libext2fs' version='%s'/>\n", td_ext2fs_version());
xml_printf("<library name='libewf' version='%s'/>\n", td_ewf_version());
xml_printf("<library name='libjpeg' version='%s'/>\n", td_jpeg_version());
xml_printf("<library name='libntfs' version='%s'/>\n", td_ntfs_version());
xml_printf("<library name='zlib' version='%s'/>\n", td_zlib_version());
+#endif
xml_pop("build_environment");
xml_push("execution_environment","");
#if defined(__CYGWIN__) || defined(__MINGW32__)
@@ -238,18 +245,8 @@ void xml_add_DFXML_creator(const char *package, const char *version)
#endif
#ifdef HAVE_GETEUID
xml_out2i("uid", geteuid());
-#if 0
-#ifdef HAVE_GETPWUID
- {
- struct passwd *tmp=getpwuid(getuid());
- if(tmp != NULL)
- {
- xml_out2s("username", tmp->pw_name);
- }
- }
-#endif
-#endif
#endif
+#if !defined(__FRAMAC__)
{
char outstr[200];
const time_t t = time(NULL);
@@ -261,11 +258,12 @@ void xml_add_DFXML_creator(const char *package, const char *version)
xml_out2s("start_time", outstr);
}
}
+#endif
xml_pop("execution_environment");
xml_pop("creator");
}
-void xml_setup(disk_t *disk, const partition_t *partition)
+void xml_setup(const disk_t *disk, const partition_t *partition)
{
if(xml_handle==NULL)
return;
@@ -319,7 +317,7 @@ static const char *relative_name(const char *fname)
/* See filegen.h for the definition of file_recovery_struct */
void xml_log_file_recovered(const file_recovery_t *file_recovery)
{
- struct td_list_head *tmp;
+ const struct td_list_head *tmp;
uint64_t file_size=0;
if(xml_handle==NULL)
return;
diff --git a/src/dfxml.h b/src/dfxml.h
index 9f0b16c..c6cd34b 100644
--- a/src/dfxml.h
+++ b/src/dfxml.h
@@ -35,7 +35,7 @@ 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);
-void xml_setup(disk_t *disk, const partition_t *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);
diff --git a/src/dimage.c b/src/dimage.c
index d1f3483..6e65118 100644
--- a/src/dimage.c
+++ b/src/dimage.c
@@ -41,6 +41,9 @@
#include <assert.h>
#include <string.h>
#include <errno.h>
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
#include "types.h"
#include "common.h"
#include "intrf.h"
@@ -123,6 +126,7 @@ int disk_image(disk_t *disk, const partition_t *partition, const char *image_dd)
free(buffer);
return -1;
}
+#if !defined(__FRAMAC__)
if(fstat(disk_dst, &stat_buf)==0)
{
int res=1;
@@ -136,6 +140,7 @@ int disk_image(disk_t *disk, const partition_t *partition, const char *image_dd)
src_offset+=dst_offset;
}
}
+#endif
src_offset_old=src_offset;
#ifdef HAVE_NCURSES
window=newwin(LINES, COLS, 0, 0); /* full screen */
diff --git a/src/dir.c b/src/dir.c
index f1f0fdf..06bd544 100644
--- a/src/dir.c
+++ b/src/dir.c
@@ -22,6 +22,10 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#ifdef __FRAMAC__
+#undef HAVE_CHMOD
+#endif
#include <stdio.h>
#ifdef HAVE_STRING_H
diff --git a/src/dirn.c b/src/dirn.c
index ab18db9..050129f 100644
--- a/src/dirn.c
+++ b/src/dirn.c
@@ -202,7 +202,7 @@ static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_
waddstr(window,", ");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,"h");
+ waddstr(window,"'h'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
if((dir_data->param&FLAG_LIST_DELETED)==0)
@@ -215,7 +215,7 @@ static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_
waddstr(window,", ");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,"h");
+ waddstr(window,"'h'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
if((dir_data->param&FLAG_LIST_ADS)==0)
@@ -226,7 +226,7 @@ static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_
wmove(window,LINES-2,4);
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,"q");
+ waddstr(window,"'q'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
waddstr(window," to quit");
@@ -235,13 +235,13 @@ static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_
waddstr(window,", ");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,":");
+ waddstr(window,"':'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
waddstr(window," to select the current file, ");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,"a");
+ waddstr(window,"'a'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
if((status&FILE_STATUS_MARKED)==FILE_STATUS_MARKED)
@@ -250,13 +250,13 @@ static long int dir_aff_ncurses(disk_t *disk, const partition_t *partition, dir_
waddstr(window," to deselect all files");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- mvwaddstr(window,LINES-1,4,"C");
+ mvwaddstr(window,LINES-1,4,"'C'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
waddstr(window," to copy the selected files, ");
if(has_colors())
wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
- waddstr(window,"c");
+ waddstr(window,"'c'");
if(has_colors())
wbkgdset(window,' ' | COLOR_PAIR(0));
waddstr(window," to copy the current file");
diff --git a/src/ewf.c b/src/ewf.c
index 7bf502c..e7c6391 100644
--- a/src/ewf.c
+++ b/src/ewf.c
@@ -23,6 +23,10 @@
#include <config.h>
#endif
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_LIBEWF
+#endif
+
#ifdef HAVE_STRING_H
#include <string.h>
#endif
@@ -96,34 +100,30 @@ struct info_fewf_struct
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;
-#if !defined( HAVE_LIBEWF_V2_API ) && defined( HAVE_GLOB_H )
- glob_t globbuf;
-#endif
-#if defined( HAVE_LIBEWF_V2_API )
libewf_error_t *ewf_error = NULL;
-#endif
data=(struct info_fewf_struct *)MALLOC(sizeof(struct info_fewf_struct));
- memset(data, 0, 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
-#if defined( HAVE_LIBEWF_V2_API )
libewf_notify_set_stream( stderr, NULL );
libewf_notify_set_verbose( 1 );
-#else
- libewf_set_notify_values( stderr, 1 );
-#endif
#endif
-#if defined( HAVE_LIBEWF_V2_API )
if( libewf_glob(
data->file_name,
strlen(data->file_name),
@@ -140,36 +140,9 @@ disk_t *fewf_init(const char *device, const int mode)
free(data);
return NULL;
}
-#elif 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_files<globbuf.gl_pathc; num_files++) {
- filenames[num_files]=globbuf.gl_pathv[num_files];
- }
- }
- }
- if(filenames==NULL)
- {
- globfree(&globbuf);
- free(data->file_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)
{
-#if defined( HAVE_LIBEWF_V2_API )
if( libewf_handle_initialize(
&( data->handle ),
&ewf_error) != 1 )
@@ -209,18 +182,10 @@ disk_t *fewf_init(const char *device, const int mode)
NULL );
data->handle=NULL;
}
-#else
- 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);
- }
-#endif /* defined( HAVE_LIBEWF_V2_API ) */
}
if(data->handle==NULL)
{
data->mode&=~TESTDISK_O_RDWR;
-#if defined( HAVE_LIBEWF_V2_API )
if( libewf_handle_initialize(
&( data->handle ),
&ewf_error) != 1 )
@@ -261,7 +226,140 @@ disk_t *fewf_init(const char *device, const int mode)
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_files<globbuf.gl_pathc; num_files++) {
+ filenames[num_files]=globbuf.gl_pathv[num_files];
+ }
+ }
+ }
+ if(filenames==NULL)
+ {
+ globfree(&globbuf);
+ free(data->file_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)
{
@@ -274,27 +372,27 @@ disk_t *fewf_init(const char *device, const int mode)
free(data);
return NULL;
}
-#endif /* defined( HAVE_LIBEWF_V2_API ) */
}
-#if defined( HAVE_LIBEWF_V2_API )
- 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);
- }
-#else
if( libewf_parse_header_values( data->handle, LIBEWF_DATE_FORMAT_DAYMONTH) != 1 )
{
log_error("%s Unable to parse EWF header values\n", device);
}
-#endif
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;
@@ -303,18 +401,10 @@ disk_t *fewf_init(const char *device, const int mode)
disk->sync=&fewf_sync;
disk->access_mode=(data->mode&TESTDISK_O_RDWR);
disk->clean=&fewf_clean;
-#if defined( HAVE_LIBEWF_V2_API ) || defined( LIBEWF_GET_BYTES_PER_SECTOR_HAVE_TWO_ARGUMENTS )
+#if defined( LIBEWF_GET_BYTES_PER_SECTOR_HAVE_TWO_ARGUMENTS )
{
uint32_t bytes_per_sector = 0;
-
-#if defined( HAVE_LIBEWF_V2_API )
- if( libewf_handle_get_bytes_per_sector(
- data->handle,
- &bytes_per_sector,
- NULL ) != 1 )
-#else
if( libewf_get_bytes_per_sector(data->handle, &bytes_per_sector)<0)
-#endif
{
disk->sector_size=DEFAULT_SECTOR_SIZE;
}
@@ -326,7 +416,6 @@ disk_t *fewf_init(const char *device, const int mode)
#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;
@@ -335,19 +424,10 @@ disk_t *fewf_init(const char *device, const int mode)
disk->geom.heads_per_cylinder=1;
disk->geom.sectors_per_head=1;
disk->geom.bytes_per_sector=disk->sector_size;
- /* Get disk_real_size */
-#if defined( HAVE_LIBEWF_V2_API ) || defined( LIBEWF_GET_MEDIA_SIZE_HAVE_TWO_ARGUMENTS )
+#if defined( LIBEWF_GET_MEDIA_SIZE_HAVE_TWO_ARGUMENTS )
{
size64_t media_size = 0;
-
-#if defined( HAVE_LIBEWF_V2_API )
- if( libewf_handle_get_media_size(
- data->handle,
- &media_size,
- NULL ) != 1 )
-#else
if(libewf_get_media_size(data->handle, &media_size)<0)
-#endif
{
disk->disk_real_size=0;
}
@@ -360,19 +440,13 @@ disk_t *fewf_init(const char *device, const int mode)
disk->disk_real_size=libewf_get_media_size(data->handle);
#endif
update_disk_car_fields(disk);
-#if defined( HAVE_LIBEWF_V2_API )
- libewf_glob_free(
- filenames,
- num_files,
- NULL );
-#else
#if defined( HAVE_GLOB_H )
globfree(&globbuf);
#endif
free(filenames);
-#endif
return disk;
}
+#endif
static const char *fewf_description(disk_t *disk)
{
@@ -529,4 +603,3 @@ const char*td_ewf_version(void)
return "none";
}
#endif /* defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF) */
-
diff --git a/src/ewf.h b/src/ewf.h
index 2bcf4cc..16d2bad 100644
--- a/src/ewf.h
+++ b/src/ewf.h
@@ -23,6 +23,10 @@
extern "C" {
#endif
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_LIBEWF
+#endif
+
#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF)
disk_t *fewf_init(const char *device, const int testdisk_mode);
#endif
diff --git a/src/exfatp.c b/src/exfatp.c
index 00374ac..06c24ec 100644
--- a/src/exfatp.c
+++ b/src/exfatp.c
@@ -31,6 +31,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "exfatp.h"
#include "exfat.h"
#include "log.h"
diff --git a/src/ext2.c b/src/ext2.c
index 2cd6a07..cb81316 100644
--- a/src/ext2.c
+++ b/src/ext2.c
@@ -109,7 +109,7 @@ static void set_EXT2_info(const struct ext2_super_block *sb, partition_t *partit
Primary superblock is at 1024 (SUPERBLOCK_OFFSET)
Group 0 begin at s_first_data_block
*/
-int recover_EXT2(disk_t *disk, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind)
+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;
diff --git a/src/ext2.h b/src/ext2.h
index 68bffea..47ef0a7 100644
--- a/src/ext2.h
+++ b/src/ext2.h
@@ -202,7 +202,7 @@ struct ext2_super_block {
uint32_t s_checksum; /* crc32c(superblock) */
};
int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose);
-int recover_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);
+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" */
diff --git a/src/ext2_dir.c b/src/ext2_dir.c
index f3dc4a2..efc19a3 100644
--- a/src/ext2_dir.c
+++ b/src/ext2_dir.c
@@ -23,6 +23,10 @@
#include <config.h>
#endif
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_LIBEXT2FS
+#endif
+
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
@@ -31,12 +35,14 @@
#include <errno.h>
#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"
@@ -67,7 +73,6 @@ 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 io_channel alloc_io_channel(disk_t *disk_car,my_data_t *my_data);
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);
@@ -91,7 +96,6 @@ static struct struct_io_manager my_struct_manager = {
.write_blk64=&my_write_blk64,
#endif
};
-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);
static io_channel shared_ioch=NULL;
/*
@@ -105,7 +109,7 @@ static io_channel shared_ioch=NULL;
/*
* Allocate libext2fs structures associated with I/O manager
*/
-static io_channel alloc_io_channel(disk_t *disk_car,my_data_t *my_data)
+static io_channel alloc_io_channel(const disk_t *disk_car,my_data_t *my_data)
{
io_channel ioch;
#ifdef DEBUG_EXT2
diff --git a/src/ext2_inc.h b/src/ext2_inc.h
index ca2421b..e3cf9f5 100644
--- a/src/ext2_inc.h
+++ b/src/ext2_inc.h
@@ -19,6 +19,10 @@
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_LIBEXT2FS
+#endif
+
#if defined(HAVE_LIBEXT2FS)
struct ext2_dir_struct {
file_info_t *dir_list;
diff --git a/src/ext2_sb.c b/src/ext2_sb.c
index 8a72ed3..e0e9763 100644
--- a/src/ext2_sb.c
+++ b/src/ext2_sb.c
@@ -38,7 +38,7 @@
#include "guid_cmp.h"
#include "ext2_sb.h"
-int interface_superblock(disk_t *disk_car,list_part_t *list_part, char**current_cmd)
+int interface_superblock(disk_t *disk_car, const list_part_t *list_part, char**current_cmd)
{
const list_part_t *parts;
const partition_t *old_part=NULL;
diff --git a/src/ext2_sb.h b/src/ext2_sb.h
index fae7c31..b527b8e 100644
--- a/src/ext2_sb.h
+++ b/src/ext2_sb.h
@@ -23,7 +23,7 @@
extern "C" {
#endif
-int interface_superblock(disk_t *disk_car,list_part_t *list_part,char**current_cmd);
+int interface_superblock(disk_t *disk_car, const list_part_t *list_part, char**current_cmd);
#ifdef __cplusplus
} /* closing brace for extern "C" */
diff --git a/src/ext2grp.c b/src/ext2grp.c
index c48ec2b..96db73f 100644
--- a/src/ext2grp.c
+++ b/src/ext2grp.c
@@ -36,7 +36,7 @@
#include "log.h"
#include "photorec.h"
-unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, partition_t *partition)
+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;
@@ -73,7 +73,7 @@ unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, parti
return blocksize;
}
-unsigned int ext2_fix_inode(alloc_data_t *list_search_space, disk_t *disk, partition_t *partition)
+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;
diff --git a/src/ext2grp.h b/src/ext2grp.h
index ad854fe..ed5e9db 100644
--- a/src/ext2grp.h
+++ b/src/ext2grp.h
@@ -23,8 +23,8 @@
extern "C" {
#endif
-unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, partition_t *partition);
-unsigned int ext2_fix_inode(alloc_data_t *list_search_space, disk_t *disk, partition_t *partition);
+unsigned int ext2_fix_group(alloc_data_t *list_search_space, disk_t *disk, const partition_t *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" */
diff --git a/src/ext2p.c b/src/ext2p.c
index 84b2ca6..2e57e43 100644
--- a/src/ext2p.c
+++ b/src/ext2p.c
@@ -22,6 +22,12 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_LIBEXT2FS
+#endif
+
+#if defined(HAVE_LIBEXT2FS)
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -33,6 +39,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "intrf.h"
#include "dir.h"
#ifdef HAVE_EXT2FS_EXT2_FS_H
@@ -47,7 +54,6 @@
#include "log.h"
#include "log_part.h"
-#ifdef HAVE_LIBEXT2FS
unsigned int ext2_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space)
{
dir_data_t dir_data;
diff --git a/src/fat.c b/src/fat.c
index f1f3a65..cc41a9e 100644
--- a/src/fat.c
+++ b/src/fat.c
@@ -50,14 +50,102 @@
extern const arch_fnct_t arch_i386;
extern const arch_fnct_t arch_mac;
-static void set_FAT_info(disk_t *disk_car, const struct fat_boot_sector *fat_header, partition_t *partition);
-static int fat32_set_part_name(disk_t *disk_car, partition_t *partition, const struct fat_boot_sector*fat_header);
static int log_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size);
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);
static int is_fat12(const partition_t *partition);
static int is_fat16(const partition_t *partition);
static int is_fat32(const partition_t *partition);
+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;
+}
+
+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);
+ }
+}
+
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));
@@ -150,7 +238,7 @@ int log_fat2_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector
return 0;
}
-int check_FAT(disk_t *disk_car,partition_t *partition,const int verbose)
+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);
@@ -178,54 +266,6 @@ int check_FAT(disk_t *disk_car,partition_t *partition,const int verbose)
return 0;
}
-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);
- }
-}
-
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;
@@ -764,7 +804,7 @@ unsigned long int fat32_get_next_free(const unsigned char *boot_fat32, const uns
return le32(fsinfo->nextfree);
}
-static int fat_has_EFI_entry(disk_t *disk, partition_t *partition, const int verbose)
+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;
@@ -866,48 +906,6 @@ int recover_FAT(disk_t *disk_car, const struct fat_boot_sector*fat_header, parti
return 0;
}
-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;
-}
-
int check_OS2MB(disk_t *disk, partition_t *partition, const int verbose)
{
unsigned char *buffer=(unsigned char *)MALLOC(disk->sector_size);
diff --git a/src/fat1x.c b/src/fat1x.c
index 90ab49b..43d8950 100644
--- a/src/fat1x.c
+++ b/src/fat1x.c
@@ -43,7 +43,7 @@
#include "fat1x.h"
#ifdef HAVE_NCURSES
-static void dump_fat1x_ncurses(disk_t *disk_car, partition_t *partition, const unsigned char *buffer_bs)
+static void dump_fat1x_ncurses(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs)
{
WINDOW *window=newwin(LINES, COLS, 0, 0); /* full screen */
keypad(window, TRUE); /* Need it to get arrow key */
@@ -62,7 +62,7 @@ static void dump_fat1x_ncurses(disk_t *disk_car, partition_t *partition, const u
}
#endif
-static void dump_fat1x(disk_t *disk_car, partition_t *partition, const unsigned char *buffer_bs, char **current_cmd)
+static void dump_fat1x(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, char **current_cmd)
{
log_info("Boot sector\n");
dump_log(buffer_bs, FAT1x_BOOT_SECTOR_SIZE);
diff --git a/src/fat_adv.c b/src/fat_adv.c
index 5fcfe77..c6f6790 100644
--- a/src/fat_adv.c
+++ b/src/fat_adv.c
@@ -173,7 +173,7 @@ static unsigned long int get_subdirectory(disk_t *disk_car,const uint64_t hd_off
#ifdef HAVE_NCURSES
#define INTER_DIR 16
-static int ask_root_directory(disk_t *disk_car, const partition_t *partition, const file_info_t*dir_list, const unsigned long int cluster)
+static int ask_root_directory(const disk_t *disk_car, const partition_t *partition, const file_info_t*dir_list, const unsigned long int cluster)
{
/* Return value
* -1: quit
diff --git a/src/fat_cluster.c b/src/fat_cluster.c
index 1384202..a009e7f 100644
--- a/src/fat_cluster.c
+++ b/src/fat_cluster.c
@@ -42,7 +42,7 @@
/* Using a couple of inodes of "." directory entries, get the cluster size and where the first cluster begins.
* */
-int find_sectors_per_cluster(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, unsigned int *sectors_per_cluster, uint64_t *offset_org, const upart_type_t upart_type)
+int find_sectors_per_cluster(disk_t *disk_car, const partition_t *partition, const int verbose, const int dump_ind, unsigned int *sectors_per_cluster, uint64_t *offset_org, const upart_type_t upart_type)
{
unsigned int nbr_subdir=0;
sector_cluster_t sector_cluster[10];
diff --git a/src/fat_cluster.h b/src/fat_cluster.h
index a5b3d2f..9bc53fe 100644
--- a/src/fat_cluster.h
+++ b/src/fat_cluster.h
@@ -42,7 +42,7 @@ struct cluster_offset_struct
unsigned int first_sol;
};
-int find_sectors_per_cluster(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, unsigned int *sectors_per_cluster, uint64_t *offset, const upart_type_t upart_type);
+int find_sectors_per_cluster(disk_t *disk_car, const partition_t *partition, const int verbose, const int dump_ind, unsigned int *sectors_per_cluster, uint64_t *offset, const upart_type_t upart_type);
upart_type_t no_of_cluster2part_type(const unsigned long int no_of_cluster);
int find_sectors_per_cluster_aux(const sector_cluster_t *sector_cluster, const unsigned int nbr_sector_cluster,unsigned int *sectors_per_cluster, uint64_t *offset, const int verbose, const unsigned long int part_size_in_sectors, const upart_type_t upart_type);
diff --git a/src/fat_common.h b/src/fat_common.h
index 471c4e8..780b5cc 100644
--- a/src/fat_common.h
+++ b/src/fat_common.h
@@ -24,10 +24,34 @@
#ifdef __cplusplus
extern "C" {
#endif
+/*@
+ @ requires \valid_read(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);
+ @ assigns \nothing;
+ @ */
unsigned int get_dir_entries(const struct fat_boot_sector *fat_header);
+
+/*@
+ @ requires \valid_read(fat_header);
+ @ assigns \nothing;
+ @ */
unsigned int fat_sector_size(const struct fat_boot_sector *fat_header);
+
+/*@
+ @ requires \valid_read(fat_header);
+ @ assigns \nothing;
+ @ */
unsigned int fat_sectors(const struct fat_boot_sector *fat_header);
#ifdef __cplusplus
diff --git a/src/fat_dir.c b/src/fat_dir.c
index 3c9c171..02a327b 100644
--- a/src/fat_dir.c
+++ b/src/fat_dir.c
@@ -57,7 +57,6 @@ struct fat_dir_struct
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);
-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);
static inline void fat16_towchar(wchar_t *dst, const uint8_t *src, size_t len);
static int fat_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file);
static void dir_partition_fat_close(dir_data_t *dir_data);
diff --git a/src/fat_unformat.c b/src/fat_unformat.c
index 4cf6a83..885ecda 100644
--- a/src/fat_unformat.c
+++ b/src/fat_unformat.c
@@ -55,8 +55,10 @@
#include "fat_common.h"
#include <assert.h>
+extern int need_to_stop;
+
#define READ_SIZE 4*1024*1024
-static int pfind_sectors_per_cluster(disk_t *disk, partition_t *partition, const int verbose, unsigned int *sectors_per_cluster, uint64_t *offset_org, alloc_data_t *list_search_space)
+static int pfind_sectors_per_cluster(disk_t *disk, const partition_t *partition, const int verbose, unsigned int *sectors_per_cluster, uint64_t *offset_org, alloc_data_t *list_search_space)
{
uint64_t offset=0;
uint64_t next_offset=0;
@@ -386,6 +388,13 @@ static pstatus_t fat_unformat_aux(struct ph_param *params, const struct ph_optio
}
}
#endif
+ if(need_to_stop!=0)
+ {
+ log_info("PhotoRec has been stopped\n");
+ params->offset=offset;
+ offset = offset_end;
+ ind_stop=PSTATUS_STOP;
+ }
}
}
free(buffer_start);
diff --git a/src/fatp.c b/src/fatp.c
index af33ec3..81fd62f 100644
--- a/src/fatp.c
+++ b/src/fatp.c
@@ -31,6 +31,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "fatp.h"
#include "fat.h"
#include "fat_common.h"
diff --git a/src/fidentify.c b/src/fidentify.c
index 310bb42..883e76a 100644
--- a/src/fidentify.c
+++ b/src/fidentify.c
@@ -24,6 +24,11 @@
#include <config.h>
#endif
+#ifdef __FRAMAC__
+#undef HAVE_FTELLO
+#undef HAVE_DUP2
+#endif
+
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -52,13 +57,21 @@
#include "misc.h"
#include "file_jpg.h"
#include "file_gz.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
-extern file_enable_t list_file_enable[];
+extern file_enable_t array_file_enable[];
extern file_check_list_t file_check_list;
#define READ_SIZE 1024*512
+#define OPT_CHECK 1
+#define OPT_TIME 2
-static int file_identify(const char *filename, const unsigned int check)
+/*@
+ @ requires valid_read_string(filename);
+ @*/
+static int file_identify(const char *filename, const unsigned int options)
{
const unsigned int blocksize=65536;
const unsigned int buffer_size=blocksize + READ_SIZE;
@@ -79,21 +92,31 @@ static int file_identify(const char *filename, const unsigned int check)
}
if(fread(buffer, 1, READ_SIZE, file) >0)
{
- struct td_list_head *tmpl;
+ const struct td_list_head *tmpl;
file_recovery_t file_recovery_new;
file_recovery_t file_recovery;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, READ_SIZE);
+#endif
reset_file_recovery(&file_recovery);
+ reset_file_recovery(&file_recovery_new);
file_recovery.blocksize=blocksize;
file_recovery_new.blocksize=blocksize;
- file_recovery_new.file_stat=NULL;
+ /*@ assert file_recovery_new.file_stat==NULL; */
td_list_for_each(tmpl, &file_check_list.list)
{
- struct td_list_head *tmp;
+ const struct td_list_head *tmp;
const file_check_list_t *pos=td_list_entry_const(tmpl, const file_check_list_t, list);
- td_list_for_each(tmp, &pos->file_checks[buffer[pos->offset]].list)
+ const struct td_list_head *tmp_list=&pos->file_checks[buffer[pos->offset]].list;
+ td_list_for_each(tmp, tmp_list)
{
+ /*TODO assert tmp!=tmp_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) &&
+ if(
+#ifdef __FRAMAC__
+ file_check->header_check!=NULL &&
+#endif
+ (file_check->length==0 || memcmp(buffer + file_check->offset, file_check->value, file_check->length)==0) &&
file_check->header_check(buffer, blocksize, 0, &file_recovery, &file_recovery_new)!=0)
{
file_recovery_new.file_stat=file_check->file_stat;
@@ -103,16 +126,21 @@ static int file_identify(const char *filename, const unsigned int check)
if(file_recovery_new.file_stat!=NULL)
break;
}
- if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL &&
- check > 0 && file_recovery_new.file_check!=NULL)
+ if(file_recovery_new.file_stat!=NULL &&
+ file_recovery_new.file_stat->file_hint!=NULL &&
+ file_recovery_new.file_check!=NULL &&
+ ((options&OPT_CHECK)!=0 || ((options&OPT_TIME)!=0 && file_recovery_new.time==0))
+ )
{
+ off_t file_size;
file_recovery_new.handle=file;
my_fseek(file_recovery_new.handle, 0, SEEK_END);
-#ifdef HAVE_FTELLO
- file_recovery_new.file_size=ftello(file_recovery_new.handle);
+#if defined(HAVE_FTELLO)
+ file_size=ftello(file_recovery_new.handle);
#else
- file_recovery_new.file_size=ftell(file_recovery_new.handle);
+ file_size=ftell(file_recovery_new.handle);
#endif
+ file_recovery_new.file_size=(file_size==-1?0:file_size);
file_recovery_new.calculated_file_size=file_recovery_new.file_size;
(file_recovery_new.file_check)(&file_recovery_new);
if(file_recovery_new.file_size < file_recovery_new.min_filesize)
@@ -125,8 +153,10 @@ static int file_identify(const char *filename, const unsigned int check)
printf("%s: %s", filename,
((file_recovery_new.extension!=NULL && file_recovery_new.extension[0]!='\0')?
file_recovery_new.extension:file_recovery_new.file_stat->file_hint->description));
- if(check > 0 && file_recovery_new.file_check!=NULL)
+ if((options&OPT_CHECK)!=0 && file_recovery_new.file_check!=NULL)
printf(" file_size=%llu", (long long unsigned)file_recovery_new.file_size);
+ if((options&OPT_TIME)!=0 && file_recovery_new.time!=0)
+ printf(" time=%llu", (long long unsigned)file_recovery_new.time);
printf("\n");
}
else
@@ -140,8 +170,8 @@ static int file_identify(const char *filename, const unsigned int check)
return 0;
}
-#ifndef __AFL_COMPILER
-static void file_identify_dir(const char *current_dir, const unsigned int check)
+#if !defined(__AFL_COMPILER) && !defined(MAIN_fidentify)
+static void file_identify_dir(const char *current_dir, const unsigned int options)
{
DIR *dir;
struct dirent *entry;
@@ -164,9 +194,9 @@ static void file_identify_dir(const char *current_dir, const unsigned int check)
#endif
{
if(S_ISDIR(buf_stat.st_mode))
- file_identify_dir(current_file, check);
+ file_identify_dir(current_file, options);
else if(S_ISREG(buf_stat.st_mode))
- file_identify(current_file, check);
+ file_identify(current_file, options);
}
free(current_file);
}
@@ -193,25 +223,36 @@ static void display_version(void)
#ifdef RECORD_COMPILATION_DATE
printf("Compilation date: %s\n", get_compilation_date());
#endif
+#ifndef MAIN_fidentify
printf("libjpeg: %s, zlib: %s\n", td_jpeg_version(), td_zlib_version());
printf("OS: %s\n" , get_os());
+#endif
}
int main(int argc, char **argv)
{
int i;
- unsigned int check=0;
+#ifdef MAIN_fidentify
+ unsigned int options=OPT_CHECK|OPT_TIME;
+#else
+ unsigned int options=0;
+#endif
FILE *log_handle=NULL;
int log_errno=0;
int enable_all_formats=1;
int scan_dir=1;
file_stat_t *file_stats;
log_set_levels(LOG_LEVEL_DEBUG|LOG_LEVEL_TRACE|LOG_LEVEL_QUIET|LOG_LEVEL_INFO|LOG_LEVEL_VERBOSE|LOG_LEVEL_PROGRESS|LOG_LEVEL_WARNING|LOG_LEVEL_ERROR|LOG_LEVEL_PERROR|LOG_LEVEL_CRITICAL);
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
if( strcmp(argv[i], "/check")==0 || strcmp(argv[i], "-check")==0 || strcmp(argv[i], "--check")==0)
{
- check++;
+ options|=OPT_CHECK;
+ }
+ if( strcmp(argv[i], "/time")==0 || strcmp(argv[i], "-time")==0 || strcmp(argv[i], "--time")==0)
+ {
+ options|=OPT_TIME;
}
else if(strcmp(argv[i],"/help")==0 || strcmp(argv[i],"-help")==0 || strcmp(argv[i],"--help")==0 ||
strcmp(argv[i],"/h")==0 || strcmp(argv[i],"-h")==0 ||
@@ -227,28 +268,32 @@ int main(int argc, char **argv)
return 0;
}
}
+#endif
#ifndef __AFL_COMPILER
log_handle=log_open("fidentify.log", TD_LOG_CREATE, &log_errno);
if(log_handle!=NULL)
{
time_t my_time;
-#ifdef HAVE_DUP2
+#if defined(HAVE_DUP2)
dup2(fileno(log_handle),2);
#endif
my_time=time(NULL);
log_info("\n\n%s",ctime(&my_time));
log_info("Command line: fidentify");
+#ifndef MAIN_fidentify
for(i=1;i<argc;i++)
log_info(" %s", argv[i]);
+#endif
log_info("\n\n");
log_flush();
}
log_info("fidentify %s, Data Recovery Utility, %s\nChristophe GRENIER <grenier@cgsecurity.org>\nhttps://www.cgsecurity.org\n", VERSION, TESTDISKDATE);
#endif
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
file_enable_t *file_enable;
- for(file_enable=list_file_enable;file_enable->file_hint!=NULL;file_enable++)
+ for(file_enable=array_file_enable;file_enable->file_hint!=NULL;file_enable++)
if(argv[i][0]=='+' &&
file_enable->file_hint->extension!=NULL &&
strcmp(file_enable->file_hint->extension,&argv[i][1])==0)
@@ -257,17 +302,20 @@ int main(int argc, char **argv)
enable_all_formats=0;
}
}
+#endif
if(enable_all_formats)
{
/* Enable all file formats */
file_enable_t *file_enable;
- for(file_enable=list_file_enable;file_enable->file_hint!=NULL;file_enable++)
+ for(file_enable=array_file_enable;file_enable->file_hint!=NULL;file_enable++)
file_enable->enable=1;
}
- file_stats=init_file_stats(list_file_enable);
+ file_stats=init_file_stats(array_file_enable);
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
if(strcmp(argv[i], "/check")==0 || strcmp(argv[i], "-check")==0 || strcmp(argv[i], "--check")==0 ||
+ strcmp(argv[i], "/time")==0 || strcmp(argv[i], "-time")==0 || strcmp(argv[i], "--time")==0 ||
argv[i][0]=='+')
{
}
@@ -282,17 +330,20 @@ int main(int argc, char **argv)
#endif
{
if(S_ISREG(buf_stat.st_mode))
- file_identify(argv[i], check);
+ file_identify(argv[i], options);
#ifndef __AFL_COMPILER
else if(S_ISDIR(buf_stat.st_mode))
- file_identify_dir(argv[i], check);
+ file_identify_dir(argv[i], options);
#endif
}
}
}
#ifndef __AFL_COMPILER
if(scan_dir)
- file_identify_dir(".", check);
+ file_identify_dir(".", options);
+#endif
+#else
+ file_identify("demo", options);
#endif
free_header_check();
free(file_stats);
diff --git a/src/file_ape.c b/src/file_ape.c
index 3391a39..c013880 100644
--- a/src/file_ape.c
+++ b/src/file_ape.c
@@ -31,7 +31,6 @@
#include "common.h"
static void register_header_check_ape(file_stat_t *file_stat);
-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 file_hint_t file_hint_ape= {
.extension="ape",
@@ -106,7 +105,6 @@ static int header_check_ape(const unsigned char *buffer, const unsigned int buff
if(le16(ape->nVersion)>=3980)
{
const struct APE_DESCRIPTOR *descr=(const struct APE_DESCRIPTOR*)buffer;
- const struct APE_HEADER *apeh=(const struct APE_HEADER*)&buffer[le32(descr->nDescriptorBytes)];
if(le32(descr->nDescriptorBytes) < sizeof(struct APE_DESCRIPTOR))
return 0;
if(le32(descr->nHeaderDataBytes) > 0 && le32(descr->nHeaderDataBytes) < sizeof(struct APE_HEADER))
@@ -115,8 +113,11 @@ static int header_check_ape(const unsigned char *buffer, const unsigned int buff
return 0;
if(le32(descr->nDescriptorBytes) + sizeof(struct APE_HEADER) >= buffer_size)
return 0;
- if(le16(apeh->nChannels)<1 || le16(apeh->nChannels)>2)
- return 0;
+ {
+ const struct APE_HEADER *apeh=(const struct APE_HEADER*)&buffer[le32(descr->nDescriptorBytes)];
+ 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;
diff --git a/src/file_asf.c b/src/file_asf.c
index 8f96d2a..a9a7650 100644
--- a/src/file_asf.c
+++ b/src/file_asf.c
@@ -66,24 +66,29 @@ struct asf_stream_prop_s {
unsigned char stream_type[16];
} __attribute__ ((gcc_struct, __packed__));
+static const char *extension_wma="wma";
+static const char *extension_wmv="wmv";
+
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;
- unsigned int i;
- const struct asf_file_prop_s *prop=(const struct asf_file_prop_s*)(hdr+1);
+ 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;
- const char *extension=file_hint_asf.extension;
+ 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)>buffer_size ||
- le32(hdr->nbr_header_obj)<4)
+ nbr_header_obj<4)
return 0;
for(i=0;
- i<le32(hdr->nbr_header_obj) &&
- (const unsigned char *)prop+0x28 < buffer + buffer_size;
- i++, prop=(const struct asf_file_prop_s *)((const char *)prop + le64(prop->object_size)))
+ 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]= {
@@ -94,18 +99,20 @@ static int header_check_asf(const unsigned char *buffer, const unsigned int buff
0x91, 0x07, 0xdc, 0xb7, 0xb7, 0xa9, 0xcf, 0x11,
0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
};
- if(le64(prop->object_size) < 0x18)
+ if(object_size < 0x18)
{
- log_info("header_check_asf object_size too small %llu\n", (long long unsigned)le64(prop->object_size));
+ log_info("header_check_asf object_size too small %llu\n", (long long unsigned)object_size);
return 0;
}
+ if(object_size > 0x8000000000000000)
+ return 0;
if(memcmp(prop->object_id, asf_file_prop_id, sizeof(asf_file_prop_id))==0)
{
- if(le64(prop->object_size) < 0x28)
- return 0;
- if(le64(prop->file_size) < sizeof(struct asf_header_obj_s) + sizeof(struct asf_file_prop_s))
+ 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)
@@ -117,25 +124,27 @@ static int header_check_asf(const unsigned char *buffer, const unsigned int buff
const char wmv[16]={
0xc0, 0xef, 0x19, 0xbc, 0x4d, 0x5b, 0xcf, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b
};
- if(le64(prop->object_size) < 0x28)
+ if(object_size < 0x28)
return 0;
if(memcmp(stream->stream_type, wma, sizeof(wma))==0)
- extension="wma";
+ extension=extension_wma;
else if(memcmp(stream->stream_type, wmv, sizeof(wmv))==0)
- extension="wmv";
+ extension=extension_wmv;
}
- if(le64(prop->object_size) > buffer_size)
- break;
+ 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=le64(size);
+ 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->time=time;
return 1;
}
diff --git a/src/file_bmp.c b/src/file_bmp.c
index f20326a..afef52b 100644
--- a/src/file_bmp.c
+++ b/src/file_bmp.c
@@ -30,9 +30,11 @@
#include "types.h"
#include "filegen.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_bmp(file_stat_t *file_stat);
-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 file_hint_t file_hint_bmp= {
.extension="bmp",
@@ -45,28 +47,75 @@ const file_hint_t file_hint_bmp= {
static const unsigned char bmp_header[2]= {'B','M'};
-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);
-}
-
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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_bmp, buffer+(..), file_recovery, file_recovery_new);
+ @ 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;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> \initialized(&file_recovery_new->time);
+ @ 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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @ ensures *buffer==\old(*buffer);
+ @*/
+ /* TODO ensures *file_recovery==\old(*file_recovery); */
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' && bm->reserved==0 &&
+ 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->size) >= 65 &&
+ le32(bm->hdr_size) < le32(bm->size))
{
/* See http://en.wikipedia.org/wiki/BMP_file_format */
reset_file_recovery(file_recovery_new);
@@ -75,7 +124,111 @@ static int header_check_bmp(const unsigned char *buffer, const unsigned int buff
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;
}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+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);
+}
+
+#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/src/file_bz2.c b/src/file_bz2.c
index 05914f2..191bcd6 100644
--- a/src/file_bz2.c
+++ b/src/file_bz2.c
@@ -51,7 +51,7 @@ static void register_header_check_bz2(file_stat_t *file_stat)
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[4]=='1' && buffer[5]=='A' && buffer[6]=='Y' && buffer[7]=='&' && buffer[8]=='S' && buffer[9]=='Y')
+ 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;
diff --git a/src/file_doc.c b/src/file_doc.c
index 4451796..a0361f9 100644
--- a/src/file_doc.c
+++ b/src/file_doc.c
@@ -39,13 +39,11 @@
#include "memmem.h"
#include "setdate.h"
#include "file_doc.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_doc(file_stat_t *file_stat);
-static void file_check_doc(file_recovery_t *file_recovery);
-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);
-static void file_rename_doc(file_recovery_t *file_recovery);
-static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset);
-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);
const file_hint_t file_hint_doc= {
.extension="doc",
@@ -56,6 +54,45 @@ const file_hint_t file_hint_doc= {
.register_header_check=&register_header_check_doc
};
+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_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";
const char WilcomDesignInformationDDD[56]=
{
@@ -68,6 +105,342 @@ const char WilcomDesignInformationDDD[56]=
'D', '\0', 'D', '\0', 'D', '\0', '\0', '\0'
};
+/*@
+ @ requires \valid(IN);
+ @ requires (9 == uSectorShift) || (12 == uSectorShift);
+ @ requires \valid( buf + (0 .. (1<<uSectorShift)-1));
+ @ ensures \result == -1 || \result == 0;
+ @*/
+/* TODO: ensures \result == 0 ==> \initialized(buf + (0 .. (1<<uSectorShift)-1)); */
+static int OLE_read_block(FILE *IN, unsigned char *buf, const unsigned int uSectorShift, const unsigned int block, const uint64_t offset)
+{
+ const size_t size=1<<uSectorShift;
+ if(block==0xFFFFFFFF || block==0xFFFFFFFE)
+ return -1;
+ if(my_fseek(IN, offset + ((uint64_t)(1+block)<<uSectorShift), SEEK_SET) < 0)
+ {
+ return -1;
+ }
+ if(fread(buf, size, 1, IN)!=1)
+ {
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buf, size);
+#endif
+ /* TODO: assert \initialized((char *)buf + (0 .. size-1)); */
+ return 0;
+}
+
+/*@
+ @ requires \valid_read(dir_entry);
+ @ requires \initialized(dir_entry);
+ @ 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);
+ @*/
+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
+ for(block=le32(header->root_start_block), i=0;
+ block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
+ i++)
+ {
+ const uint64_t offset_root_dir=((uint64_t)1+block)<<uSectorShift;
+#ifdef DEBUG_OLE
+ log_info("Root Directory block=%u (0x%x)\n", block, block);
+#endif
+ if(offset_root_dir>buffer_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;
+ 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 && j<le16(dir_entry->namsiz) && 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(header);
+ @ requires le32(header->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<<le16(header->uSectorShift))/4-1);
+ @ ensures \result==\null || \valid_read((const char *)\result + ( 0 .. (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))-1));
+ @*/
+static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
+{
+ uint32_t *fat;
+ uint32_t *dif;
+ const unsigned int uSectorShift=le16(header->uSectorShift);
+ const unsigned int num_FAT_blocks=le32(header->num_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<<uSectorShift)/4-1); */
+ const unsigned int dif_size=109*4+(le32(header->num_extra_FAT_blocks)<<uSectorShift);
+ /*@ assert 109*4 <= dif_size <= 109*4+(50<<12); */
+#ifdef __FRAMAC__
+ dif=(uint32_t*)MALLOC(109*4+(50<<12));
+#else
+ dif=(uint32_t*)MALLOC(dif_size);
+#endif
+ /*@ assert \valid((char *)dif+(0..dif_size-1)); */
+ memcpy(dif,(header+1),109*4);
+ if(le32(header->num_extra_FAT_blocks)>0)
+ { /* Load DIF*/
+ unsigned long int i;
+ for(i=0; i<le32(header->num_extra_FAT_blocks); i++)
+ {
+ const unsigned int block=(i==0 ? le32(header->FAT_next_block) : le32(dif[109+i*(((1<<uSectorShift)/4)-1)]));
+ unsigned char *data=(unsigned char*)&dif[109]+i*((1<<uSectorShift)-4);
+ if(OLE_read_block(IN, data, uSectorShift, block, offset) < 0)
+ {
+ free(dif);
+ return NULL;
+ }
+ }
+ }
+#ifdef __FRAMAC__
+ /*@ assert (109+50*((1<<12)/4-1))<<12 >= num_FAT_blocks<<uSectorShift; */
+ fat=(uint32_t*)MALLOC((109+50*((1<<12)/4-1))<<12);
+#else
+ fat=(uint32_t*)MALLOC(num_FAT_blocks<<uSectorShift);
+#endif
+ /*@ assert \valid((char *)fat + (0 .. (num_FAT_blocks<<uSectorShift)-1)); */
+ { /* Load FAT */
+ unsigned int j;
+ for(j=0; j<num_FAT_blocks; j++)
+ {
+ if(OLE_read_block(IN, (unsigned char*)fat + (j<<uSectorShift), uSectorShift, le32(dif[j]), offset)<0)
+ {
+ free(dif);
+ free(fat);
+ return NULL;
+ }
+ }
+ }
+ free(dif);
+ return fat;
+}
+
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ ensures \valid(file_recovery->handle);
+ @*/
void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
{
unsigned char buffer_header[512];
@@ -77,22 +450,36 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
unsigned int freesect_count=0;
const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
const uint64_t doc_file_size_org=file_recovery->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<<le16(header->uSectorShift));
- log_trace("num_FAT_blocks %u\n",le32(header->num_FAT_blocks));
+ log_trace("sector size %u\n",1<<uSectorShift);
+ log_trace("num_FAT_blocks %u\n",num_FAT_blocks);
log_trace("num_extra_FAT_blocks %u\n",le32(header->num_extra_FAT_blocks));
#endif
- /* Sanity check */
- 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<<le16(header->uSectorShift))-1))
+ 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<<uSectorShift)/4-1))
+ return ;
+ /*@ assert num_FAT_blocks <= 109+le32(header->num_extra_FAT_blocks)*((1<<uSectorShift)/4-1); */
if((fat=OLE_load_FAT(file_recovery->handle, header, offset))==NULL)
{
#ifdef DEBUG_OLE
@@ -101,18 +488,34 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
return ;
}
/* Search how many entries are not used at the end of the FAT */
- for(i=(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-1;
- i>0 && le32(fat[i])==0xFFFFFFFF;
- i--)
- freesect_count++;
- doc_file_size=offset + ((1+(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-freesect_count)<<le16(header->uSectorShift));
+ {
+ const unsigned int val_max=(num_FAT_blocks<<uSectorShift)/4-1;
+ /*@ assert \valid_read((char *)fat + ( 0 .. val_max)); */
+ /*@
+ @ loop invariant 0 <= freesect_count <= val_max;
+ @ loop assigns freesect_count;
+ @ loop variant val_max - freesect_count;
+ @*/
+ for(freesect_count=0; freesect_count < val_max; freesect_count++)
+ {
+ const unsigned j=val_max-freesect_count;
+ /*@ assert 0 <= j <= val_max; */
+ if(fat[j]!=0xFFFFFFFF)
+ break;
+ }
+ }
+ /*@ assert 0 <= freesect_count <= (num_FAT_blocks<<uSectorShift)/4-1; */
+ {
+ const unsigned int block=(num_FAT_blocks<<uSectorShift)/4-freesect_count;
+ doc_file_size=offset + (((uint64_t)1+block)<<uSectorShift);
+ }
if(doc_file_size > doc_file_size_org)
{
#ifdef DEBUG_OLE
log_info("doc_file_size=%llu + (1+(%u<<%u)/4-%u)<<%u\n",
(unsigned long long)offset,
- le32(header->num_FAT_blocks), le16(header->uSectorShift),
- freesect_count, le16(header->uSectorShift));
+ 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
@@ -124,9 +527,9 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
#endif
{
unsigned int block;
- const unsigned int fat_entries=(le32(header->num_FAT_blocks)==0 ?
+ const unsigned int fat_entries=(num_FAT_blocks==0 ?
109:
- (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
+ (num_FAT_blocks<<uSectorShift)/4);
#ifdef DEBUG_OLE
log_info("root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
@@ -145,19 +548,15 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
free(fat);
return ;
}
- if(my_fseek(file_recovery->handle, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET)<0)
- {
-#ifdef DEBUG_OLE
- log_info("fseek failed\n");
+#ifdef __FRAMAC__
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<12);
+#else
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<uSectorShift);
#endif
- free(fat);
- return ;
- }
- dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
- if(fread(dir_entries, (1<<le16(header->uSectorShift)), 1, file_recovery->handle)!=1)
+ if(OLE_read_block(file_recovery->handle, (unsigned char *)dir_entries, uSectorShift, block, offset)<0)
{
#ifdef DEBUG_OLE
- log_info("fread failed\n");
+ log_info("OLE_read_block failed\n");
#endif
free(dir_entries);
free(fat);
@@ -165,12 +564,14 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
}
{
unsigned int sid;
- struct OLE_DIR *dir_entry;
- for(sid=0, dir_entry=dir_entries;
- sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
- sid++,dir_entry++)
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
{
- if(offset +
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
+ if(dir_entry->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) ||
@@ -192,491 +593,631 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
file_recovery->file_size=doc_file_size;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_doc;
+ @ ensures \valid(file_recovery->handle);
+ @*/
static void file_check_doc(file_recovery_t *file_recovery)
{
file_check_doc_aux(file_recovery, 0);
}
-static const char *ole_get_file_extension(const unsigned char *buffer, const unsigned int buffer_size)
+/*@
+ @ requires \valid(IN);
+ @ requires \valid_read(fat + (0 .. fat_entries-1));
+ @ requires 9 == uSectorShift || 12 == uSectorShift;
+ @ requires 0 < len <= 1024*1024;
+ @ 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)
{
- const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
- const uint32_t *fat;
- unsigned int fat_entries;
+ //@ split uSectorShift;
+ unsigned char *dataPt;
unsigned int block;
unsigned int i;
- if(buffer_size<512)
- return NULL;
- if(le32(header->num_FAT_blocks)==0)
- {
- fat=(const uint32_t *)(header+1);
- fat_entries=109;
- }
- else
- {
- const uint32_t *fati=(const uint32_t *)(header+1);
- const unsigned int fat_offset=(1+le32(fati[0])) << le16(header->uSectorShift);
- fat=(const uint32_t *)&buffer[fat_offset];
- fat_entries=(le32(header->num_FAT_blocks) << le16(header->uSectorShift))/4;
- if(fat_offset>buffer_size)
- fat_entries=0;
- else if(fat_offset+fat_entries>buffer_size)
- fat_entries=buffer_size-fat_offset;
- }
- /* 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);
+ const unsigned int i_max=((len+(1<<uSectorShift)-1) >> uSectorShift);
+#ifdef __FRAMAC__
+ dataPt=(unsigned char *)MALLOC(((1024*1024+(1<<uSectorShift)-1) >> uSectorShift) << uSectorShift);
+#else
+ dataPt=(unsigned char *)MALLOC(i_max << uSectorShift);
#endif
- for(block=le32(header->root_start_block), i=0;
- block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
- block=le32(fat[block]), i++)
+ /*@ assert \valid(dataPt + ( 0 .. len-1)); */
+ for(i=0, block=block_start;
+ i < i_max;
+ i++, block=le32(fat[block]))
{
- const unsigned int offset_root_dir=(1+block)<<le16(header->uSectorShift);
-#ifdef DEBUG_OLE
- log_info("Root Directory block=%u (0x%x)\n", block, block);
-#endif
- if(offset_root_dir>buffer_size-512)
+ if(!(block < fat_entries))
+ {
+ free(dataPt);
return NULL;
+ }
+ if(OLE_read_block(IN, &dataPt[i<<uSectorShift], uSectorShift, block, offset)<0)
{
- unsigned int sid;
- const struct OLE_DIR *dir_entry;
- const char *ext=NULL;
- int is_db=0;
- for(sid=0,dir_entry=(const struct OLE_DIR *)&buffer[offset_root_dir];
- sid<512/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
- sid++,dir_entry++)
- {
-#ifdef DEBUG_OLE
- unsigned int j;
- for(j=0;j<64 && j<le16(dir_entry->namsiz) && 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
- if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0)
- is_db++;
- else if(sid==2 && (memcmp(&dir_entry->name, "2\0\0\0", 4)==0 ||
- memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0", 14)==0))
- is_db++;
- switch(le16(dir_entry->namsiz))
- {
- case 10:
- if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
- return "qdf-backup";
- break;
- case 12:
- /* 3ds max */
- if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
- return "max";
- /* Licom AlphaCAM */
- else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
- return "amb";
- 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="xls";
- /* Microsoft Works .wps */
- else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
- return "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 "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 "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 "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 "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 "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 "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 "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)
- {
-#ifdef DJGPP
- return "sld";
-#else
- return "sldprt";
-#endif
- }
- break;
- case 32:
- /* 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 "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 "sdc";
- break;
- case 36:
- 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 "sda";
- 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 "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 "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 "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 "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)
- {
-#ifdef DJGPP
- return "sld";
-#else
- return "sldprt";
-#endif
- }
- break;
- case 56:
- /* Wilcom ES Software */
- if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
- return "emb";
- break;
- }
- if(sid==1 && memcmp(&dir_entry->name, "D\0g\0n", 6)==0)
- return "dgn";
- }
- if(ext!=NULL)
- return ext;
- /* Thumbs.db */
- if(is_db==2)
- return "db";
+ free(dataPt);
+ return NULL;
}
}
-#ifdef DEBUG_OLE
- log_info("Root Directory end\n");
-#endif
- return NULL;
+ return dataPt;
}
-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)
+/*@
+ @ requires \valid(IN);
+ @ requires \valid_read(header);
+ @ requires \valid_read(fat);
+ @ requires 9 == le16(header->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)
{
- 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<<le16(header->uSectorShift))-1))
- return 0;
- 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(buffer, buffer_size);
- if(file_recovery_new->extension!=NULL)
+ uint32_t *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);
+ if(csectMiniFat==0)
+ return NULL;
+ /*@ assert 0 < csectMiniFat; */
+ /*@ assert 0 < csectMiniFat <= 2048; */
+#ifdef __FRAMAC__
+ minifat=(uint32_t*)MALLOC(2048 << 12);
+#else
+ minifat=(uint32_t*)MALLOC(csectMiniFat << uSectorShift);
+#endif
+ block=le32(header->MiniFat_block);
+ for(i=0; i < csectMiniFat; i++)
{
- if(strcmp(file_recovery_new->extension,"sda")==0)
+ unsigned char*minifat_pos=(unsigned char*)minifat + (i << uSectorShift);
+ if(block >= fat_entries)
{
- if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
- file_recovery_new->extension="sdd";
+ free(minifat);
+ return NULL;
}
- else if(strcmp(file_recovery_new->extension,"wps")==0)
+ if(OLE_read_block(IN, (unsigned char *)minifat_pos, uSectorShift, block, offset)<0)
{
- /* Distinguish between MS Works .wps and MS Publisher .pub */
- if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
- file_recovery_new->extension="pub";
+ free(minifat);
+ return NULL;
}
- return 1;
+ block=le32(fat[block]);
}
- if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL)
+ return 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)
+{
+ const uint32_t *val=(const uint32_t *)((const unsigned char *)buffer+offset);
+ 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)
+{
+ const uint64_t *val=(const uint64_t *)((const unsigned char *)buffer+offset);
+ return le64(*val);
+}
+
+/*@
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. count-1));
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ assigns *ext;
+ @*/
+static void software2ext(const char **ext, const unsigned char *software, const unsigned int count)
+{
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ if(count>=12)
{
- file_recovery_new->extension="doc";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "MicroStation", 12)==0)
+ {
+ *ext=extension_dgn;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL)
+ if(count>=14)
{
- file_recovery_new->extension="sda";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft Word", 14)==0)
+ {
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL)
+ if(count>=15)
{
- file_recovery_new->extension="sdc";
+ /*@ 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;
+ }
}
- else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
+ if(count>=20)
{
- file_recovery_new->extension="sdd";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft PowerPoint", 20)==0)
+ {
+ *ext=extension_ppt;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- 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)
+ if(count>=21)
{
- file_recovery_new->extension="xls";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft Office Word", 21)==0)
+ {
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL)
+ if(count==21)
{
- file_recovery_new->extension="ppt";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "TurboCAD for Windows", 21)==0)
+ {
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
+ if(count==22)
{
- file_recovery_new->extension="mdb";
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "TurboCAD pour Windows", 22)==0)
+ {
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL)
+ /*@ 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 unsigned char *software, const unsigned int count)
+{
+ if(count>=15)
{
- file_recovery_new->extension="vsd";
+ /*@ 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;
+ }
}
- else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL)
+ if(count>=17)
{
- file_recovery_new->extension="sdw";
- }
- else if(td_memmem(buffer,buffer_size,"CPicPage",8)!=NULL)
- { /* Flash Project File */
- file_recovery_new->extension="fla";
- }
- else if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
- { /* Publisher */
- file_recovery_new->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="wdb";
- }
- else if(td_memmem(buffer,buffer_size,"MetaStock",9)!=NULL)
- { /* MetaStock */
- file_recovery_new->extension="mws";
+ /*@ 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;
+ }
}
- else
- file_recovery_new->extension=file_hint_doc.extension;
- return 1;
+ return NULL;
}
-static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
+struct summary_entry
{
- uint32_t *fat;
- uint32_t *dif;
- dif=(uint32_t*)MALLOC(109*4+(le32(header->num_extra_FAT_blocks)<<le16(header->uSectorShift)));
- memcpy(dif,(header+1),109*4);
- if(le32(header->num_extra_FAT_blocks)>0)
- { /* Load DIF*/
- unsigned long int i;
- unsigned long int block;
- unsigned char *data=(unsigned char*)&dif[109];
- for(i=0, block=le32(header->FAT_next_block);
- i<le32(header->num_extra_FAT_blocks) && block!=0xFFFFFFFF && block!=0xFFFFFFFE;
- i++, block=le32(dif[109+i*(((1<<le16(header->uSectorShift))/4)-1)]))
+ 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 unsigned 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)
{
- if(my_fseek(IN, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET) < 0)
- {
- free(dif);
- return NULL;
- }
- if(fread(data, 1<<le16(header->uSectorShift), 1, IN)!=1)
- {
- free(dif);
- return NULL;
- }
- data+=(1<<le16(header->uSectorShift))-4;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
}
- }
- fat=(uint32_t*)MALLOC(le32(header->num_FAT_blocks)<<le16(header->uSectorShift));
- { /* Load FAT */
- unsigned long int j;
- unsigned char *data;
- for(j=0, data=(unsigned char*)fat;
- j<le32(header->num_FAT_blocks);
- j++, data+=(1<<le16(header->uSectorShift)))
+ /*@ assert 0 < count <= size; */
+ if(offset_soft + count > size)
{
- if(my_fseek(IN, offset + ((1+le32(dif[j]))<<le16(header->uSectorShift)), SEEK_SET)<0)
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ 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<count; j++)
{
- free(dif);
- free(fat);
- return NULL;
- }
- if(fread(data, (1<<le16(header->uSectorShift)), 1, IN)!=1)
- {
- free(dif);
- free(fat);
- return NULL;
+ /*@ assert 0 <= j < count; */
+ /*@ assert offset_soft + count <= size; */
+ const unsigned int tmp=offset_soft+j;
+ /*@ assert tmp < size; */
+ log_info("%c", buffer[tmp]);
}
+ log_info("\n");
}
+#endif
+ software2ext(ext, &buffer[offset_soft], count);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
- free(dif);
- return fat;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
-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)
+/*@
+ @ 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_uni_software_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, const char **ext)
{
- unsigned char *dataPt;
- unsigned int block;
- unsigned int size_read;
- dataPt=(unsigned char *)MALLOC((len+(1<<uSectorShift)-1) / (1<<uSectorShift) * (1<<uSectorShift));
- for(block=block_start, size_read=0;
- size_read < len;
- block=le32(fat[block]), size_read+=(1<<uSectorShift))
+ if(offset >= size - 8)
{
- if(!(block < fat_entries))
+ /*@ 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)
{
- free(dataPt);
- return NULL;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
}
- if(my_fseek(IN, offset + ((1+block)<<uSectorShift), SEEK_SET)<0)
+ /*@ assert 0 < count <= size/2; */
+ count2=2*count;
+ /*@ assert 0 < count2 <= size; */
+ if(count2 > size - offset_soft)
{
- free(dataPt);
- return NULL;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
}
- if(fread(&dataPt[size_read], (1<<uSectorShift), 1, IN)!=1)
+ /*@ 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
{
- free(dataPt);
- return NULL;
+ 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);
}
- return dataPt;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
-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)
+/*@
+ @ 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 unsigned char *buffer, const unsigned int size, const unsigned int offset, char *title)
{
- unsigned char*minifat_pos;
- uint32_t *minifat;
- unsigned int block;
- unsigned int i;
- if(le32(header->csectMiniFat)==0)
- return NULL;
- minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << le16(header->uSectorShift));
- minifat_pos=(unsigned char*)minifat;
- block=le32(header->MiniFat_block);
- for(i=0; i < le32(header->csectMiniFat) && block < fat_entries; i++)
+ if(offset + 8 > size)
+ {
+ return;
+ }
+ /*@ assert offset + 8 <= size; */
{
- if(my_fseek(IN, offset + (((uint64_t)1+block) << le16(header->uSectorShift)), SEEK_SET) < 0)
+ /*@ 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)
{
- free(minifat);
- return NULL;
+ return;
}
- if(fread(minifat_pos, 1 << le16(header->uSectorShift), 1, IN) != 1)
+ /*@ assert 1 < count <= size; */
+ /*@ assert 1 < count <= 1024*1024; */
+ if(offset_tmp + count > size)
{
- free(minifat);
- return NULL;
+ return;
}
- minifat_pos+=1 << le16(header->uSectorShift);
- block=le32(fat[block]);
+ /*@ 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
}
- return minifat;
-}
-
-static uint32_t get32u(const void *buffer, const unsigned int offset)
-{
- const uint32_t *val=(const uint32_t *)((const unsigned char *)buffer+offset);
- return le32(*val);
+ /*@ assert valid_string(title); */
}
-static uint64_t get64u(const void *buffer, const unsigned int offset)
+/*@
+ @ 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 unsigned char *buffer, const unsigned int size, const unsigned int offset, time_t *file_time)
{
- const uint64_t *val=(const uint64_t *)((const unsigned char *)buffer+offset);
- return le64(*val);
-}
-
-static void software2ext(const char **ext, const unsigned int count, const unsigned char *software)
-{
- if(count>=12 && memcmp(software, "MicroStation", 12)==0)
+ uint64_t tmp;
+ if(offset + 12 > size)
{
- *ext="dgn";
- return;
+ return ;
}
- if(count>=14 && memcmp(software, "Microsoft Word", 14)==0)
+ /*@ assert offset + 12 <= size; */
+ tmp=get64u(buffer, offset + 4);
+ tmp/=10000000;
+ if(tmp > (uint64_t)134774 * 24 * 3600)
{
- *ext="doc";
- return;
+ tmp -= (uint64_t)134774 * 24 * 3600;
+ *file_time=tmp;
}
- if(count>=15 && memcmp(software, "Microsoft Excel", 15)==0)
+}
+
+/*@
+ @ 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 *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 unsigned 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)
{
- if(*ext==NULL || strcmp(*ext,"sldprt")!=0)
- *ext="xls";
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
return;
}
- if(count>=20 && memcmp(software, "Microsoft PowerPoint", 20)==0)
+ /*@ assert offset < size - 4; */
+ /*@ assert \valid_read(buffer + (0 .. offset + 4 - 1)); */
+ type=get32u(buffer, offset);
+#ifdef DEBUG_OLE
+ log_info("entry 0x%x, tag 0x%x, offset 0x%x, offset + 4 0x%x, type 0x%x\n",
+ entry_offset, 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)
{
- *ext="ppt";
+ /*@ assert valid_string(title); */
+ OLE_parse_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
return;
}
- if(count>=21 && memcmp(software, "Microsoft Office Word", 21)==0)
+ /* tag: Software, type: VT_LPWSTR */
+ if(tag==0x12 && type==31)
{
- *ext="doc";
+ /*@ 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;
}
- if(count==21 && memcmp(software, "TurboCAD for Windows", 21)==0)
+ /* tag: title, type: VT_LPSTR */
+ if(tag==0x02 && type==30 && title[0]=='\0')
{
- *ext="tcw";
- return;
+ OLE_parse_title_entry(buffer, size, offset, title);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return ;
}
- if(count==22 && memcmp(software, "TurboCAD pour Windows", 22)==0)
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ /* ModifyDate, type=VT_FILETIME */
+ if(tag==0x0d && type==64)
{
- *ext="tcw";
+ OLE_parse_filetime_entry(buffer, size, offset, file_time);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
return;
}
- return ;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
}
-static const char *software_uni2ext(const unsigned int count, const unsigned char *software)
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(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);
+ @*/
+/*X TODO assigns *ext, *(title + (0..1023)), *file_time; */
+/*X TODO requires \initialized(buffer+ (0 .. size-1)); */
+static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned int size, const char **ext, char *title, time_t *file_time)
{
- if(count>=15 && memcmp(software, "M\0i\0c\0r\0o\0s\0o\0f\0t\0 \0E\0x\0c\0e\0l\0", 30)==0)
- return "et";
- if(count>=17 && memcmp(software, "D\0e\0l\0c\0a\0m\0 \0P\0o\0w\0e\0r\0S\0H\0A\0P\0E\0", 34)==0)
- return "psmodel";
- return NULL;
+ 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 unsigned 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 variant numEntries-i;
+ @*/
+ /*X TODO loop assigns *ext, *(title + (0..1023)), *file_time; */
+ for(i=0; i<numEntries; i++)
+ {
+ const struct summary_entry *entry;
+ const unsigned int entry_offset=8+8*i;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ if(entry_offset + 8 > 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); */
+ entry=(const struct summary_entry *)&buffer[entry_offset];
+ 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); */
}
-static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char **title, time_t *file_time)
+/*@
+ @ 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);
+ @*/
+/*X TODO assigns *ext, *(title + (0..1023)), *file_time; */
+static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char *title, time_t *file_time)
{
unsigned int pos;
assert(dirLen >= 48 && dirLen<=1024*1024);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
#ifdef DEBUG_OLE
dump_log(dataPt, dirLen);
#endif
@@ -684,141 +1225,140 @@ static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned in
return ;
pos=get32u(dataPt, 44);
if(pos > dirLen - 8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
return ;
+ }
+ /*@ assert pos <= dirLen - 8; */
{
-// unsigned int size;
- unsigned int numEntries;
- unsigned int i;
- numEntries=get32u(dataPt, pos+4);
-#ifdef DEBUG_OLE
+ /* PropertySet */
+ const unsigned int size=get32u(dataPt, pos);
+ if(size <= 8 || size > dirLen || pos + size > dirLen)
{
- unsigned int size=get32u(dataPt, pos);
- log_info("Property Info %u - %u at 0x%x\n", numEntries, size, pos);
- }
-#endif
- if(pos + 8 + 8 * numEntries > dirLen)
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
return ;
- for(i=0; i<numEntries; i++)
- {
- const unsigned int entry = pos + 8 + 8 * i;
- const unsigned int tag=get32u(dataPt, entry);
- const unsigned int offset=get32u(dataPt, entry + 4);
- const unsigned int valStart = pos + 4 + offset;
- unsigned int type;
- if(valStart >= dirLen)
- return ;
- type=get32u(dataPt, pos + offset);
-#ifdef DEBUG_OLE
- log_info("entry 0x%x, tag 0x%x, offset 0x%x, valStart 0x%x, type 0x%x\n",
- entry, tag, offset, valStart, type);
-#endif
- /* tag: Software, type: VT_LPSTR */
- if(tag==0x12 && type==30)
- {
- unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + count > dirLen)
- return ;
-#ifdef DEBUG_OLE
- {
- unsigned int j;
- log_info("Software ");
- for(j=0; j<count; j++)
- {
- log_info("%c", dataPt[valStart + 4 + j]);
- }
- log_info("\n");
- }
-#endif
- software2ext(ext, count, &dataPt[valStart + 4]);
- }
- /* tag: Software, type: VT_LPWSTR */
- if(tag==0x12 && type==31)
- {
- unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + 2 * count > dirLen)
- return ;
-#ifdef DEBUG_OLE
- {
- unsigned int j;
- log_info("Software ");
- for(j=0; j < 2 * count; j+=2)
- {
- log_info("%c", dataPt[valStart + 4 + j]);
- }
- log_info("\n");
- }
-#endif
- *ext=software_uni2ext(count, &dataPt[valStart + 4]);
- }
- if(tag==0x02 && type==30 && *title==NULL)
- {
- const unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + count > dirLen)
- return ;
- *title=(char*)MALLOC(count+1);
- memcpy(*title, &dataPt[valStart + 4], count);
- (*title)[count]='\0';
-#ifdef DEBUG_OLE
- log_info("Title %s\n", *title);
-#endif
- }
- /* ModifyDate, type=VT_FILETIME */
- if(tag==0x0d && type==64)
- {
- uint64_t tmp=get64u(dataPt, valStart);
- tmp/=10000000;
- if(tmp > (uint64_t)134774 * 24 * 3600)
- {
- tmp -= (uint64_t)134774 * 24 * 3600;
- *file_time=tmp;
- }
- }
}
+ /*@ assert 8 < size; */
+ /*@ assert size <= dirLen; */
+ /*@ assert dirLen <=1024*1024; */
+ /*@ assert \valid_read(dataPt + (0 .. dirLen-1)); */
+ /*@ assert pos + size <= dirLen; */
+ /*@ assert \valid_read(dataPt + (0 .. pos+size-1)); */
+ /*@ assert \initialized(dataPt + (0 .. dirLen-1)); */
+ /*@ assert pos + size <= dirLen; */
+ /*X TODO assert \initialized(dataPt + (0 .. pos+size-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); */
}
-static void *OLE_read_ministream(unsigned char *ministream,
+/*@
+ @ 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;
unsigned int size_read;
+#ifdef __FRAMAC__
+ dataPt=(unsigned char *)MALLOC((1024*1024+(1<<uMiniSectorShift)-1) / (1<<uMiniSectorShift) * (1<<uMiniSectorShift));
+#else
dataPt=(unsigned char *)MALLOC((len+(1<<uMiniSectorShift)-1) / (1<<uMiniSectorShift) * (1<<uMiniSectorShift));
+#endif
for(mblock=miniblock_start, size_read=0;
size_read < len;
- mblock=le32(minifat[mblock]), size_read+=(1<<uMiniSectorShift))
+ size_read+=(1<<uMiniSectorShift))
{
- if(!(mblock < minifat_entries))
+ if(mblock >= minifat_entries)
{
free(dataPt);
return NULL;
}
- if((mblock<<uMiniSectorShift)+ (1<<uMiniSectorShift) <= ministream_size)
- memcpy(&dataPt[size_read], &ministream[mblock<<uMiniSectorShift], (1<<uMiniSectorShift));
+ /* TODO assert mblock < minifat_entries; */
+ if((mblock+1)> ministream_size>>uMiniSectorShift)
+ {
+ free(dataPt);
+ return NULL;
+ }
+ memcpy(&dataPt[size_read], &ministream[mblock<<uMiniSectorShift], (1<<uMiniSectorShift));
+#ifdef __FRAMAC__
+ mblock=Frama_C_interval(0, minifat_entries);
+#else
+ mblock=le32(minifat[mblock]);
+#endif
}
return dataPt;
}
+/*@
+ @ requires \valid(file);
+ @ requires \valid_read(fat + (0 .. fat_entries-1));
+ @ requires \valid_read(header);
+ @ requires 9 == le16(header->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 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);
unsigned 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 && ministream_size < 1024*1024)
+ 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) << le16(header->uSectorShift)) / 4;
+ 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, le16(header->uSectorShift),
+ fat, fat_entries, uSectorShift,
ministream_block, ministream_size, offset);
if(ministream != NULL)
{
@@ -832,27 +1372,55 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
}
else
summary=(unsigned char *)OLE_read_stream(file,
- fat, fat_entries, le16(header->uSectorShift),
+ fat, fat_entries, uSectorShift,
block, len, offset);
+#if defined(__FRAMAC__)
+ {
+ free(summary);
+ summary=MALLOC(4096);
+ Frama_C_make_unknown((char *)summary, 4096);
+ /*@ assert \initialized((char *)summary + (0 .. 4096 - 1)); */
+#if 0
+ OLE_parse_summary_aux(summary, 4096, ext, title, file_time);
+ /*@ assert valid_string(title); */
+#else
+ OLE_parse_PropertySet(summary, 4096, ext, title, file_time);
+#endif
+ /*@ assert valid_string(title); */
+ free(summary);
+ }
+#else
if(summary!=NULL)
{
OLE_parse_summary_aux(summary, len, ext, title, file_time);
free(summary);
}
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_doc;
+ @*/
static void file_rename_doc(file_recovery_t *file_recovery)
{
const char *ext=NULL;
- char *title=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="sdd";
+ ext=extension_sdd;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
return;
#ifdef DEBUG_OLE
@@ -865,10 +1433,33 @@ static void file_rename_doc(file_recovery_t *file_recovery)
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(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<<le16(header->uSectorShift))-1))
+ 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<<uSectorShift)/4-1))
{
fclose(file);
return ;
@@ -878,9 +1469,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
fclose(file);
return ;
}
- fat_entries=(le32(header->num_FAT_blocks)==0 ?
- 109:
- (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
+ fat_entries=(num_FAT_blocks==0 ? 109 : (num_FAT_blocks<<uSectorShift)/4);
{
unsigned int ministream_block=0;
unsigned int ministream_size=0;
@@ -891,43 +1480,48 @@ static void file_rename_doc(file_recovery_t *file_recovery)
#ifdef DEBUG_OLE
log_info("file_rename_doc root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
+#ifndef __FRAMAC__
for(block=le32(header->root_start_block), i=0;
block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
block=le32(fat[block]), i++)
+#else
+ block=le32(header->root_start_block), i=0;
+#endif
{
+ /*@ assert valid_string(&title[0]); */
struct OLE_DIR *dir_entries;
- if(my_fseek(file, (1+block)<<le16(header->uSectorShift), SEEK_SET)<0)
- {
- free(fat);
- fclose(file);
- free(title);
- return ;
- }
- dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
- if(fread(dir_entries, 1<<le16(header->uSectorShift), 1, file)!=1)
+#ifdef __FRAMAC__
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<12);
+#else
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<uSectorShift);
+#endif
+ if(OLE_read_block(file, (unsigned char *)dir_entries, uSectorShift, block, 0)<0)
{
free(fat);
free(dir_entries);
fclose(file);
- free(title);
return ;
}
-
#ifdef DEBUG_OLE
log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
+ /*@ assert valid_string(&title[0]); */
{
unsigned int sid;
- const struct OLE_DIR *dir_entry=dir_entries;
+ int is_db=0;
if(i==0)
{
+ const struct OLE_DIR *dir_entry=dir_entries;
ministream_block=le32(dir_entry->start_block);
ministream_size=le32(dir_entry->size);
}
- for(sid=0, dir_entry=dir_entries;
- sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR);
- sid++,dir_entry++)
+ /*@ assert valid_string(&title[0]); */
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
{
+ /*@ assert valid_string(&title[0]); */
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
if(dir_entry->type!=NO_ENTRY)
{
const char SummaryInformation[40]=
@@ -938,9 +1532,10 @@ static void file_rename_doc(file_recovery_t *file_recovery)
'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 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
+ for(j=0;j<64 && j<namsiz && dir_entry->name[j]!='\0';j+=2)
{
log_info("%c",dir_entry->name[j]);
}
@@ -950,140 +1545,83 @@ static void file_rename_doc(file_recovery_t *file_recovery)
(unsigned int)le32(dir_entry->start_block),
(unsigned int)le32(dir_entry->size));
#endif
- switch(le16(dir_entry->namsiz))
{
- case 10:
- if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
- ext="qdf-backup";
- break;
- case 12:
- /* 3ds max */
- if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
- ext="max";
- /* Licom AlphaCAM */
- else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
- ext="amb";
+ 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="psmodel";
+ 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="snt";
+ 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="xls";
- /* Microsoft Works .wps */
- else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
- ext="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)
- ext="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)
- ext="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)
- ext="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)
- ext="albm";
- /* Lotus Approach */
- else if(memcmp(dir_entry->name,"A\0p\0p\0r\0o\0a\0c\0h\0D\0o\0c\0\0\0",24)==0)
- ext="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)
- ext="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)
- ext="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)
- {
-#ifdef DJGPP
- ext="sld";
-#else
- ext="sldprt";
-#endif
- }
- 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)
- ext="camrec";
- 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)
- ext="sdc";
+ ext=extension_xls;
+ /*@ assert valid_string(&title[0]); */
break;
case 36:
/* sda=StarDraw, sdd=StarImpress */
- if((ext==NULL || strcmp(ext,"sdd")!=0) &&
+ 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="sda";
- else 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)
- ext="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)
- ext="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)
- ext="sdw";
+ 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, &file_time, 0);
+ &ext, &title[0], &file_time, 0);
+ /*@ assert valid_string(&title[0]); */
+ /*@ assert ext == \null || valid_read_string(ext); */
}
- else 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)
- ext="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)
- ext="msg";
+ /*@ assert valid_string(&title[0]); */
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)
- {
-#ifdef DJGPP
- ext="sld";
-#else
- ext="sldprt";
-#endif
- }
- break;
- case 56:
- /* Wilcom ES Software */
- if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
- ext="emb";
+ default:
+ /*@ assert valid_string(&title[0]); */
break;
}
- if(sid==1 && le16(dir_entry->namsiz) >=6 &&
+ /*@ assert valid_string(&title[0]); */
+ if(sid==1 && namsiz >=6 &&
memcmp(dir_entry->name, "D\0g\0n", 6)==0)
- ext="dgn";
+ ext=extension_dgn;
#ifdef DEBUG_OLE
if(ext!=NULL)
- log_info("Found %s %u\n", ext, le16(dir_entry->namsiz));
+ 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);
@@ -1092,15 +1630,228 @@ static void file_rename_doc(file_recovery_t *file_recovery)
set_date(file_recovery->filename, file_time, file_time);
if(title!=NULL)
{
- file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, ext, 1);
- free(title);
+ 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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_doc, buffer, file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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->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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+ // TODO ensures *buffer == \old(*buffer);
+ // TODO ensures *file_recovery == \old(*file_recovery);
+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<<le16(header->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<<le16(header->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=file_hint_doc.extension;
+ }
+ 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=file_hint_doc.extension;
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ return 1;
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
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);
}
+
+#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/src/file_emf.c b/src/file_emf.c
index db02070..b4a10d0 100644
--- a/src/file_emf.c
+++ b/src/file_emf.c
@@ -30,10 +30,11 @@
#include "filegen.h"
#include "log.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_emf(file_stat_t *file_stat);
-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 data_check_t data_check_emf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
const file_hint_t file_hint_emf= {
.extension="emf",
@@ -201,37 +202,30 @@ struct EMF_HDR
#define EMR_COLORMATCHTOTARGETW 121
#define EMR_CREATECOLORSPACEW 122
-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(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;
-}
-
+/*@
+ @ requires buffer_size >= 2;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_emf;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP || \result == DC_ERROR;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 8);
+ @ ensures file_recovery->data_check==&data_check_emf;
+ @ 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 - file_recovery->file_size + buffer_size/2;
- const unsigned int itype=buffer[i]+(buffer[i+1]<<8)+(buffer[i+2]<<16)+(buffer[i+3]<<24);
- const unsigned int atom_size=buffer[i+4]+(buffer[i+5]<<8)+(buffer[i+6]<<16)+(buffer[i+7]<<24);
+ 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)
@@ -362,15 +356,158 @@ static data_check_t data_check_emf(const unsigned char *buffer, const unsigned i
#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; */
}
+ /*@ 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 - 8; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 8; */
return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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;
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
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);
}
+
+#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/src/file_evtx.c b/src/file_evtx.c
new file mode 100644
index 0000000..68f884f
--- /dev/null
+++ b/src/file_evtx.c
@@ -0,0 +1,80 @@
+/*
+
+ File: file_evtx.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General 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 <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#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__));
+
+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=&register_header_check_evtx
+};
+
+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);
+}
diff --git a/src/file_exe.c b/src/file_exe.c
index 1348db5..2050e21 100644
--- a/src/file_exe.c
+++ b/src/file_exe.c
@@ -35,9 +35,11 @@
#include "filegen.h"
#include "pe.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_exe(file_stat_t *file_stat);
-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);
static void file_rename_pe_exe(file_recovery_t *file_recovery);
const file_hint_t file_hint_exe= {
@@ -49,124 +51,149 @@ const file_hint_t file_hint_exe= {
.register_header_check=&register_header_check_exe
};
+static const char *extension_dll="dll";
static const unsigned char exe_header[2] = {'M','Z'};
-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);
-}
-
+/*@
+ @ requires buffer_size >= 2;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_exe, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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;
- const struct pe_image_file_hdr *pe_hdr;
if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
return 0;
- pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
if(le32(dos_hdr->e_lfanew)>0 &&
- le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
- (le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
+ le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr))
{
- /* NE Win16 */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_exe.extension;
- return 1;
- }
- if(le32(dos_hdr->e_lfanew)>0 &&
- le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
- (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="dll";
- }
- else if(le16(pe_hdr->Characteristics) & 0x02)
+ 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;
}
- else
+ 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));
+ 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(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));
+ return 0;
}
- else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
+#ifdef DEBUG_EXE
{
- const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ 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));
+ }
}
- 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=0;
- 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));
- for(i=0;
- i<le16(pe_hdr->NumberOfSections) &&
- (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
- i++,pe_image_section++)
{
- if(le32(pe_image_section->SizeOfRawData)>0)
+ 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));
+ for(i=0;
+ i<le16(pe_hdr->NumberOfSections) &&
+ (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)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
+ 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 < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
- sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
+ if(le32(pe_image_section->SizeOfRawData)%32==0)
+ {
+ if(sum < tmp)
+ sum=tmp;
+ }
}
- }
- if(le16(pe_image_section->NumberOfRelocations)>0)
- {
+ 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)le32(pe_image_section->PointerToRelocations)+1*le16(pe_image_section->NumberOfRelocations)-1);
+ log_debug("relocations 0x%lx-0x%lx\n",
+ (unsigned long)le32(pe_image_section->PointerToRelocations),
+ (unsigned long)(tmp-1));
#endif
- if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
- sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ if(sum < tmp)
+ sum = tmp;
+ }
}
- }
- if(le32(pe_hdr->NumberOfSymbols)>0)
- {
+ 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)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
+ 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 < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
- sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
+ 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;
}
- /* 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;
}
- 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 &&
@@ -183,23 +210,36 @@ static int header_check_exe(const unsigned char *buffer, const unsigned int buff
{ /* 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
{
- unsigned int i;
- const struct exe_reloc *exe_reloc;
+ 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", le16(dos_hdr->num_relocs));
- for(i=0, exe_reloc=(const struct exe_reloc *)(buffer+le16(dos_hdr->reloc_table_offset));
- i < le16(dos_hdr->num_relocs) &&
- le16(dos_hdr->reloc_table_offset)+ (i+1)*sizeof(struct exe_reloc) < buffer_size;
- i++, exe_reloc++)
+ log_info("reloc %u\n", num_relocs);
+ if(reloc_table_offset + num_relocs * sizeof(struct exe_reloc) <= buffer_size)
{
- log_info("offset %x, segment %x\n",
- le16(exe_reloc->offset), le16(exe_reloc->segment));
+ 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
@@ -213,11 +253,17 @@ struct rsrc_entries_s
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;
+ uint16_t type; /* 0=binary data, 1=text*/
} __attribute__ ((gcc_struct, __packed__));
static char vs_version_info[32]={
@@ -241,276 +287,618 @@ static char InternalName[24]={
'N', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0
};
-static unsigned int ReadUnicodeStr(const char *buffer, unsigned int pos, const unsigned int 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_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)
{
- for(; pos+2<len && (buffer[pos]!='\0' || buffer[pos+1]!='\0'); pos+=2)
+ 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
- log_info("%c", buffer[pos]);
+ 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);
}
- pos+=2;
- if((pos & 0x03)!=0)
- pos+=2;
- return pos;
+ return len;
}
-static int PEVersion_aux(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int 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_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;
- while(1)
+#ifdef DEBUG_EXE
+ log_info("parse_StringArray end=%u\n", end);
+#endif
+ /*@
+ @ loop variant end - pos;
+ @*/
+ while(pos<end)
{
- const struct PE_index *PE_index;
- pos=(pos + 3) & 0xfffffffc; /* align on a 4-byte boundary */
- if(pos + 6 > end)
- {
+ const int res=parse_String(file_recovery, &buffer[pos], end - pos, needle, needle_len, force_ext);
+ if(res <= 0)
return -1;
- }
- PE_index=(const struct PE_index*)&buffer[pos];
- if(le16(PE_index->len)==0 && le16(PE_index->val_len)==0)
- {
- return -1;
- }
- {
- const char *stringName=&buffer[pos+6];
- if(pos + 6 + sizeof(vs_version_info) < end &&
- memcmp(stringName, vs_version_info, sizeof(vs_version_info))==0)
- {
- pos+=6+sizeof(vs_version_info);
- if((pos & 0x03)!=0)
- pos+=2;
- pos+=le16(PE_index->val_len);
- }
- else if(pos + 6 + sizeof(StringFileInfo) < end &&
- memcmp(stringName, StringFileInfo, sizeof(StringFileInfo))==0 &&
- le16(PE_index->val_len)==0)
- {
- unsigned int i;
- unsigned int pt=pos+6+sizeof(StringFileInfo);
- pos+=le16(PE_index->len);
- for(i=0; pt + 6 < pos; i++)
- {
- if(i==0)
- {
- pt=ReadUnicodeStr(buffer, pt+6, pos);
- }
- else
- {
- int do_rename=0;
- PE_index=(const struct PE_index*)&buffer[pt];
- if(pt+6+needle_len < end &&
- memcmp(&buffer[pt+6], needle, needle_len)==0)
- {
- do_rename=1;
- }
- pt=ReadUnicodeStr(buffer, pt+6, pos);
- if(le16(PE_index->val_len)>0)
- {
- if(do_rename)
- {
- file_rename_unicode(file_recovery, buffer, end, pt, NULL, force_ext);
- return 0;
- }
+ /*@ assert res > 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(": ");
+ log_info("parse_StringTable len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
#endif
- pt=ReadUnicodeStr(buffer, pt, pos);
- }
- }
+ 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("\n");
+ log_info("parse_StringFileInfo len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
#endif
- }
- }
- else
- {
- pos+=le16(PE_index->len)+le16(PE_index->val_len);
- }
- }
+ 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;
+ 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 ;
- buffer=(char*)MALLOC(length);
- if(fread(buffer, length, 1, file) != 1)
+ if(fread(&buffer, length, 1, file) != 1)
{
- free(buffer);
return ;
}
- if(PEVersion_aux(file_recovery, buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
+#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)
{
- free(buffer);
return;
}
- PEVersion_aux(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
- free(buffer);
+ 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; j<nbr_sections; j++)
+ {
+ const struct pe_image_section_hdr *pe_section=&pe_sections[j];
+ const uint32_t virt_addr_start=le32(pe_section->VirtualAddress);
+ 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;
}
-static void file_exe_ressource(FILE *file, const unsigned int base, const unsigned int dir_start, const unsigned int size, const unsigned int rsrcType, const unsigned int level, const struct pe_image_section_hdr *pe_sections, unsigned int nbr_sections, file_recovery_t *file_recovery)
+/*@
+ @ 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;
- struct rsrc_entries_s *rsrc_entry;
- unsigned char buffer[16];
- int buffer_size;
- unsigned int nameEntries;
- unsigned idEntries;
unsigned int count;
unsigned int i;
#ifdef DEBUG_EXE
- log_info("file_exe_ressource(file, %u, %u, %u, %u)\n", base, dir_start, size, level);
+ 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(level > 2)
+ if(count==0 || count > 1024)
return ;
- if(fseek(file, base + dir_start, SEEK_SET)<0)
+ /*@ 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 ;
- buffer_size=fread(buffer, 1, sizeof(buffer), file);
- if(buffer_size<16)
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
+ {
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+ int res=pe_resource_language_aux(file, base, pe_sections, nbr_sections, file_recovery, rsrc_entry);
+ if(res <= 0)
+ {
+ free(rsrc_entries);
+ return ;
+ }
+ }
+ free(rsrc_entries);
+}
+
+/*@
+ @ 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_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 ;
- nameEntries = buffer[12]+(buffer[13]<<8);
- idEntries = buffer[14]+(buffer[15]<<8);
- count = nameEntries + idEntries;
+ /*@ 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; i<count; i++)
+ {
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+#ifdef DEBUG_EXE
+ log_info("resource id=%u, %x, offset %u\n",
+ le32(rsrc_entry->Type),
+ 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 ;
}
- for(i=0, rsrc_entry=rsrc_entries; i<count; i++, rsrc_entry++)
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
{
- const unsigned int rsrcType_new=(level==0?le32(rsrc_entry->Type):rsrcType);
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+ const unsigned int rsrcType=le32(rsrc_entry->Type);
#ifdef DEBUG_EXE
- log_info("ressource %u, %x, offset %u\n",
- rsrcType_new,
+ log_info("resource type=%u, %x, offset %u\n",
+ rsrcType,
le32(rsrc_entry->Pos),
base + (le32(rsrc_entry->Pos) & 0x7fffffff));
#endif
- /* Only intersted by version resources */
- if(rsrcType_new==16)
+ /* 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)
{
- file_exe_ressource(file,
+ pe_resource_id(file,
base,
le32(rsrc_entry->Pos) & 0x7fffffff,
- size,
- (level==0?le32(rsrc_entry->Type):rsrcType),
- level + 1,
pe_sections, nbr_sections, file_recovery);
}
- if(level==2)
- {
- unsigned int off;
- unsigned int len;
- if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0)
- {
- free(rsrc_entries);
- return ;
- }
- buffer_size=fread(buffer, 1, sizeof(buffer), file);
- if(buffer_size<16)
- {
- free(rsrc_entries);
- return ;
- }
- off=buffer[0]+ (buffer[1]<<8) + (buffer[2]<<16) + (buffer[3]<<24);
- len=buffer[4]+ (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
- {
- const struct pe_image_section_hdr *pe_section;
- for(i=0, pe_section=pe_sections; i<nbr_sections; i++,pe_section++)
- {
- if(le32(pe_section->VirtualAddress) <= off
- && off < le32(pe_section->VirtualAddress) + le32(pe_section->SizeOfRawData))
- {
- PEVersion(file, off - le32(pe_section->VirtualAddress) + base, len, file_recovery);
- free(rsrc_entries);
- return ;
- }
- }
- }
- free(rsrc_entries);
- return ;
- }
}
}
free(rsrc_entries);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_pe_exe;
+ @*/
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 dos_image_file_hdr*)buffer;
+ 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 ;
}
- if((unsigned int)buffer_size < le32(dos_hdr->e_lfanew)+sizeof(struct pe_image_file_hdr))
+ 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+le32(dos_hdr->e_lfanew));
- if(le32(dos_hdr->e_lfanew)==0 ||
- le32(dos_hdr->e_lfanew) > buffer_size-sizeof(struct pe_image_file_hdr) ||
- le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
+ 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;
- const struct pe_image_section_hdr *pe_sections;
- const struct pe_image_section_hdr *pe_section;
- unsigned int nbr_sections;
- pe_sections=(const struct pe_image_section_hdr*)
- ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
- for(i=0, pe_section=pe_sections;
- i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
- i++, pe_section++)
+ 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
- if(le32(pe_section->SizeOfRawData)>0)
+ /*@
+ @ loop invariant 0 <= i <= nbr_sections;
+ @*/
+ for(i=0; i<nbr_sections; i++)
+ {
+ const struct pe_image_section_hdr *pe_section=&pe_sections[i];
+ /*@ assert \valid_read(pe_section); */
+ if(le32(pe_section->VirtualSize)>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
}
- nbr_sections=i;
- for(i=0, pe_section=pe_sections;
- i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
- i++, pe_section++)
+#endif
+ /*@
+ @ loop invariant 0 <= i <= nbr_sections;
+ @*/
+ for(i=0; i<nbr_sections; i++)
{
+ const struct pe_image_section_hdr *pe_section=&pe_sections[i];
+ /*@ assert \valid_read(pe_section); */
if(le32(pe_section->SizeOfRawData)>0)
{
if(memcmp((const char*)pe_section->Name, ".rsrc", 6)==0)
{
- file_exe_ressource(file,
+ pe_resource_type(file,
le32(pe_section->PointerToRawData),
- 0,
le32(pe_section->SizeOfRawData),
- 0,
- 0,
pe_sections, nbr_sections, file_recovery);
fclose(file);
return;
@@ -520,3 +908,97 @@ static void file_rename_pe_exe(file_recovery_t *file_recovery)
}
fclose(file);
}
+
+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);
+}
+
+#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/src/file_exr.c b/src/file_exr.c
new file mode 100644
index 0000000..f0df6ba
--- /dev/null
+++ b/src/file_exr.c
@@ -0,0 +1,58 @@
+/*
+
+ File: file_exr.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General 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 <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+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=&register_header_check_exr
+};
+
+/* https://www.openexr.com/documentation/openexrfilelayout.pdf */
+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);
+}
diff --git a/src/file_fp7.c b/src/file_fp7.c
index c82763c..8e54e54 100644
--- a/src/file_fp7.c
+++ b/src/file_fp7.c
@@ -54,7 +54,7 @@ static int header_check_fp7(const unsigned char *buffer, const unsigned int buff
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="fp12";
+ file_recovery_new->extension="fmp12";
else
file_recovery_new->extension=file_hint_fp7.extension;
return 1;
diff --git a/src/file_gpg.c b/src/file_gpg.c
index 387e168..6492aed 100644
--- a/src/file_gpg.c
+++ b/src/file_gpg.c
@@ -33,9 +33,12 @@
#ifdef DEBUG_GPG
#include "log.h"
#endif
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+static const char *extension_pgp="pgp";
static void register_header_check_gpg(file_stat_t *file_stat);
-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);
const file_hint_t file_hint_gpg= {
.extension="gpg",
@@ -82,31 +85,24 @@ const file_hint_t file_hint_gpg= {
static const unsigned char pgp_header[5]= {0xa8, 0x03, 'P', 'G', 'P'};
-static void register_header_check_gpg(file_stat_t *file_stat)
-{
- static const unsigned char gpg_header_pkey_enc[1]= {0x85};
- static const unsigned char gpg_header_symkey_enc[1]= {0x8c};
- static const unsigned char gpg_header_seckey[1]= {0x95};
-#if 1
- static const unsigned char gpg_header_pkey[1]= {0x99};
-#endif
- register_header_check(0, gpg_header_seckey, sizeof(gpg_header_seckey), &header_check_gpg, file_stat);
- register_header_check(0, gpg_header_symkey_enc, sizeof(gpg_header_symkey_enc), &header_check_gpg, file_stat);
- register_header_check(0, gpg_header_pkey_enc, sizeof(gpg_header_pkey_enc), &header_check_gpg, file_stat);
- register_header_check(0, pgp_header, sizeof(pgp_header), &header_check_gpg, file_stat);
-#if 1
- register_header_check(0, gpg_header_pkey, sizeof(gpg_header_pkey), &header_check_gpg, file_stat);
-#endif
-}
-
-static unsigned int openpgp_packet_tag(const unsigned char *buf)
+/*@
+ @ ensures 0 <= \result <= 0x3f;
+ @ assigns \nothing;
+ @*/
+static unsigned int openpgp_packet_tag(const unsigned char buf)
{
/* Bit 7 -- Always one */
- if((buf[0]&0x80)==0)
+ if((buf&0x80)==0)
return 0; /* Invalid */
- return ((buf[0]&0x40)==0?((buf[0]>>2)&0x0f):(buf[0]&0x3f));
+ return ((buf&0x40)==0?((buf>>2)&0x0f):(buf&0x3f));
}
+/*@ requires \valid_read(buf+(0..5));
+ @ requires \valid(length_type);
+ @ requires \valid(indeterminate_length);
+ @ 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 */
@@ -119,8 +115,11 @@ static unsigned int old_format_packet_length(const unsigned char *buf, unsigned
*length_type=3;
return (buf[1] << 8) | buf[2];
case 2:
- *length_type=5;
- return (buf[1] << 24) |(buf[2] << 16) | (buf[3] << 8) | buf[4];
+ {
+ const uint32_t *tmp32_ptr=(const uint32_t *)&buf[1];
+ *length_type=5;
+ return be32(*tmp32_ptr);
+ }
default:
*length_type=1;
*indeterminate_length=1;
@@ -128,41 +127,77 @@ static unsigned int old_format_packet_length(const unsigned char *buf, unsigned
}
}
+/*@ 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(buf[0]<=191)
+ if(buf0<=191)
{
*length_type=1;
- return buf[0];
+ /*@ assert buf0 <= 191; */
+ return buf0;
}
/* Two-Octet Body Length */
- if(buf[0]<=223)
+ 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;
- return ((buf[0] - 192) << 8) + buf[1] + 192;
+ /*@ assert 192 <= tmp <= ((223-192) << 8) + 255 + 192; */
+ return tmp;
}
+ /*@ assert 224 <= buf0; */
/* Five-Octet Body Length */
- if(buf[0]==255)
+ if(buf0==255)
{
+ const uint32_t *tmp32=(const uint32_t *)&buf[1];
+ const unsigned int tmp=be32(*tmp32);
*length_type=5;
- return (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
+ /*@ 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;
}
- /* Partial Body Lengths */
- *length_type=1;
- *partial_body_length=1;
- return 1 << (buf[0]& 0x1F);
}
-static int is_valid_mpi(const uint16_t *size)
+/*@
+ @ ensures \result == -1 || 0 <= \result <= 2048;
+ @ assigns \nothing;
+ @*/
+static int is_valid_mpi(const uint16_t size)
{
- if(be16(*size) <= 16384)
- return (be16(*size)+7)/8;
+ const uint16_t tmp=be16(size);
+ if(tmp <= 16384)
+ return (tmp+7)/8;
return -1;
}
-static int is_valid_pubkey_algo(const int algo)
+/*@
+ @ 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
@@ -189,6 +224,10 @@ static int is_valid_pubkey_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @ assigns \nothing;
+ @*/
static int is_valid_sym_algo(const int algo)
{
/*
@@ -222,6 +261,10 @@ static int is_valid_sym_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @ assigns \nothing;
+ @*/
static int is_valid_S2K(const unsigned int algo)
{
/* ID S2K Type
@@ -235,48 +278,90 @@ static int is_valid_S2K(const unsigned int algo)
return (algo==0 || algo==1 || algo==3);
}
+/*@
+ @ requires \valid(handle);
+ @ requires offset + tmp2 < 0x8000000000000000;
+ @*/
+static unsigned int file_check_gpg_pubkey(FILE *handle, const uint64_t offset, const uint64_t tmp2)
+{
+ int len2;
+ uint16_t mpi2;
+ if(my_fseek(handle, offset+tmp2, SEEK_SET) < 0 ||
+ fread(&mpi2, sizeof(mpi2), 1, handle) != 1)
+ return 0;
+#ifdef __FRAMAC__
+ Frama_C_make_unknown((char *)&mpi2, sizeof(mpi2));
+#endif
+ len2=is_valid_mpi(mpi2);
+#ifdef DEBUG_GPG
+ log_info(" data: [ %u bits]\n", be16(mpi2));
+#endif
+ if(len2 < 0)
+ return 0;
+ return len2;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_gpg;
+ @*/
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;
- off_t offset=0;
- unsigned char buffer[32];
+ uint64_t offset=0;
const uint64_t org_file_size=file_recovery->file_size;
file_recovery->file_size=0;
while(stop==0)
{
+ unsigned char buffer[32];
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(&buffer, sizeof(buffer), 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((char *)&buffer, sizeof(buffer));
+#endif
if(partial_body_length==0)
{
- if((buffer[i]&0x80)==0)
+ if((buffer[0]&0x80)==0)
break; /* Invalid */
- tag=openpgp_packet_tag(&buffer[i]);
- if((buffer[i]&0x40)==0)
+ tag=openpgp_packet_tag(buffer[0]);
+ if((buffer[0]&0x40)==0)
{
- length=old_format_packet_length(&buffer[i], &length_type, &stop);
+ 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[i+1], &length_type, &partial_body_length);
+ 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[i], &length_type, &partial_body_length);
+ 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",
- i, nbr, tag, length_type, length);
+ 0, nbr, tag, length_type, length);
#endif
#if 0
if(tag==0 || tag==15 || (tag>19 && tag!=61)) /* Reserved or unused */
@@ -284,46 +369,48 @@ static void file_check_gpg(file_recovery_t *file_recovery)
#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 || offset + length >= 0x7000000000000000)
+ return ;
+ /*@ assert offset < 0x7000000000000000; */
+ /*@ assert offset + length < 0x7000000000000000; */
if(old_partial_body_length==0)
{
if(tag==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY)
{
- const uint16_t *mpi=(const uint16_t *)&buffer[i+1+8+1];
- const int len=is_valid_mpi(mpi);
+ 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(buffer[i+1+8]) &&
+ 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], buffer[i+1+8],
+ 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));
+ log_info(" data: [ %u bits]\n", be16(*mpi_ptr));
#endif
- if((unsigned)(1+8+1+2+len) > length)
+ if(tmp2 > length)
return ;
- if(buffer[i+1+8]==16 || buffer[i+1+8]==20)
+ /*@ assert tmp2 <= length; */
+ if(pubkey_algo==16 || pubkey_algo==20)
{
- int len2;
- unsigned char tmp[2];
- if(my_fseek(file_recovery->handle, offset+1+8+1+2+len, SEEK_SET) < 0 ||
- fread(&tmp, sizeof(tmp), 1, file_recovery->handle) != 1)
- return;
- mpi=(const uint16_t *)&tmp[0];
- len2=is_valid_mpi(mpi);
-#ifdef DEBUG_GPG
- log_info(" data: [ %u bits]\n", be16(*mpi));
-#endif
+ const int len2=file_check_gpg_pubkey(file_recovery->handle, offset, tmp2);
if(len2 <= 0)
- return ;
+ return;
if((unsigned)(1+8+1+2+len+2+len2) > length)
- return ;
+ return;
}
}
else
@@ -408,6 +495,28 @@ static void file_check_gpg(file_recovery_t *file_recovery)
file_recovery->file_size=(stop==0?org_file_size:(uint64_t)offset);
}
+/*@
+ @ requires buffer_size >= 23;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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;
@@ -416,8 +525,12 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
int partial_body_length=0;
int stop=0;
memset(packet_tag, 0, sizeof(packet_tag));
- while(nbr<16 && i < buffer_size - 20 && stop==0)
+ /*@
+ @ loop invariant 0 <= nbr <=16;
+ @*/
+ 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;
@@ -426,24 +539,28 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
{
if((buffer[i]&0x80)==0)
break; /* Invalid */
- packet_tag[nbr]=openpgp_packet_tag(&buffer[i]);
+ 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%04x: %02u tag=%2u, size=%u + %u)\n",
+ log_info("GPG 0x%04lx: %02u tag=%2u, size=%u + %u)\n",
i, nbr, tag, length_type, length);
#endif
#if 0
@@ -452,13 +569,15 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
#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=(const uint16_t *)&buffer[i+1+8+1];
- const int len=is_valid_mpi(mpi);
+ 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
@@ -466,23 +585,25 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
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));
+ log_info(" data: [ %u bits]\n", be16(*mpi_ptr));
#endif
- if((unsigned)(1+8+1+2+len) > length)
+ if(offset_mpi +2 > length)
return 0;
if((buffer[i+1+8]==16 || buffer[i+1+8]==20) &&
- i+1+8+1+2+len+2<buffer_size)
+ offset_mpi + 2 <= buffer_size)
{
int len2;
- mpi=(const uint16_t *)&buffer[i+1+8+1+2+len];
- len2=is_valid_mpi(mpi);
+ /*@ 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));
+ log_info(" data: [ %u bits]\n", be16(*mpi_ptr));
#endif
if(len2 <= 0)
return 0;
@@ -600,7 +721,7 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
{
reset_file_recovery(file_recovery_new);
file_recovery_new->file_check=&file_check_gpg;
- file_recovery_new->extension="pgp";
+ file_recovery_new->extension=extension_pgp;
return 1;
}
if( /* encrypted_data.gpg */
@@ -641,3 +762,84 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
#endif
return 0;
}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_gpg(file_stat_t *file_stat)
+{
+ static const unsigned char gpg_header_pkey_enc[1]= {0x85};
+ static const unsigned char gpg_header_symkey_enc[1]= {0x8c};
+ static const unsigned char gpg_header_seckey[1]= {0x95};
+ static const unsigned char gpg_header_pkey[1]= {0x99};
+ register_header_check(0, gpg_header_seckey, sizeof(gpg_header_seckey), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_symkey_enc, sizeof(gpg_header_symkey_enc), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_pkey_enc, sizeof(gpg_header_pkey_enc), &header_check_gpg, file_stat);
+ register_header_check(0, pgp_header, sizeof(pgp_header), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_pkey, sizeof(gpg_header_pkey), &header_check_gpg, file_stat);
+}
+
+#if defined(MAIN_gpg)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.gpg";
+ 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_gpg;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_gpg(&file_stats);
+ if(header_check_gpg(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_gpg.extension || file_recovery_new.extension == extension_pgp; */
+ /*@ assert file_recovery_new.file_check == &file_check_gpg; */
+ /*@ assert file_recovery_new.file_stat->file_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/src/file_gz.c b/src/file_gz.c
index 0ef52e0..f67cb84 100644
--- a/src/file_gz.c
+++ b/src/file_gz.c
@@ -23,6 +23,11 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#ifdef __FRAMAC__
+#undef HAVE_LIBZ
+#endif
+
#ifdef HAVE_STRING_H
#include <string.h>
#endif
@@ -157,17 +162,6 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
}
if(off >= 512 || off >= buffer_size)
return 0;
- 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;
- }
- if(file_recovery->file_check==&file_check_bgzf)
- {
- header_ignored(file_recovery_new);
- return 0;
- }
#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
{
static const unsigned char schematic_header[12]={ 0x0a, 0x00, 0x09,
@@ -207,6 +201,17 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
/* Probably too small to be a file */
if(d_stream.total_out < 16)
return 0;
+ 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;
+ }
+ if(file_recovery->file_check==&file_check_bgzf)
+ {
+ header_ignored(file_recovery_new);
+ return 0;
+ }
buffer_uncompr[d_stream.total_out]='\0';
if(bgzf!=0)
{
@@ -297,6 +302,17 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
}
}
#else
+ 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;
+ }
+ if(file_recovery->file_check==&file_check_bgzf)
+ {
+ header_ignored(file_recovery_new);
+ return 0;
+ }
reset_file_recovery(file_recovery_new);
file_recovery_new->min_filesize=22;
file_recovery_new->time=le32(gz->mtime);
diff --git a/src/file_ico.c b/src/file_ico.c
index 03bebb3..af2ae41 100644
--- a/src/file_ico.c
+++ b/src/file_ico.c
@@ -33,7 +33,6 @@
#include "log.h"
static void register_header_check_ico(file_stat_t *file_stat);
-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 file_hint_t file_hint_ico= {
.extension="ico",
@@ -54,20 +53,6 @@ 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};
-
-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);
- 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);
-}
-
/*
* http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)
*/
@@ -103,7 +88,7 @@ static int header_check_ico(const unsigned char *buffer, const unsigned int buff
if(le16(ico->reserved)!=0 || le16(ico->type)!=1 || le16(ico->count)==0)
return 0;
for(i=0, ico_dir=(const struct ico_directory*)(ico+1);
- i<le16(ico->count);
+ (const unsigned char *)(ico_dir+1) <= buffer+buffer_size && i<le16(ico->count);
i++, ico_dir++)
{
#ifdef DEBUG_ICO
@@ -157,3 +142,16 @@ static int header_check_ico(const unsigned char *buffer, const unsigned int buff
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);
+ 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);
+}
diff --git a/src/file_jpg.c b/src/file_jpg.c
index 8c8ae08..67c2723 100644
--- a/src/file_jpg.c
+++ b/src/file_jpg.c
@@ -23,6 +23,12 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#ifdef __FRAMAC__
+#undef HAVE_LIBJPEG
+#undef DEBUG_JPEG
+#endif
+
#ifdef HAVE_STRING_H
#include <string.h>
#endif
@@ -49,18 +55,22 @@
#include "file_jpg.h"
#include "file_tiff.h"
#include "setdate.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_jpg) && !defined(MAIN_fidentify)
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;
extern data_check_t data_check_avi_stream(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+#endif
static void register_header_check_jpg(file_stat_t *file_stat);
-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);
static void file_check_jpg(file_recovery_t *file_recovery);
-data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, 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);
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= {
@@ -72,12 +82,12 @@ const file_hint_t file_hint_jpg= {
.register_header_check=&register_header_check_jpg
};
-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);
-}
-
+/*@
+ @ requires \valid_read(buffer + (0 .. buffer_size-1));
+ @ requires \valid(height);
+ @ requires \valid(width);
+ @ requires \separated(buffer, 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;
@@ -108,7 +118,7 @@ struct MP_IFD_Field
uint16_t tag;
uint16_t type;
uint32_t count;
- char value[0];
+ char value[4];
} __attribute__ ((gcc_struct, __packed__));
struct MP_Entry
@@ -120,6 +130,11 @@ struct MP_Entry
uint16_t dep2;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ 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;
@@ -129,40 +144,55 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
unsigned int nbr;
unsigned int NumberOfImages=0;
unsigned int MPEntry_offset=0;
- const struct MP_Entry* MPEntry;
uint64_t max_offset=0;
#ifdef DEBUG_JPEG
log_info("check_mpo_be\n");
#endif
- if(offset+2 >= size)
+ 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++)
{
- const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)(&mpo[offset]);
- if(offset+12 > size)
- return 0;
+ /*@ 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(be16(field->type)!=7 || be32(field->count)!=4)
+ if(type!=7 || count!=4)
return 0;
break;
case 0xb001:
/* NumberOfImages, type must be long */
- if(be16(field->type)!=4 || be32(field->count)!=1)
+ 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(be16(field->type)!=7 || be32(field->count)!=16*NumberOfImages)
+ if(type!=7 || count!=16*NumberOfImages)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
@@ -170,74 +200,105 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
}
break;
}
- offset+=12;
}
#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 + 16*NumberOfImages > size)
return 0;
- for(i=0, MPEntry=(const struct MP_Entry*)(&mpo[MPEntry_offset]);
- i<NumberOfImages;
- i++, MPEntry++)
+ /*@
+ @ loop invariant 0 <= i <= NumberOfImages;
+ @ loop assigns i, max_offset;
+ @ loop variant NumberOfImages-i;
+ @*/
+ for(i=0; i<NumberOfImages; i++)
{
- uint64_t tmp=be32(MPEntry->offset)+be32(MPEntry->size);
+ /*@ assert 0 <= i < NumberOfImages; */
+ const unsigned char *MPEntry_ptr=&mpo[MPEntry_offset + i * sizeof(struct MP_Entry)];
+ /*@ assert \valid_read(MPEntry_ptr+ ( 0 .. sizeof(struct MP_Entry)-1)); */
+ const struct MP_Entry *MPEntry=(const struct MP_Entry*)MPEntry_ptr;
+ uint64_t tmp=be32(MPEntry->size);
#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+=mpo_offset;
+ tmp+=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;
- const struct MP_Entry* MPEntry;
uint64_t max_offset=0;
#ifdef DEBUG_JPEG
log_info("check_mpo_le\n");
#endif
- if(offset+2 >= size)
+ 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++)
{
- const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)(&mpo[offset]);
- if(offset+12 > size)
- return 0;
+ /*@ 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(le16(field->type)!=7 || le32(field->count)!=4)
+ if(type!=7 || count!=4)
return 0;
break;
case 0xb001:
/* NumberOfImages, type must be long */
- if(le16(field->type)!=4 || le32(field->count)!=1)
+ 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(le16(field->type)!=7 || le32(field->count)!=16*NumberOfImages)
+ if(type!=7 || count!=16*NumberOfImages)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
@@ -245,33 +306,51 @@ static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset
}
break;
}
- offset+=12;
}
#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 + 16*NumberOfImages > size)
return 0;
- for(i=0, MPEntry=(const struct MP_Entry*)(&mpo[MPEntry_offset]);
- i<NumberOfImages;
- i++, MPEntry++)
+ /*@
+ @ loop invariant 0 <= i <= NumberOfImages;
+ @ loop assigns i, max_offset;
+ @ loop variant NumberOfImages-i;
+ @*/
+ for(i=0; i<NumberOfImages; i++)
{
- uint64_t tmp=le32(MPEntry->offset)+le32(MPEntry->size);
+ /*@ assert 0 <= i < NumberOfImages; */
+ const unsigned char *MPEntry_ptr=&mpo[MPEntry_offset + i * sizeof(struct MP_Entry)];
+ /*@ assert \valid_read(MPEntry_ptr+ ( 0 .. sizeof(struct MP_Entry)-1)); */
+ const struct MP_Entry *MPEntry=(const struct MP_Entry*)MPEntry_ptr;
+ uint64_t tmp=le32(MPEntry->size);
#ifdef DEBUG_JPEG
log_info("offset=%lu, size=%lu\n",
(long unsigned)le32(MPEntry->offset),
(long unsigned)le32(MPEntry->size));
#endif
if(le32(MPEntry->offset)>0)
- tmp+=mpo_offset;
+ 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);
@@ -283,6 +362,13 @@ static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires valid_read_string((char *)&fr->filename);
+ @ requires \initialized(&fr->time);
+ @ requires fr->file_check==&file_check_mpo;
+ @*/
static void file_check_mpo(file_recovery_t *fr)
{
unsigned char buffer[512];
@@ -300,12 +386,21 @@ static void file_check_mpo(file_recovery_t *fr)
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(&buffer, 1, sizeof(buffer), fr->handle);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#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 */
@@ -314,19 +409,22 @@ static void file_check_mpo(file_recovery_t *fr)
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(2+size > nbytes)
- size=nbytes-2;
- if(size<12)
+ if(8+size > nbytes)
+ 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);
fr->file_size=(max_offset > fr->file_size ? 0 : max_offset);
@@ -372,10 +470,83 @@ static int is_marker_valid(const unsigned int marker)
}
}
+/*@
+ @ requires \valid_read(buffer + (0 .. buffer_size-1));
+ @*/
+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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_jpg, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_jpg.extension;
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ 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 > 0;
+ @ ensures \result == 1 ==> file_recovery_new->offset_ok == 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 ==> valid_read_string(file_recovery_new->extension);
+ @*/
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;
+ while(i+4<buffer_size && buffer[i]==0xff && is_marker_valid(buffer[i+1]))
+ {
+ const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
+ if(buffer[i+1]==0xff)
+ i++;
+ else
+ {
+ if(buffer[i+1]==0xe1)
+ { /* APP1 Exif information */
+ jpg_time=jpg_get_date(buffer, buffer_size, i, size);
+ }
+ else if(buffer[i+1]==0xc4)
+ {
+ /* DHT */
+ if(jpg_check_dht(buffer, buffer_size, i, 2+(buffer[i+2]<<8)+buffer[i+3])!=0)
+ return 0;
+ }
+ i+=2+size;
+ }
+ }
+ if(i+1 < file_recovery_new->blocksize && buffer[i+1]!=0xda)
+ return 0;
+ if(i+1 < 512 && buffer[i+1]!=0xda)
+ return 0;
if(file_recovery->file_stat!=NULL)
{
static const unsigned char jpg_header_app0_avi[0x0c]= {
@@ -388,17 +559,19 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
unsigned int width=0;
unsigned int height=0;
jpg_get_size(buffer, buffer_size, &height, &width);
+#if !defined(MAIN_jpg) && !defined(MAIN_fidentify)
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)
+ 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 */
@@ -432,6 +605,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
return 0;
}
}
+#if !defined(MAIN_jpg) && !defined(MAIN_fidentify)
/* 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 ||
@@ -454,6 +628,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
if(buffer[3]==0xdb) /* DQT */
{
header_ignored(file_recovery_new);
@@ -480,35 +655,6 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
return 0;
}
}
- while(i+4<buffer_size && buffer[i]==0xff && is_marker_valid(buffer[i+1]))
- {
- if(buffer[i+1]==0xff)
- i++;
- else
- {
- if(buffer[i+1]==0xe1)
- { /* APP1 Exif information */
- if(i+0x0A < buffer_size && 2+(buffer[i+2]<<8)+buffer[i+3] > 0x0A)
- {
- unsigned int tiff_size=2+(buffer[i+2]<<8)+buffer[i+3]-0x0A;
- if(buffer_size - (i+0x0A) < tiff_size)
- tiff_size=buffer_size - (i+0x0A);
- jpg_time=get_date_from_tiff_header((const TIFFHeader*)&buffer[i+0x0A], tiff_size);
- }
- }
- else if(buffer[i+1]==0xc4)
- {
- /* DHT */
- if(jpg_check_dht(buffer, buffer_size, i, 2+(buffer[i+2]<<8)+buffer[i+3])!=0)
- return 0;
- }
- i+=2+(buffer[i+2]<<8)+buffer[i+3];
- }
- }
- if(i+1 < file_recovery->blocksize && buffer[i+1]!=0xda)
- return 0;
- if(i+1 < 512 && buffer[i+1]!=0xda)
- return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->min_filesize=i;
file_recovery_new->calculated_file_size=0;
@@ -517,6 +663,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
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;
}
@@ -741,13 +888,25 @@ static void jpg_term_source (j_decompress_ptr cinfo)
}
+/* 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, uint64_t offset, const unsigned int blocksize)
+static void jpeg_testdisk_src (j_decompress_ptr cinfo, FILE * infile, const uint64_t offset, const unsigned int blocksize)
{
my_source_mgr * src;
@@ -759,13 +918,7 @@ static void jpeg_testdisk_src (j_decompress_ptr cinfo, FILE * infile, uint64_t o
* manager serially with the same JPEG object. Caveat programmer.
*/
if (cinfo->src == NULL) { /* first time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof(my_source_mgr));
- src = (my_source_mgr *) cinfo->src;
- src->buffer = (JOCTET *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- blocksize * sizeof(JOCTET));
+ jpeg_testdisk_alloc_src(cinfo, blocksize);
}
src = (my_source_mgr *) cinfo->src;
@@ -1176,7 +1329,7 @@ static uint64_t jpg_check_thumb(FILE *infile, const uint64_t offset, const unsig
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", offset_error);
+// 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);
@@ -1250,7 +1403,6 @@ static void jpg_check_picture(file_recovery_t *file_recovery)
(long long unsigned)file_recovery->offset_ok,
(long long unsigned)file_recovery->offset_error);
#endif
-#if 1
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);
@@ -1262,7 +1414,6 @@ static void jpg_check_picture(file_recovery_t *file_recovery)
(long long unsigned)file_recovery->offset_error);
#endif
}
-#endif
jpeg_session_delete(&jpeg_session);
return;
}
@@ -1328,13 +1479,19 @@ static void jpg_check_picture(file_recovery_t *file_recovery)
}
#endif
-static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned i, const unsigned int size)
+/*@
+ @ 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 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;
@@ -1348,6 +1505,12 @@ static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_
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];
@@ -1369,299 +1532,412 @@ struct sof_header
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)
{
- const struct sof_header *h=(const struct sof_header *)&buffer[i];
if(i+4 > buffer_size)
return 0;
- if(be16(h->length) < sizeof(struct sof_header)-2)
- return 1;
+ {
+ 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;
- if(h->precision!=8 || be16(h->width)==0 || h->nbr==0)
- return 1;
- if(be16(h->length) < 8+h->nbr*3)
- return 1;
+ {
+ 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 file_recovery->blocksize <= 1048576;
+ @ requires file_recovery->offset_error <= (1<<63) - 1;
+ @ ensures \valid(file_recovery->handle);
+ @*/
static void jpg_search_marker(file_recovery_t *file_recovery)
{
FILE* infile=file_recovery->handle;
unsigned char buffer[40*8192];
size_t nbytes;
+ const uint64_t offset_error=file_recovery->offset_error;
+ uint64_t offset_test=offset_error;
uint64_t offset;
- unsigned int i;
+ /*@ assert offset_test == offset_error; */
if(file_recovery->blocksize==0)
return ;
- offset=file_recovery->offset_error / file_recovery->blocksize * file_recovery->blocksize;
- i=file_recovery->offset_error % file_recovery->blocksize;
+ offset=offset_test / file_recovery->blocksize * file_recovery->blocksize;
if(my_fseek(infile, offset, SEEK_SET) < 0)
return ;
- do
+ /*@ assert offset_test == offset_error; */
+ /*@
+ @ loop invariant offset_test >= offset_error;
+ @*/
+ while((nbytes=fread(&buffer, 1, sizeof(buffer), infile))>0)
{
- while((nbytes=fread(&buffer, 1, sizeof(buffer), infile))>0)
+ unsigned int i;
+ /*@ assert 0 < nbytes <= sizeof(buffer); */
+ if(offset_test > 0x80000000)
+ return ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#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<nbytes)
{
- for(;i+1<nbytes; i+=file_recovery->blocksize)
+ const uint64_t tmp=offset + i;
+ /*@ assert tmp == offset + i; */
+ /*@ assert tmp >= 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 */
+ )
{
- 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)
{
- file_recovery->extra=offset + i - file_recovery->offset_error;
- 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);
- }
- return ;
+ 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 +=nbytes;
- i=i % file_recovery->blocksize;
- } while(nbytes == sizeof(buffer));
+ offset_test += nbytes;
+ }
return ;
}
-static uint64_t jpg_check_structure(file_recovery_t *file_recovery, const unsigned int extract_thumb)
-{
- FILE* infile=file_recovery->handle;
- unsigned char buffer[40*8192];
- uint64_t thumb_offset=0;
- size_t nbytes;
- file_recovery->extra=0;
- if(my_fseek(infile, 0, SEEK_SET) < 0)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires \valid(thumb_offset);
+ @ requires valid_read_string((char *)&file_recovery->filename);
+ @ requires file_recovery->blocksize > 0;
+ @ requires \valid_read(buffer + (0 .. nbytes-1));
+ @ requires \initialized(&file_recovery->time);
+ @ ensures \valid(file_recovery->handle);
+ @*/
+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 size_t nbytes, uint64_t *thumb_offset)
+{ /* APP1 Exif information */
+ const unsigned int tiff_offset=i+2+8;
+ const unsigned char *potential_error=NULL;
+ const unsigned char *thumb_data=NULL;
+ const unsigned char *tiff;
+ unsigned int thumb_size=0;
+ unsigned int tiff_size;
+ 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))
+ return 1;
+ /*@ assert 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(*thumb_offset!=0)
+ {
+ *thumb_offset+=tiff_offset;
+ thumb_data=buffer+ (*thumb_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((nbytes=fread(&buffer, 1, sizeof(buffer), infile))>0)
+ }
+ if(file_recovery->offset_ok<i)
+ file_recovery->offset_ok=i;
+ if(thumb_data!=0 && thumb_size!=0 && *thumb_offset < nbytes - 1)
{
- unsigned int offset;
- file_recovery->offset_error=0;
- for(offset=file_recovery->blocksize; offset < nbytes && file_recovery->offset_error==0; offset+=file_recovery->blocksize)
+ 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)
{
- 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;
- }
+ file_recovery->offset_error=*thumb_offset;
+ jpg_search_marker(file_recovery);
+ return 0;
}
- offset=2;
- while(offset + 4 < nbytes && (file_recovery->offset_error==0 || offset < file_recovery->offset_error))
+ if(buffer[*thumb_offset+1]!=0xd8)
{
- const unsigned int i=offset;
- const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
- if(buffer[i]!=0xff)
+ file_recovery->offset_error=*thumb_offset+1;
+ return 0;
+ }
+ while(j+4<nbytes && thumb_sos_found==0)
+ {
+ if(buffer[j]!=0xff)
{
+ file_recovery->offset_error=j;
#ifdef DEBUG_JPEG
- log_info("%s no marker at 0x%x\n", file_recovery->filename, i);
+ 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
- file_recovery->offset_error=i;
jpg_search_marker(file_recovery);
- return thumb_offset;
+ return 0;
}
- if(buffer[i+1]==0xff)
+ if(buffer[j+1]==0xff)
{
/* See B.1.1.2 Markers in http://www.w3.org/Graphics/JPEG/itu-t81.pdf*/
- offset++;
+ j++;
continue;
}
#ifdef DEBUG_JPEG
- log_info("%s marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[i+1], i);
+ log_info("%s thumb marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j);
#endif
- offset+=(uint64_t)2+size;
- if(buffer[i+1]==0xda) /* SOS: Start Of Scan */
+ if(buffer[j+1]==0xda) /* Thumb SOS: Start Of Scan */
+ thumb_sos_found=1;
+ else if(buffer[j+1]==0xc4) /* DHT */
{
- file_recovery->offset_ok=i+1;
- return thumb_offset;
- }
- else if(buffer[i+1]==0xe1)
- { /* APP1 Exif information */
-#if 1
- if(i+0x0A < nbytes && 2+size > 0x0A)
+ if(jpg_check_dht(buffer, nbytes, j, 2+(buffer[j+2]<<8)+buffer[j+3])!=0)
{
- const char *potential_error=NULL;
- const TIFFHeader *tiff=(const TIFFHeader*)&buffer[i+0x0A];
- unsigned int tiff_size=2+size-0x0A;
- const char *thumb_data=NULL;
- const char *ifbytecount=NULL;
- if(nbytes - (i+0x0A) < tiff_size)
- tiff_size=nbytes - (i+0x0A);
- if(file_recovery->time==0)
- file_recovery->time=get_date_from_tiff_header(tiff, tiff_size);
- thumb_data=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFOFFSET, &potential_error);
- if(thumb_data!=NULL)
- {
- thumb_offset=thumb_data-(const char*)buffer;
- ifbytecount=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFBYTECOUNT, &potential_error);
- }
- if(potential_error!=NULL)
- {
- file_recovery->offset_error=potential_error-(const char*)buffer;
- return 0;
- }
- if(file_recovery->offset_ok<i)
- file_recovery->offset_ok=i;
- if(thumb_data!=NULL && ifbytecount!=NULL)
- {
- const unsigned int thumb_size=ifbytecount-(const char*)tiff;
- if(thumb_offset < nbytes - 1)
- {
- unsigned int j=thumb_offset+2;
- unsigned int thumb_sos_found=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
+ {
+ log_info("%s thumb unknown marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j);
+ file_recovery->offset_error=j;
+ return 0;
+ }
+ if(file_recovery->offset_ok<j)
+ file_recovery->offset_ok=j;
#ifdef DEBUG_JPEG
- unsigned int j_old=j;
+ 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;
- }
- while(j+4<nbytes && thumb_sos_found==0)
- {
- if(buffer[j]!=0xff)
- {
- file_recovery->offset_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);
+ j+=2U+(buffer[j+2]<<8)+buffer[j+3];
+ }
+ if(thumb_sos_found>0 && extract_thumb>0
+ && offset < nbytes && buffer[offset]==0xff &&
+ *thumb_offset+thumb_size < nbytes)
+ {
+ 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
- if(buffer[j+1]==0xda) /* Thumb SOS: Start Of Scan */
- thumb_sos_found=1;
- else if(buffer[j+1]==0xc4) /* DHT */
- {
-#if 1
- if(jpg_check_dht(buffer, nbytes, j, 2+(buffer[j+2]<<8)+buffer[j+3])!=0)
- {
- file_recovery->offset_error=j+2;
- return 0;
- }
-#endif
- }
- 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
- {
- log_info("%s thumb unknown marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j);
- file_recovery->offset_error=j;
- return 0;
- }
- if(file_recovery->offset_ok<j)
- file_recovery->offset_ok=j;
-#ifdef DEBUG_JPEG
- j_old=j;
+ )
+ {
+ FILE *out;
+#ifndef __FRAMAC__
+ *(sep+1)='t';
#endif
- j+=2U+(buffer[j+2]<<8)+buffer[j+3];
- }
- if(thumb_sos_found>0 && extract_thumb>0
- && offset < nbytes && buffer[offset]==0xff)
- {
- char *thumbname;
- char *sep;
- thumbname=strdup(file_recovery->filename);
- sep=strrchr(thumbname,'/');
- if(sep!=NULL && *(sep+1)=='f' && thumb_offset+thumb_size < nbytes)
- {
- FILE *out;
- *(sep+1)='t';
- if((out=fopen(thumbname,"wb"))!=NULL)
- {
- if(fwrite(thumb_data, thumb_size, 1, out) < 1)
- {
- log_error("Can't write to %s: %s\n", thumbname, strerror(errno));
- }
- fclose(out);
- if(file_recovery->time!=0 && file_recovery->time!=(time_t)-1)
- set_date(thumbname, file_recovery->time, file_recovery->time);
- }
- else
- {
- log_error("fopen %s failed\n", thumbname);
- }
- }
- free(thumbname);
- }
- }
+ if((out=fopen(thumbname,"wb"))!=NULL)
+ {
+ const char *buffer_char=(const char *)buffer;
+ /*@ assert \valid_read(buffer_char + (0 .. nbytes - 1)); */
+ /*@ assert *thumb_offset + thumb_size < nbytes; */
+ /*@ assert \valid_read(buffer_char + (0 .. *thumb_offset + thumb_size - 1)); */
+ /*@ assert \valid_read(buffer_char + *thumb_offset + (0 .. thumb_size - 1)); */
+ const char *thumb_char=&buffer_char[*thumb_offset];
+ /*@ assert \valid_read(thumb_char + (0 .. thumb_size - 1)); */
+ if(fwrite(thumb_char, thumb_size, 1, out) < 1)
+ {
+ log_error("Can't write to %s: %s\n", thumbname, strerror(errno));
}
+ fclose(out);
+ if(file_recovery->time!=0 && file_recovery->time!=(time_t)-1)
+ set_date(thumbname, file_recovery->time, file_recovery->time);
}
-#endif
- }
- else if(buffer[i+1]==0xc4) /* DHT */
- {
-#if 1
- if(jpg_check_dht(buffer, nbytes, i, 2+size)!=0)
+ else
{
- file_recovery->offset_error=i+2;
- return thumb_offset;
+ log_error("fopen %s failed\n", thumbname);
}
-#endif
- if(file_recovery->offset_ok<i+1)
- file_recovery->offset_ok=i+1;
}
- else if(buffer[i+1]==0xdb || /* DQT */
- (buffer[i+1]>=0xc0 && buffer[i+1]<=0xcf) || /* SOF0 - SOF15 */
- buffer[i+1]==0xdd || /* DRI */
- (buffer[i+1]>=0xe0 && buffer[i+1]<=0xef) || /* APP0 - APP15 */
- buffer[i+1]==0xfe) /* COM */
- {
- if(file_recovery->offset_ok<i+1)
- file_recovery->offset_ok=i+1;
- }
- else
+ }
+ }
+ 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);
+ */
+static uint64_t jpg_check_structure(file_recovery_t *file_recovery, const unsigned int extract_thumb)
+{
+ FILE* infile=file_recovery->handle;
+ unsigned char buffer[40*8192];
+ uint64_t thumb_offset=0;
+ size_t nbytes;
+ unsigned int offset;
+ file_recovery->extra=0;
+ if(my_fseek(infile, 0, SEEK_SET) < 0)
+ return 0;
+ nbytes=fread(&buffer, 1, sizeof(buffer), infile);
+ if(nbytes <= 0)
+ return 0;
+ /*@ assert nbytes > 0; */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#endif
+ file_recovery->offset_error=0;
+ 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;
+ while(offset + 4 < nbytes && (file_recovery->offset_error==0 || offset < file_recovery->offset_error))
+ {
+ const unsigned int i=offset;
+ const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
+ if(buffer[i]!=0xff)
+ {
+#if defined(DEBUG_JPEG)
+ log_info("%s no marker at 0x%x\n", file_recovery->filename, i);
+#endif
+ file_recovery->offset_error=i;
+ jpg_search_marker(file_recovery);
+ return thumb_offset;
+ }
+ 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 0x%02x at 0x%x\n", file_recovery->filename, buffer[i+1], i);
+#endif
+ offset+=(uint64_t)2+size;
+ if(buffer[i+1]==0xda) /* SOS: Start Of Scan */
+ {
+ file_recovery->offset_ok=i+1;
+ return thumb_offset;
+ }
+ else 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)
{
- log_info("%s unknown marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[i+1], i+1);
- file_recovery->offset_error=i+1;
+ file_recovery->offset_error=i+2;
return thumb_offset;
}
+ if(file_recovery->offset_ok<i+1)
+ file_recovery->offset_ok=i+1;
}
- if(offset > nbytes && nbytes < sizeof(buffer))
+ else if(buffer[i+1]==0xdb || /* DQT */
+ (buffer[i+1]>=0xc0 && buffer[i+1]<=0xcf) || /* SOF0 - SOF15 */
+ buffer[i+1]==0xdd || /* DRI */
+ (buffer[i+1]>=0xe0 && buffer[i+1]<=0xef) || /* APP0 - APP15 */
+ buffer[i+1]==0xfe) /* COM */
+ {
+ if(file_recovery->offset_ok<i+1)
+ file_recovery->offset_ok=i+1;
+ }
+ else
{
- file_recovery->offset_error=nbytes;
+#ifndef __FRAMAC__
+ log_info("%s unknown marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[i+1], i+1);
+#endif
+ file_recovery->offset_error=i+1;
return thumb_offset;
}
}
+ if(offset > nbytes && nbytes < sizeof(buffer))
+ {
+ file_recovery->offset_error=nbytes;
+ return thumb_offset;
+ }
return thumb_offset;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires valid_read_string((char *)&file_recovery->filename);
+ @ requires \initialized(&file_recovery->time);
+ @ requires file_recovery->file_check == &file_check_mpo || file_recovery->file_check == &file_check_jpg;
+ @*/
static void file_check_jpg(file_recovery_t *file_recovery)
{
uint64_t thumb_offset;
@@ -1731,27 +2007,39 @@ static void file_check_jpg(file_recovery_t *file_recovery)
#endif
}
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->calculated_file_size >= 2;
+ @ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @ requires file_recovery->data_check == &data_check_jpg2;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == \null;
+ @ ensures file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2;
+ @ 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)
{
-#if 0
- unsigned int old_marker=0;
-#endif
- if(file_recovery->calculated_file_size<2)
- {
- /* Reset to the correct file checker */
- file_recovery->data_check=&data_check_jpg;
- return data_check_jpg(buffer, buffer_size, file_recovery);
- }
+ /*@
+ @ 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 < file_recovery->file_size + buffer_size/2)
{
- const unsigned int i=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 file_recovery->data_check == &data_check_jpg2; */
if(buffer[i-1]==0xFF)
{
if(buffer[i]==0xd9)
{
/* JPEG_EOI */
file_recovery->calculated_file_size++;
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
return DC_STOP;
}
else if(buffer[i] >= 0xd0 && buffer[i] <= 0xd7)
@@ -1770,6 +2058,7 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
/* TODO: store old_marker in file_recovery */
old_marker=buffer[i];
#endif
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
}
else if(buffer[i] == 0xda || buffer[i] == 0xc4)
{
@@ -1785,29 +2074,59 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
(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; */
return DC_STOP;
}
}
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
file_recovery->calculated_file_size++;
}
return DC_CONTINUE;
}
-data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+/*@
+ @ requires buffer_size >= 8;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid(file_recovery);
+ @ requires buffer_size >= 4;
+ @ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @ requires file_recovery->data_check == &data_check_jpg;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ 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;
+ @ 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==0)
- file_recovery->calculated_file_size+=2;
+ 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)
{
- const unsigned int i=file_recovery->calculated_file_size - 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,
@@ -1817,44 +2136,87 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
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;
- return data_check_jpg2(buffer, buffer_size, file_recovery);
+ /*@ 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; */
+ /*@ 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)
{
- unsigned int size_test=size;
- if(i + 2 + size >= buffer_size)
- {
- size_test=buffer_size-i-2;
- }
+ const uint64_t offset=old_calculated_file_size+8;
if(i>=buffer_size/2)
{
- file_recovery->calculated_file_size-=2+size;
+ /* Restore previous value */
+ file_recovery->calculated_file_size=old_calculated_file_size;
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
return DC_CONTINUE;
}
- if(size>12)
+ /*@ assert 0 <= i < buffer_size / 2 ; */
+ if( i + size <= buffer_size)
{
- const uint64_t offset=file_recovery->calculated_file_size-(2+size)+8;
- const uint64_t calculated_file_size=check_mpo(buffer+i+8, offset, size_test-8);
- if(calculated_file_size > 0)
+ /*@ assert i + size <= buffer_size; */
+ /*@ assert size <= buffer_size - i; */
+ if(size >= 16)
{
- /* 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;
- return DC_CONTINUE;
+ /*@ 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;
+ }
}
}
}
@@ -1866,9 +2228,13 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
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;
}
@@ -1892,3 +2258,137 @@ const char*td_jpeg_version(void)
return "none";
#endif
}
+
+
+/*@
+ @ requires \valid(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);
+}
+
+#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/src/file_list.c b/src/file_list.c
index 61a1dd5..6e3685a 100644
--- a/src/file_list.c
+++ b/src/file_list.c
@@ -121,7 +121,9 @@ 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;
@@ -286,6 +288,7 @@ 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;
@@ -361,8 +364,9 @@ 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 list_file_enable[]=
+file_enable_t array_file_enable[]=
{
+#ifndef MAIN_fidentify
{ .enable=0, .file_hint=&file_hint_sig },
{ .enable=0, .file_hint=&file_hint_1cd },
{ .enable=0, .file_hint=&file_hint_3dm },
@@ -402,7 +406,9 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_binvox },
{ .enable=0, .file_hint=&file_hint_bkf },
{ .enable=0, .file_hint=&file_hint_blend },
+#endif
{ .enable=0, .file_hint=&file_hint_bmp },
+#ifndef MAIN_fidentify
{ .enable=0, .file_hint=&file_hint_bpg },
{ .enable=0, .file_hint=&file_hint_bvr },
{ .enable=0, .file_hint=&file_hint_bz2 },
@@ -458,7 +464,9 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_emf },
{ .enable=0, .file_hint=&file_hint_ess },
{ .enable=0, .file_hint=&file_hint_evt },
+ { .enable=0, .file_hint=&file_hint_evtx },
{ .enable=0, .file_hint=&file_hint_exe },
+ { .enable=0, .file_hint=&file_hint_exr },
{ .enable=0, .file_hint=&file_hint_exs },
{ .enable=0, .file_hint=&file_hint_ext2_sb },
{ .enable=0, .file_hint=&file_hint_ext2_fs },
@@ -622,6 +630,7 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_rw2 },
{ .enable=0, .file_hint=&file_hint_rx2 },
{ .enable=0, .file_hint=&file_hint_save },
+ { .enable=0, .file_hint=&file_hint_sdsk },
{ .enable=0, .file_hint=&file_hint_ses },
{ .enable=0, .file_hint=&file_hint_sgcta },
{ .enable=0, .file_hint=&file_hint_shn },
@@ -696,6 +705,7 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_zcode },
{ .enable=0, .file_hint=&file_hint_zip },
{ .enable=0, .file_hint=&file_hint_zpr },
+#endif
{ .enable=0, .file_hint=NULL }
};
diff --git a/src/file_m2ts.c b/src/file_m2ts.c
index ca3a7bf..3a8a456 100644
--- a/src/file_m2ts.c
+++ b/src/file_m2ts.c
@@ -120,7 +120,7 @@ static int header_check_m2ts(const unsigned char *buffer, const unsigned int buf
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_m2ts &&
(file_recovery->data_check==&data_check_ts_192 ||
- file_recovery->blocksize < 5))
+ file_recovery_new->blocksize < 5))
{
header_ignored(file_recovery_new);
return 0;
diff --git a/src/file_mov.c b/src/file_mov.c
index dc9c138..a403eb9 100644
--- a/src/file_mov.c
+++ b/src/file_mov.c
@@ -32,12 +32,12 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_mov(file_stat_t *file_stat);
static void register_header_check_mov_mdat(file_stat_t *file_stat);
-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);
-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);
-static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
const file_hint_t file_hint_mov= {
.extension="mov",
@@ -57,30 +57,13 @@ const file_hint_t file_hint_mov_mdat= {
.register_header_check=&register_header_check_mov_mdat
};
-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);
-}
-
-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);
- 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);
-}
+static const char *extension_mp4="mp4";
+static const char *extension_m4p="m4p";
+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
{
@@ -95,6 +78,10 @@ struct atom64_struct
uint64_t size;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_mov(file_recovery_t *file_recovery)
{
FILE *file;
@@ -107,29 +94,145 @@ static void file_rename_mov(file_recovery_t *file_recovery)
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);
}
-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)
+/*@
+ @ requires buffer_size >= 16;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_mov;
+ @ requires file_recovery->file_size == 0 || file_recovery->calculated_file_size > file_recovery->file_size - 16;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 16);
+ @*/
+static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_mov &&
- (file_recovery->calculated_file_size == file_recovery->file_size ||
- file_recovery->blocksize < 16))
- { /* PhotoRec is already trying to recover this mov file */
- header_ignored(file_recovery_new);
- return 0;
+ 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==1)
+ {
+ const struct atom64_struct *atom64;
+ if(i + 16 > buffer_size)
+ {
+ /*@ assert file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size + 16 > buffer_size; */
+ /*@ assert file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 16; */
+ return DC_CONTINUE;
+ }
+ /*@ assert i + 16 <= buffer_size; */
+ atom64=(const struct atom64_struct*)&buffer[i];
+ atom_size=be64(atom64->size);
+ if(atom_size<16)
+ return DC_STOP;
+ }
+ else if(atom_size<8)
+ return DC_STOP;
+ 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( (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
+ (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='v' && buffer[i+7]=='d') ||
+ (buffer[i+4]=='d' && buffer[i+5]=='c' && buffer[i+6]=='o' && buffer[i+7]=='m') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='e') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p') ||
+ (buffer[i+4]=='j' && buffer[i+5]=='p' && buffer[i+6]=='2' && buffer[i+7]=='h') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='i' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='e' && buffer[i+6]=='t' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
+ (buffer[i+4]=='P' && buffer[i+5]=='I' && buffer[i+6]=='C' && buffer[i+7]=='T') ||
+ (buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t') ||
+ (buffer[i+4]=='s' && buffer[i+5]=='k' && buffer[i+6]=='i' && buffer[i+7]=='p') ||
+ (buffer[i+4]=='s' && buffer[i+5]=='t' && buffer[i+6]=='b' && buffer[i+7]=='l') ||
+ (buffer[i+4]=='t' && buffer[i+5]=='h' && buffer[i+6]=='u' && buffer[i+7]=='m') ||
+ (buffer[i+4]=='t' && buffer[i+5]=='r' && buffer[i+6]=='a' && buffer[i+7]=='k') ||
+ (buffer[i+4]=='u' && buffer[i+5]=='u' && buffer[i+6]=='i' && buffer[i+7]=='d') ||
+ (buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e') )
+ {
+ file_recovery->calculated_file_size+=atom_size;
+ }
+ else
+ {
+ 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);
+ return DC_STOP;
+ }
}
- return header_check_mov_aux(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new);
+ /*@ 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 - 8; */
+ /*@ assert file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 8; */
+#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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_m4p ||
+ 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)
+ 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)
{
@@ -137,47 +240,65 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
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->blocksize < 16)
+ 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=i+atom_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->blocksize < 16)
+ 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=i+atom_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->blocksize < 16)
+ 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')
{
@@ -188,13 +309,14 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
*/
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_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 ||
@@ -203,92 +325,117 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
memcmp(&buffer[i+8], "M4P", 3)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="mp4";
+ 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=i+atom_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);
/* acc ? */
- file_recovery_new->extension="m4p";
+ file_recovery_new->extension=extension_m4p;
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=i+atom_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="3gp";
+ 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=i+atom_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="3g2";
+ 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=i+atom_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="heic";
+ 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=i+atom_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="jp2";
+ 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="mov";
+ 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=i+atom_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="cr3";
- file_recovery_new->file_rename=&file_rename_mov;
+ 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=i+atom_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, "der.mdat\" anim=\"", 16)==0)
+ if(memcmp(&buffer[i], "der.mdat\" anim=\"", 16)==0)
return 0;
if(file_recovery->file_stat!=NULL &&
buffer[8]=='a' && isprint(buffer[0]) && isprint(buffer[1]) && isprint(buffer[2]) && isprint(buffer[3]))
@@ -299,88 +446,180 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
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)
+ 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=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
+ if(atom_size > buffer_size)
+ return 0;
i+=atom_size;
}
return 0;
}
-static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+/*@
+ @ requires buffer_size >= 16;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_m4p ||
+ 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)
{
- 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 - file_recovery->file_size + buffer_size/2;
- const struct atom_struct *atom=(const struct atom_struct*)&buffer[i];
- uint64_t atom_size=be32(atom->size);
- if(atom_size==1)
- {
- const struct atom64_struct *atom64=(const struct atom64_struct*)&buffer[i];
- if(file_recovery->calculated_file_size + 16 > file_recovery->file_size + buffer_size/2)
- return DC_CONTINUE;
- atom_size=be64(atom64->size);
- if(atom_size<16)
- return DC_STOP;
- }
- else if(atom_size<8)
- return DC_STOP;
-#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);
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_mov &&
+ (file_recovery->calculated_file_size == file_recovery->file_size ||
+ file_recovery_new->blocksize < 16))
+ { /* 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(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(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);
+ 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);
+}
+
+#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
- if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t')
+
+ 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)
{
- file_recovery->calculated_file_size+=atom_size;
-#if 0
- if(i+8 == buffer_size)
- {
- return -((atom_size + buffer_size/2 - 1)/ (buffer_size/2));
- }
+ /*@ 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);
}
- else if( (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
- (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='v' && buffer[i+7]=='d') ||
- (buffer[i+4]=='d' && buffer[i+5]=='c' && buffer[i+6]=='o' && buffer[i+7]=='m') ||
- (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='a') ||
- (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='e') ||
- (buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p') ||
- (buffer[i+4]=='j' && buffer[i+5]=='p' && buffer[i+6]=='2' && buffer[i+7]=='h') ||
- (buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='i' && buffer[i+7]=='a') ||
- (buffer[i+4]=='m' && buffer[i+5]=='e' && buffer[i+6]=='t' && buffer[i+7]=='a') ||
- (buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
- (buffer[i+4]=='P' && buffer[i+5]=='I' && buffer[i+6]=='C' && buffer[i+7]=='T') ||
- (buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t') ||
- (buffer[i+4]=='s' && buffer[i+5]=='k' && buffer[i+6]=='i' && buffer[i+7]=='p') ||
- (buffer[i+4]=='s' && buffer[i+5]=='t' && buffer[i+6]=='b' && buffer[i+7]=='l') ||
- (buffer[i+4]=='t' && buffer[i+5]=='h' && buffer[i+6]=='u' && buffer[i+7]=='m') ||
- (buffer[i+4]=='t' && buffer[i+5]=='r' && buffer[i+6]=='a' && buffer[i+7]=='k') ||
- (buffer[i+4]=='u' && buffer[i+5]=='u' && buffer[i+6]=='i' && buffer[i+7]=='d') ||
- (buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e') )
- {
- file_recovery->calculated_file_size+=atom_size;
- }
- else
+ }
+ /*@ 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)
{
- 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);
- return DC_STOP;
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
}
}
-#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;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_mov(&file_recovery_new);
+ return 0;
}
+#endif
diff --git a/src/file_mp3.c b/src/file_mp3.c
index 9cde947..11431da 100644
--- a/src/file_mp3.c
+++ b/src/file_mp3.c
@@ -31,15 +31,16 @@
#include "common.h"
#include "filegen.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_mp3)
extern const file_hint_t file_hint_mkv;
extern const file_hint_t file_hint_tiff;
+#endif
static void register_header_check_mp3(file_stat_t *file_stat);
-static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
-static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
-static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size);
-static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size);
const file_hint_t file_hint_mp3= {
.extension="mp3",
@@ -50,7 +51,6 @@ const file_hint_t file_hint_mp3= {
.register_header_check=&register_header_check_mp3
};
-
#define MPEG_V25 0
#define MPEG_V2 0x2
#define MPEG_V1 0x3
@@ -112,149 +112,167 @@ static const unsigned int bit_rate_table[4][4][16]=
},
};
-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)
+/*@
+ @ 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)
{
- 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;
- 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;
- }
+ 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;
}
-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)
+/*@
+ @ 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)
{
- 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)))
+ 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;
- if(file_recovery->file_stat!=NULL)
+ /*@ assert i + sizeof(mm_header) <= buffer_size; */
+ if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header
{
- if(file_recovery->file_stat->file_hint==&file_hint_mp3 ||
- file_recovery->file_stat->file_hint==&file_hint_mkv)
- {
- header_ignored(file_recovery_new);
+ 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;
- }
- /* 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;
- }
+ /* log_info("search_MMT: image extension present\n"); */
}
- while(potential_frame_offset+1 < buffer_size &&
- potential_frame_offset+1 < 2048)
{
- if(buffer[potential_frame_offset+0]!=0xFF)
+ const unsigned int tmp=i+size;
+ const uint32_t *image_size_ptr;
+ uint32_t image_size;
+ if(tmp+8>buffer_size)
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;
- 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;
- 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==0)
- return 0;
- potential_frame_offset+=frameLengthInBytes;
- nbr++;
- }
+ /*@ 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;
}
- if(nbr>1)
{
-#ifdef DEBUG_MP3
- log_info("header_check_mp3 mp3 found\n");
-#endif
- reset_file_recovery(file_recovery_new);
- file_recovery_new->calculated_file_size=potential_frame_offset;
- file_recovery_new->min_filesize=287;
- file_recovery_new->extension=file_hint_mp3.extension;
- if(file_recovery_new->blocksize >= 16)
+ 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)
{
- file_recovery_new->data_check=&data_check_mp3;
- file_recovery_new->file_check=&file_check_size;
+ /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
+ return 0;
}
- return 1;
}
- return 0;
-}
-
-static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
-{
- 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)
+ size+=4+256; /* padding + version_info */
+ size+=20; /* data offset */
{
- const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
- if(buffer[i]==0)
- { /* Padding is present */
- file_recovery->calculated_file_size++;
+ 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
- { /* no more padding or no padding */
- file_recovery->data_check=&data_check_mp3;
- file_recovery->file_check=&file_check_size;
- return data_check_mp3(buffer, buffer_size, file_recovery);
+ {
+ /* log_trace("search_MMT: no mm_footer present\n"); */
+ return 0;
}
}
- return DC_CONTINUE;
+ {
+ 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 (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_mp3;
+ @ requires file_recovery->file_size == 0 || file_recovery->calculated_file_size >= file_recovery->file_size - 16;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @ ensures file_recovery->data_check==&data_check_mp3;
+ @ 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
@@ -262,10 +280,14 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
(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 - 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,
@@ -279,17 +301,15 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
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;
- const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key];
+ /*@ 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;
- /*
- log_info("frame_offset=%u\n",i);
- log_info("bit_rate=%u\n",bit_rate);
- log_info("sample_rate=%u\n",sample_rate);
- log_info("frameLengthInBytes=%u\n",frameLengthInBytes);
- */
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)
@@ -303,7 +323,9 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
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')
{
@@ -318,16 +340,20 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
The maximum length of the lyrics is 5100 bytes for Lyrics3 and 4096 bytes for Lyrics3 v2.
*/
unsigned int pos_lyrics=0;
- /* FIXME */
- if(file_recovery->calculated_file_size + 5100 >= file_recovery->file_size + buffer_size/2)
- return DC_CONTINUE;
+ 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
{
@@ -339,134 +365,269 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
}
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 unsigned int ape_tag_size = (buffer[i+12] + (buffer[i+13]<<8) + (buffer[i+14]<<16) + (buffer[i+15]<<24))+32;
+ 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;
- }
- else if(file_recovery->calculated_file_size > file_recovery->file_size)
- {
- return DC_CONTINUE;
+ /*@ 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; */
}
}
+ /*@ 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 - 16; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
return DC_CONTINUE;
}
-static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
+/*@
+ @ requires buffer_size >= 32;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_id3;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE && file_recovery->data_check==&data_check_id3 ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1);
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @ ensures file_recovery->data_check==&data_check_id3 || file_recovery->data_check==&data_check_mp3;
+ @*/
+ /*TODO 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)
{
- unsigned int i;
- if(haystack_size < needle_size)
- return 0;
- for(i=0; i <= haystack_size - needle_size; i++)
- if(memcmp(&haystack[i],needle,needle_size)==0)
- return (i+needle_size);
+ /*@
+ @ 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;
+ file_recovery->file_check=&file_check_size;
+ /*@ assert file_recovery->data_check==&data_check_mp3; */
+ if(data_check_mp3(buffer, buffer_size, file_recovery)!=DC_CONTINUE)
+ return DC_STOP;
+ /*@ assert file_recovery->data_check==&data_check_mp3; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
+ return DC_CONTINUE;
+ }
+ }
+ /*@ assert file_recovery->data_check==&data_check_id3; */
+ /*@ 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 - 1; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
+ return DC_CONTINUE;
+}
+
+/*@
+ @ requires buffer_size >= 10;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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;
}
-static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size)
+/*@
+ @ requires buffer_size >= 6;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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;
/*
- 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;
- unsigned int image_size;
- if(i+sizeof(mm_header)>buffer_size)
+ 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;
- 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
+ /*@ assert nbr == 0; */
+ /*@
+ @ loop invariant 0 <= nbr <= potential_frame_offset <= 2048 + 8065;
+ @ loop assigns potential_frame_offset,nbr;
+ @ loop variant 2048 - potential_frame_offset;
+ @*/
+ while(potential_frame_offset+1 < buffer_size &&
+ potential_frame_offset+1 < 2048)
{
- /* Check image extension */
- if( memcmp(&buffer[i+size]," ",4)!=0 &&
- memcmp(&buffer[i+size],"bmp ",4)!=0 &&
- memcmp(&buffer[i+size],"jpg ",4)!=0)
+ if(buffer[potential_frame_offset+0]!=0xFF)
return 0;
- /* log_info("search_MMT: image extension present\n"); */
+ {
+ 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++;
+ }
}
-/* dump_log(&buffer[i+size], buffer_size-(i+size)); */
- /* Image binary */
- image_size = buffer[i+size+4]+(buffer[i+size+5]<<8)+(buffer[i+size+6]<<16)+(buffer[i+size+7]<<24);
- size+=8+image_size;
- /* check null padding + version_info */
- if(i+size+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"); */
+ if(nbr<=1)
return 0;
- }
- if(memcmp(&buffer[i+size], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
+ if(file_recovery->file_stat!=NULL)
{
- /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
- return 0;
- }
- size+=4+256; /* padding + version_info */
- size+=20; /* data offset */
- /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */
- if(i+size+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;
+ if(file_recovery->file_stat->file_hint==&file_hint_mp3
+#if !defined(MAIN_mp3)
+ || file_recovery->file_stat->file_hint==&file_hint_mkv
+#endif
+ )
+ {
+ header_ignored(file_recovery_new);
+ return 0;
+ }
+#if !defined(MAIN_mp3)
+ /* 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
}
- if(memcmp(&buffer[i+size+7868],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+7868],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=7868;
- else if(memcmp(&buffer[i+size+7936],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+7936],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=7936;
- else if(memcmp(&buffer[i+size+8004],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+8004],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=8004;
- else if(memcmp(&buffer[i+size+8132],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+8132],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=8132;
- else
+ /*@ 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)
{
- /* log_trace("search_MMT: no mm_footer present\n"); */
- return 0;
+ file_recovery_new->data_check=&data_check_mp3;
+ file_recovery_new->file_check=&file_check_size;
}
- /* dump_log(&buffer[i+size], 16); */
- if(memcmp(&buffer[i+size],mm_footer,strlen(mm_footer))==0)
- size+=48; /* footer */
- else
- size+=0x80; /* TAG footer */
- /* log_trace("search_MMT: MMT found size=%u (0x%x)\n", size, size); */
- return(size);
+ return 1;
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_mp3(file_stat_t *file_stat)
{
static const unsigned char mpeg1_L3_header1[2]= {0xFF, 0xFA};
@@ -483,3 +644,183 @@ static void register_header_check_mp3(file_stat_t *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);
}
+
+#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/src/file_orf.c b/src/file_orf.c
index bf3f5b1..15531a5 100644
--- a/src/file_orf.c
+++ b/src/file_orf.c
@@ -53,8 +53,8 @@ static int header_check_orf_IIRO(const unsigned char *buffer, const unsigned int
{
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_orf.extension;
- file_recovery_new->time=get_date_from_tiff_header((const TIFFHeader *)buffer, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size);
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
diff --git a/src/file_pdf.c b/src/file_pdf.c
index c62b9bf..1311539 100644
--- a/src/file_pdf.c
+++ b/src/file_pdf.c
@@ -85,7 +85,7 @@ static void file_rename_pdf(file_recovery_t *file_recovery)
#else
offset=ftell(handle);
#endif
- if(offset < 0)
+ if(offset <= 0)
{
fclose(handle);
return;
@@ -250,11 +250,11 @@ static void file_date_pdf(file_recovery_t *file_recovery)
{
if(buffer[0]=='=' && (buffer[1]=='\'' || buffer[1]=='"'))
{
- file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS((const char *)&buffer[2]);
+ 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((const char *)&buffer[1]);
+ file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[1]);
}
}
free(buffer);
diff --git a/src/file_pf.c b/src/file_pf.c
index 8aab2f1..d01b99d 100644
--- a/src/file_pf.c
+++ b/src/file_pf.c
@@ -31,6 +31,9 @@
#include "types.h"
#include "filegen.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_pf(file_stat_t *file_stat);
@@ -54,35 +57,163 @@ struct pf_header
uint32_t unknown2;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_pf;
+ @ ensures valid_read_string((char*)&file_recovery->filename);
+ @*/
static void file_rename_pf(file_recovery_t *file_recovery)
{
FILE *file;
struct pf_header hdr;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
return;
+ }
if(fread(&hdr, sizeof(hdr), 1, file) <= 0)
{
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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_pf, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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=(uint64_t)le32(pf->size);
+ 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;
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
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);
}
+
+#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/src/file_raf.c b/src/file_raf.c
index 7912485..e171c9e 100644
--- a/src/file_raf.c
+++ b/src/file_raf.c
@@ -42,7 +42,7 @@ const file_hint_t file_hint_raf= {
.register_header_check=&register_header_check_raf
};
-/* Documentation source: http://libopenraw.freedesktop.org/wiki/Fuji_RAF/ */
+/* Documentation source: https://libopenraw.pages.freedesktop.org/formats/raf/ */
struct header_raf
{
char magic[16];
@@ -83,16 +83,8 @@ static int header_check_raf(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_raf.extension;
file_recovery_new->calculated_file_size=size;
- if(raf->dir_version[0]=='0' && raf->dir_version[1]=='1')
- {
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- }
- else
- {
- /* The size is bigger than calculated_file_size */
- file_recovery_new->file_check=&file_check_size_min;
- }
+ /* The size is bigger than calculated_file_size */
+ file_recovery_new->file_check=&file_check_size_min;
return 1;
}
diff --git a/src/file_rw2.c b/src/file_rw2.c
index 1310561..639a036 100644
--- a/src/file_rw2.c
+++ b/src/file_rw2.c
@@ -52,8 +52,8 @@ static int header_check_rw2(const unsigned char *buffer, const unsigned int buff
/* Panasonic/Leica */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="rw2";
- file_recovery_new->time=get_date_from_tiff_header(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size);
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
diff --git a/src/file_sdsk.c b/src/file_sdsk.c
new file mode 100644
index 0000000..0d0ec6a
--- /dev/null
+++ b/src/file_sdsk.c
@@ -0,0 +1,66 @@
+/*
+
+ File: file_sdsk.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General 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 <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+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=&register_header_check_sdsk
+};
+
+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);
+}
diff --git a/src/file_sig.c b/src/file_sig.c
index 7908d3c..41207e4 100644
--- a/src/file_sig.c
+++ b/src/file_sig.c
@@ -36,13 +36,15 @@
#endif
#include <stdio.h>
#include <ctype.h>
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
#include "types.h"
#include "filegen.h"
#include "common.h"
#include "log.h"
static void register_header_check_sig(file_stat_t *file_stat);
-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);
const file_hint_t file_hint_sig= {
.extension="custom",
@@ -60,14 +62,45 @@ const file_hint_t file_hint_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;
- signature_t *next;
};
-static signature_t *signatures=NULL;
+static signature_t signatures={
+ .list = TD_LIST_HEAD_INIT(signatures.list)
+};
+
+static 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;
+ }
+}
+
static void signature_insert(const char *extension, unsigned int offset, unsigned char *sig, unsigned int sig_size)
{
/* FIXME: small memory leak */
@@ -76,15 +109,15 @@ static void signature_insert(const char *extension, unsigned int offset, unsigne
newsig->sig=sig;
newsig->sig_size=sig_size;
newsig->offset=offset;
- newsig->next=signatures;
- signatures=newsig;
+ td_list_add_sorted(&newsig->list, &signatures.list, signature_cmp);
}
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)
{
- signature_t *sig;
- for(sig=signatures; sig!=NULL; sig=sig->next)
+ struct td_list_head *pos;
+ td_list_for_each(pos, &signatures.list)
{
+ const signature_t *sig = td_list_entry(pos, signature_t, list);
if(memcmp(&buffer[sig->offset], sig->sig, sig->sig_size)==0)
{
reset_file_recovery(file_recovery_new);
@@ -179,11 +212,11 @@ static char *str_uint(char *src, unsigned int *resptr)
*resptr=res;
return src;
}
-
}
static char *parse_signature_file(file_stat_t *file_stat, char *pos)
{
+ const unsigned int signatures_empty=td_list_empty(&signatures.list);
while(*pos!='\0')
{
/* skip comments */
@@ -371,7 +404,8 @@ static char *parse_signature_file(file_stat_t *file_stat, char *pos)
log_info("register a signature for %s\n", extension);
memcpy(signature, tmp, signature_size);
register_header_check(offset, signature, signature_size, &header_check_sig, file_stat);
- signature_insert(extension, offset, signature, signature_size);
+ if(signatures_empty)
+ signature_insert(extension, offset, signature, signature_size);
}
else
{
@@ -393,12 +427,16 @@ static void register_header_check_sig(file_stat_t *file_stat)
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)
{
@@ -407,6 +445,9 @@ static void register_header_check_sig(file_stat_t *file_stat)
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);
@@ -416,5 +457,3 @@ static void register_header_check_sig(file_stat_t *file_stat)
}
free(buffer);
}
-
-
diff --git a/src/file_skp.c b/src/file_skp.c
index 1b16402..0ffc00b 100644
--- a/src/file_skp.c
+++ b/src/file_skp.c
@@ -35,7 +35,7 @@ static void register_header_check_skp(file_stat_t *file_stat);
const file_hint_t file_hint_skp= {
.extension="skp",
.description="SketchUp",
- .max_filesize=10*1024*1024,
+ .max_filesize=500*1024*1024,
.recover=1,
.enable_by_default=1,
.register_header_check=&register_header_check_skp
diff --git a/src/file_spe.c b/src/file_spe.c
index 9130cf1..0e79aab 100644
--- a/src/file_spe.c
+++ b/src/file_spe.c
@@ -31,9 +31,11 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_spe(file_stat_t *file_stat);
-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);
const file_hint_t file_hint_spe= {
.extension="spe",
@@ -237,30 +239,171 @@ struct header_spe
int16_t lastvalue; /* 4098 Always the LAST value in the header */
} __attribute__ ((gcc_struct, __packed__));
-static const unsigned char spe_header[4]= {0x67, 0x45, 0x23, 0x01};
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_spe, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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_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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @ 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;
+ @*/
+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);
}
-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)
+#if defined(MAIN_spe)
+#define BLOCKSIZE 65536u
+int main()
{
- const struct header_spe *spe=(const struct header_spe*)buffer;
- if(le32(spe->WinView_id)==0x01234567L && le16(spe->lastvalue)==0x5555)
+ 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; */
{
- 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=(uint64_t)le16(spe->xdim)*le16(spe->ydim)*le32(spe->NumFrames);
- file_recovery_new->calculated_file_size*=(le16(spe->datatype)<=1?4:2);
- file_recovery_new->calculated_file_size+=4100;
- 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);
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- return 1;
+ 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/src/file_steuer2014.c b/src/file_steuer2014.c
index e293825..eba0702 100644
--- a/src/file_steuer2014.c
+++ b/src/file_steuer2014.c
@@ -33,10 +33,17 @@
#include "common.h"
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/2015",
+ .description="Steuer 2014/...",
.max_filesize=100*1024*1024,
.recover=1,
.enable_by_default=1,
@@ -59,10 +66,30 @@ static int header_check_steuer(const unsigned char *buffer, const unsigned int b
return 0;
memset(&tm_time, 0, sizeof(struct tm));
reset_file_recovery(file_recovery_new);
- if(le32(h->version1)>=0x13)
- file_recovery_new->extension="steuer2015";
- else
- file_recovery_new->extension=file_hint_steuer2014.extension;
+ 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);
diff --git a/src/file_swf.c b/src/file_swf.c
index 20a1df1..17d743a 100644
--- a/src/file_swf.c
+++ b/src/file_swf.c
@@ -19,10 +19,15 @@
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+
+#if defined(__FRAMAC__) || defined(MAIN_photorec)
+#undef HAVE_ZLIB_H
+#undef HAVE_LIBZ
+#endif
+
#ifdef HAVE_STRING_H
#include <string.h>
#endif
@@ -33,7 +38,11 @@
#endif
#include "filegen.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+static const char *extension_swc="swc";
static void register_header_check_swf(file_stat_t *file_stat);
const file_hint_t file_hint_swf= {
@@ -66,18 +75,36 @@ struct swfz_header
// 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--;
}
@@ -86,6 +113,24 @@ static int read_SB(const unsigned char **data, unsigned int *offset_bit, unsigne
return res;
}
+/*@
+ @ requires buffer_size >= 512;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ 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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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;
@@ -138,8 +183,10 @@ static int header_check_swfc(const unsigned char *buffer, const unsigned int buf
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);
@@ -149,13 +196,31 @@ static int header_check_swfc(const unsigned char *buffer, const unsigned int buf
}
#endif
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="swc";
+ 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 \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ 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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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 */
@@ -189,22 +254,136 @@ static int header_check_swf(const unsigned char *buffer, const unsigned int buff
return 1;
}
+/*@
+ @ requires buffer_size >= sizeof(struct swfz_header);
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_swf, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ 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);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
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;
- if(hdr->version < 11 || le32(hdr->compressedLen) < 6)
+ const unsigned int compressedLen=le32(hdr->compressedLen);
+ /* ZWS file compression is permitted in SWF 13 or later only. */
+ if(hdr->version < 13 || hdr->version > 50 || 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+le32(hdr->compressedLen);
+ 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(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);
}
+
+#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/src/file_tiff.c b/src/file_tiff.c
index 02d0bf7..b30064f 100644
--- a/src/file_tiff.c
+++ b/src/file_tiff.c
@@ -38,18 +38,23 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
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=100*1024*1024,
+ .max_filesize=1024*1024*1024,
.recover=1,
.enable_by_default=1,
.register_header_check=&register_header_check_tiff
};
+/* @ ensures \result == 1 || \result == 2 || \result == 4 || \result == 8;
+ */
unsigned int tiff_type2size(const unsigned int type)
{
switch(type)
@@ -132,72 +137,58 @@ const char *tag_name(unsigned int tag)
}
#endif
-const char *find_tag_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char **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)
{
+ 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(tiff, tiff_size, tag, potential_error);
- else if(tiff->tiff_magic==TIFF_LITTLEENDIAN)
- return find_tag_from_tiff_header_le(tiff, tiff_size, tag, potential_error);
- return NULL;
+ 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 TIFFHeader *tiff, const unsigned int tiff_size)
+time_t get_date_from_tiff_header(const unsigned char *buffer, const unsigned int buffer_size)
{
- const char *potential_error=NULL;
- const char *date_asc;
+ 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(tiff, tiff_size, 0x9003, &potential_error);
+ date_asc=find_tag_from_tiff_header(buffer, buffer_size, 0x9003, &potential_error);
/* DateTimeDigitalized*/
- if(date_asc==NULL || date_asc < (const char *)tiff || &date_asc[18] >= (const char *)tiff + tiff_size)
- date_asc=find_tag_from_tiff_header(tiff, tiff_size, 0x9004, &potential_error);
- if(date_asc==NULL || date_asc < (const char *)tiff || &date_asc[18] >= (const char *)tiff + tiff_size)
- date_asc=find_tag_from_tiff_header(tiff, tiff_size, 0x132, &potential_error);
- if(date_asc==NULL || date_asc < (const char *)tiff || &date_asc[18] >= (const char *)tiff + tiff_size)
+ 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;
- return get_time_from_YYYY_MM_DD_HH_MM_SS(date_asc);
+ 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};
- register_header_check(0, tiff_header_be, sizeof(tiff_header_be), &header_check_tiff_be_new, file_stat);
- register_header_check(0, tiff_header_le, sizeof(tiff_header_le), &header_check_tiff_le_new, file_stat);
-}
-
-void file_check_tiff(file_recovery_t *fr)
-{
- static uint64_t calculated_file_size=0;
- TIFFHeader header;
- calculated_file_size = 0;
- if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
- fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
- {
- fr->file_size=0;
- return;
- }
- if(header.tiff_magic==TIFF_LITTLEENDIAN)
- calculated_file_size=header_check_tiff_le(fr, le32(header.tiff_diroff), 0, 0);
- else if(header.tiff_magic==TIFF_BIGENDIAN)
- calculated_file_size=header_check_tiff_be(fr, be32(header.tiff_diroff), 0, 0);
-#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);
+#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
- if(fr->file_size < calculated_file_size || calculated_file_size==0)
- 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;
}
diff --git a/src/file_tiff.h b/src/file_tiff.h
index ed2f86c..fa9af03 100644
--- a/src/file_tiff.h
+++ b/src/file_tiff.h
@@ -23,6 +23,8 @@
extern "C" {
#endif
+#define TIFF_ERROR 0xffffffffffffffffull
+
#define TIFF_BIGENDIAN 0x4d4d
#define TIFF_LITTLEENDIAN 0x4949
#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */
@@ -66,16 +68,101 @@ struct ifd_header {
TIFFDirEntry ifd;
} __attribute__ ((gcc_struct, __packed__));
-time_t get_date_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size);
-const char *find_tag_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char **potential_error);
-void file_check_tiff(file_recovery_t *file_recovery);
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ ensures \valid_read(buffer+(0..buffer_size-1));
+ @*/
+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)
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires fr->file_check==&file_check_tiff_le;
+ @ ensures \valid(fr->handle);
+ @ ensures valid_read_string(fr->extension);
+ @*/
+void file_check_tiff_le(file_recovery_t *fr);
+
+/*@
+ @ requires buffer_size >= 15;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ 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->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_le);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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)
+/*@
+ @ requires buffer_size >= 15;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ 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->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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
-const char *find_tag_from_tiff_header_be(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error);
-const char *find_tag_from_tiff_header_le(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error);
-uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
-uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
-int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-int header_check_tiff_le_new(const unsigned char *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 tiff_type2size(const unsigned int type);
#ifdef DEBUG_TIFF
const char *tag_name(unsigned int tag);
diff --git a/src/file_tiff_be.c b/src/file_tiff_be.c
index e0b4390..74bc61e 100644
--- a/src/file_tiff_be.c
+++ b/src/file_tiff_be.c
@@ -38,105 +38,214 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if (!defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)) || defined(MAIN_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";
-static const char *find_tag_from_tiff_header_be_aux(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error, const struct ifd_header *hdr)
+#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 TIFFDirEntry *tmp;
+ 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;
- /* Bound checking */
- if((const char*)(hdr) <= (const char*)tiff ||
- (const char*)(hdr+1) > (const char*)tiff+tiff_size)
- return NULL;
+ 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);
- for(i=0, tmp=&hdr->ifd;
- i < nbr_fields && (const char*)(tmp+1) <= (const char*)tiff+tiff_size;
- i++, tmp++)
+ /*@ 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++)
{
- if(be16(tmp->tdir_type) > 18 && (*potential_error==NULL || *potential_error > (const char*)&tmp->tdir_type+1))
+ /*@ 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 char*)&tmp->tdir_type+1;
+ *potential_error = (const unsigned char*)&tmp->tdir_type;
}
if(be16(tmp->tdir_tag)==tag)
- return (const char*)tiff+be32(tmp->tdir_offset);
+ {
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ return be32(tmp->tdir_offset);
+ }
}
- return NULL;
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ return 0;
}
-const char *find_tag_from_tiff_header_be(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**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)
{
- const struct ifd_header *ifd0;
- const struct ifd_header *exififd;
- const uint32_t *tiff_next_diroff;
- if(tiff_size < sizeof(TIFFHeader))
- return NULL;
- if(tiff_size < be32(tiff->tiff_diroff)+sizeof(TIFFDirEntry))
- return NULL;
- ifd0=(const struct ifd_header *)((const char*)tiff + be32(tiff->tiff_diroff));
- /* Bound checking */
- if((const char*)ifd0 < (const char*)tiff ||
- (const char*)(ifd0+1) > (const char*)tiff + tiff_size)
- return NULL;
+ /*@ 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; */
+ /*X assert \valid_read(buffer+(0..offset_ifd0 + sizeof(struct ifd_header)-1)); */
{
- const char *tmp=find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, ifd0);
+ 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;
}
- exififd=(const struct ifd_header *)find_tag_from_tiff_header_be_aux(tiff, tiff_size, TIFFTAG_EXIFIFD, potential_error, ifd0);
- if(exififd!=NULL)
+ 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 char *tmp=find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, exififd);
+ 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;
}
- tiff_next_diroff=(const uint32_t *)(&ifd0->ifd + be16(ifd0->nbr_fields));
- if( (const char *)tiff_next_diroff >= (const char *)tiff &&
- (const char *)(tiff_next_diroff + 1) < (const char*)tiff + tiff_size &&
- be32(*tiff_next_diroff)>0)
{
- /* IFD1 */
- const struct ifd_header *ifd1=(const struct ifd_header*)((const char *)tiff+be32(*tiff_next_diroff));
- return find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ 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);
+ }
}
- return NULL;
+ /*@ 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);
+ @*/
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;
- if(be32(entry_strip_offsets->tdir_count) != be32(entry_strip_bytecounts->tdir_count))
- return -1;
- if(be32(entry_strip_offsets->tdir_count)==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 -1;
+ 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 -1;
+ 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(offsetp);
free(sizep);
- return -1;
+ 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
for(i=0; i<nbr; i++)
{
- const uint64_t tmp=be32(offsetp[i]) + be32(sizep[i]);
+ const uint64_t tmp=(uint64_t)be32(offsetp[i]) + be32(sizep[i]);
if(max_offset < tmp)
max_offset=tmp;
}
@@ -145,6 +254,11 @@ static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_off
return max_offset;
}
+/*@
+ @ requires type != 1 || \valid_read((const char *)val);
+ @ requires type != 3 || \valid_read((const char *)val + ( 0 .. 2));
+ @ requires type != 4 || \valid_read((const char *)val + ( 0 .. 4));
+ @*/
static unsigned int tiff_be_read(const void *val, const unsigned int type)
{
switch(type)
@@ -159,6 +273,7 @@ static unsigned int tiff_be_read(const void *val, const unsigned int type)
return 0;
}
}
+#endif
#ifdef ENABLE_TIFF_MAKERNOTE
static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
@@ -182,12 +297,17 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert data_read >= 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 )
@@ -198,10 +318,10 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
log_info("tiff_be_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n);
#endif
//sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
+ if(n > (unsigned int)(data_read-2)/12)
n=(data_read-2)/12;
if(n==0)
- return -1;
+ return TIFF_ERROR;
for(i=0;i<n;i++)
{
const uint64_t val=(uint64_t)be32(entry->tdir_count) * tiff_type2size(be16(entry->tdir_type));
@@ -220,7 +340,7 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
{
const uint64_t new_offset=be32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -258,13 +378,63 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
return max_offset;
}
#endif
+#endif
-uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg)
+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_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires \separated(&errno, fr);
+ @ 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_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires \separated(&errno, fr);
+ @ 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;
- const uint32_t *tiff_next_diroff;
uint64_t max_offset=0;
uint64_t alphaoffset=0;
uint64_t alphabytecount=0;
@@ -278,38 +448,58 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
uint64_t tile_bytecounts=0;
unsigned int tdir_tag_old=0;
unsigned int sorted_tag_error=0;
- const TIFFDirEntry *entry=(const TIFFDirEntry *)&buffer[2];
+ 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("header_check_tiff_be(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
+ log_info("file_check_tiff_be_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
#endif
if(depth>4)
- return -1;
+ return TIFF_ERROR;
if(count>16)
- return -1;
+ return TIFF_ERROR;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ 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 -1;
+ return TIFF_ERROR;
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
n=(buffer[0]<<8)+buffer[1];
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_be(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+ log_info("file_check_tiff_be_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
#endif
- //sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
- n=(data_read-2)/12;
if(n==0)
- return -1;
- for(i=0;i<n;i++)
+ 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*/
+ 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)be32(entry->tdir_count) * tiff_type2size(be16(entry->tdir_type));
+ 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,
@@ -317,26 +507,29 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
tdir_tag,
tag_name(tdir_tag),
be16(entry->tdir_type),
- (long unsigned)be32(entry->tdir_count),
+ (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 */
- sorted_tag_error++;
- if(sorted_tag_error > 1)
- return -1;
+ 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 -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
- if(be32(entry->tdir_count)==1 && val<=4)
+ if(tdir_count==1 && val<=4)
{
const unsigned int tmp=tiff_be_read(&entry->tdir_offset, be16(entry->tdir_type));
switch(tdir_tag)
@@ -354,18 +547,34 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ /*@ assert \valid(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:
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ /*@ assert \valid(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;
}
@@ -374,8 +583,8 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_be_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -383,8 +592,9 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
#endif
}
}
- else if(be32(entry->tdir_count) > 1)
+ else if(tdir_count > 1)
{
+ /*@ assert tdir_count > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -392,31 +602,43 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_SUBIFD:
if(be16(entry->tdir_type)==4)
{
- const unsigned int nbr=(be32(entry->tdir_count)<32?be32(entry->tdir_count):32);
+ const unsigned int nbr=(tdir_count<32?tdir_count:32);
+ /*@ assert 2 <= nbr <= 32; */
+ uint32_t subifd_offsetp[32];
unsigned int j;
- uint32_t *subifd_offsetp;
if(fseek(fr->handle, be32(entry->tdir_offset), SEEK_SET) < 0)
{
- return -1;
+ return TIFF_ERROR;
}
- subifd_offsetp=(uint32_t *)MALLOC(nbr*sizeof(*subifd_offsetp));
- if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, fr->handle) != nbr)
+ if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp));
+#endif
+ /*X
+ X loop invariant 0 <= j <= nbr <=32;
+ X loop variant nbr-j;
+ X*/
for(j=0; j<nbr; j++)
{
- const uint64_t new_offset=header_check_tiff_be(fr, be32(subifd_offsetp[j]), depth+1, 0);
- if(new_offset==-1)
+ /*@ assert \valid(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, 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)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
if(max_offset < new_offset)
max_offset = new_offset;
}
- free(subifd_offsetp);
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -434,7 +656,6 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
}
tdir_tag_old=tdir_tag;
- entry++;
}
if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount)
max_offset = alphaoffset + alphabytecount;
@@ -451,64 +672,201 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
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==-1)
- return -1;
+ 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==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(be32(*tiff_next_diroff) > 0)
{
- const uint64_t new_offset=header_check_tiff_be(fr, be32(*tiff_next_diroff), depth+1, count+1);
- if(new_offset != -1 && max_offset < new_offset)
+ 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;
}
-int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires fr->file_check==&file_check_tiff_be;
+ @*/
+static void file_check_tiff_be(file_recovery_t *fr)
{
- const char *potential_error=NULL;
+ static uint64_t calculated_file_size=0;
+ TIFFHeader header;
+ calculated_file_size = 0;
+ if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
+ fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
+ {
+ fr->file_size=0;
+ return;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 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;
+}
+#endif
+
+#if !defined(MAIN_tiff_le) && !defined(MAIN_jpg)
+/*@
+ @ 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(MAIN_tiff_be) && !defined(MAIN_tiff_le)) || defined(MAIN_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="tif";
- if(find_tag_from_tiff_header_be(header, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=NULL)
+ 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="dng";
+ file_recovery_new->extension=extension_dng;
}
else
{
- const char *tag_make;
- tag_make=find_tag_from_tiff_header_be(header, buffer_size, TIFFTAG_MAKE, &potential_error);
- if(tag_make!=NULL && tag_make >= (const char *)buffer && tag_make < (const char *)buffer + buffer_size - 20)
+ 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(tag_make, "PENTAX Corporation ", 20)==0 ||
- memcmp(tag_make, "PENTAX ", 20)==0)
- file_recovery_new->extension="pef";
- else if(memcmp(tag_make, "NIKON CORPORATION", 18)==0)
- file_recovery_new->extension="nef";
- else if(memcmp(tag_make, "Kodak", 6)==0)
- file_recovery_new->extension="dcr";
+ 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(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size);
+ file_recovery_new->file_check=&file_check_tiff_be;
return 1;
}
+#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/src/file_tiff_le.c b/src/file_tiff_le.c
index 2a4aa92..196e4c3 100644
--- a/src/file_tiff_le.c
+++ b/src/file_tiff_le.c
@@ -38,106 +38,216 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le) && !defined(MAIN_jpg)
extern const file_hint_t file_hint_raf;
+#endif
+#if (!defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)) || defined(MAIN_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";
-static const char *find_tag_from_tiff_header_le_aux(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error, const struct ifd_header *hdr)
+#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 TIFFDirEntry *tmp;
+ const unsigned char *ptr_hdr;
+ const struct ifd_header *hdr;
unsigned int i;
unsigned int nbr_fields;
- /* Bound checking */
- if((const char*)(hdr) <= (const char*)tiff ||
- (const char*)(hdr+1) > (const char*)tiff+tiff_size)
- return NULL;
+ 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);
- for(i=0, tmp=&hdr->ifd;
- i < nbr_fields && (const char*)(tmp+1) <= (const char*)tiff+tiff_size;
- i++, tmp++)
+ /*@ 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++)
{
- if(le16(tmp->tdir_type) > 18 && (*potential_error==NULL || *potential_error > (const char*)&tmp->tdir_type+1))
+ /*@ 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 char*)&tmp->tdir_type+1;
+ *potential_error = (const unsigned char*)&tmp->tdir_type;
}
if(le16(tmp->tdir_tag)==tag)
- return (const char*)tiff+le32(tmp->tdir_offset);
+ {
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ return le32(tmp->tdir_offset);
+ }
}
- return NULL;
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ return 0;
}
-const char *find_tag_from_tiff_header_le(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**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)
{
- const struct ifd_header *ifd0;
- const struct ifd_header *exififd;
- const uint32_t *tiff_next_diroff;
- if(tiff_size < sizeof(TIFFHeader))
- return NULL;
- if(tiff_size < le32(tiff->tiff_diroff)+sizeof(TIFFDirEntry))
- return NULL;
- ifd0=(const struct ifd_header *)((const char*)tiff + le32(tiff->tiff_diroff));
- /* Bound checking */
- if((const char*)ifd0 < (const char*)tiff ||
- (const char*)(ifd0+1) > (const char*)tiff + tiff_size)
- return NULL;
+ /*@ 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 char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd0);
+ 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;
}
- exififd=(const struct ifd_header *)find_tag_from_tiff_header_le_aux(tiff, tiff_size, TIFFTAG_EXIFIFD, potential_error, ifd0);
- if(exififd!=NULL)
+ 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 char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, exififd);
+ 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;
}
- tiff_next_diroff=(const uint32_t *)(&ifd0->ifd + le16(ifd0->nbr_fields));
- if( (const char *)tiff_next_diroff >= (const char *)tiff &&
- (const char *)(tiff_next_diroff + 1) < (const char*)tiff + tiff_size &&
- le32(*tiff_next_diroff)>0)
{
- /* IFD1 */
- const struct ifd_header *ifd1=(const struct ifd_header*)((const char *)tiff+le32(*tiff_next_diroff));
- return find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ 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);
+ 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);
+ }
}
- return NULL;
+ /*@ 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);
+ @*/
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;
- if(le32(entry_strip_offsets->tdir_count) != le32(entry_strip_bytecounts->tdir_count))
- return -1;
- if(le32(entry_strip_offsets->tdir_count)==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 -1;
+ 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 -1;
+ 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(offsetp);
free(sizep);
- return -1;
+ 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
for(i=0; i<nbr; i++)
{
- const uint64_t tmp=le32(offsetp[i]) + le32(sizep[i]);
+ const uint64_t tmp=(uint64_t)le32(offsetp[i]) + le32(sizep[i]);
if(max_offset < tmp)
max_offset=tmp;
}
@@ -146,6 +256,11 @@ static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_off
return max_offset;
}
+/*@
+ @ requires type != 1 || \valid_read((const char *)val);
+ @ requires type != 3 || \valid_read((const char *)val + ( 0 .. 2));
+ @ requires type != 4 || \valid_read((const char *)val + ( 0 .. 4));
+ @*/
static unsigned int tiff_le_read(const void *val, const unsigned int type)
{
switch(type)
@@ -160,6 +275,7 @@ static unsigned int tiff_le_read(const void *val, const unsigned int type)
return 0;
}
}
+#endif
#ifdef ENABLE_TIFF_MAKERNOTE
static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
@@ -183,12 +299,17 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert data_read >= 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 )
@@ -199,10 +320,10 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
log_info("tiff_le_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n);
#endif
//sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
+ if(n > (unsigned int)(data_read-2)/12)
n=(data_read-2)/12;
if(n==0)
- return -1;
+ return TIFF_ERROR;
for(i=0;i<n;i++)
{
const uint64_t val=(uint64_t)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type));
@@ -221,7 +342,7 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
{
const uint64_t new_offset=le32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -259,13 +380,63 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
return max_offset;
}
#endif
+#endif
+
+#if !defined(MAIN_tiff_be) && !defined(MAIN_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_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires \separated(&errno, fr);
+ @ 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);
+ }
+}
-uint64_t header_check_tiff_le(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_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @ requires \separated(&errno, fr);
+ @ 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;
- const uint32_t *tiff_next_diroff;
uint64_t max_offset=0;
uint64_t alphaoffset=0;
uint64_t alphabytecount=0;
@@ -279,38 +450,58 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
uint64_t tile_bytecounts=0;
unsigned int tdir_tag_old=0;
unsigned int sorted_tag_error=0;
- const TIFFDirEntry *entry=(const TIFFDirEntry *)&buffer[2];
+ 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("header_check_tiff_le(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
+ log_info("file_check_tiff_le_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
#endif
if(depth>4)
- return -1;
+ return TIFF_ERROR;
if(count>16)
- return -1;
+ return TIFF_ERROR;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ 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 -1;
- n=buffer[0]+(buffer[1]<<8);
+ return TIFF_ERROR;
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
+ n=buffer[0] | (buffer[1]<<8);
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_le(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+ log_info("file_check_tiff_le_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
#endif
- //sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
- n=(data_read-2)/12;
if(n==0)
- return -1;
- for(i=0;i<n;i++)
+ 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*/
+ 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)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type));
+ 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,
@@ -318,26 +509,30 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
tdir_tag,
tag_name(tdir_tag),
le16(entry->tdir_type),
- (long unsigned)le32(entry->tdir_count),
+ (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 file doesn't respected this rule */
- sorted_tag_error++;
- if(sorted_tag_error > 1 && strcmp(fr->extension,"sr2")!=0)
- return -1;
+ { /* 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 -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
- if(le32(entry->tdir_count)==1 && val<=4)
+ if(tdir_count==1 && val<=4)
{
const unsigned int tmp=tiff_le_read(&entry->tdir_offset, le16(entry->tdir_type));
switch(tdir_tag)
@@ -355,15 +550,23 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ /*@ assert \valid(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!=NULL && strcmp(fr->extension, "arw")==0)
+ if(fr->extension == extension_arw)
{
/* DSLR-A100 is boggus, may be A100DataOffset */
if(max_offset < tmp)
@@ -371,9 +574,17 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
else
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ /*@ assert \valid(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;
}
@@ -382,8 +593,8 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_le_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -391,8 +602,9 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
#endif
}
}
- else if(le32(entry->tdir_count) > 1)
+ else if(tdir_count > 1)
{
+ /*@ assert tdir_count > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -400,31 +612,43 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_SUBIFD:
if(le16(entry->tdir_type)==4)
{
- const unsigned int nbr=(le32(entry->tdir_count)<32?le32(entry->tdir_count):32);
+ const unsigned int nbr=(tdir_count<32?tdir_count:32);
+ /*@ assert 2 <= nbr <= 32; */
+ uint32_t subifd_offsetp[32];
unsigned int j;
- uint32_t *subifd_offsetp;
if(fseek(fr->handle, le32(entry->tdir_offset), SEEK_SET) < 0)
{
- return -1;
+ return TIFF_ERROR;
}
- subifd_offsetp=(uint32_t *)MALLOC(nbr*sizeof(*subifd_offsetp));
- if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, fr->handle) != nbr)
+ if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp));
+#endif
+ /*X
+ X loop invariant 0 <= j <= nbr <=32;
+ X loop variant nbr-j;
+ X*/
for(j=0; j<nbr; j++)
{
- const uint64_t new_offset=header_check_tiff_le(fr, le32(subifd_offsetp[j]), depth+1, 0);
- if(new_offset==-1)
+ /*@ assert \valid(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, 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)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
if(max_offset < new_offset)
max_offset = new_offset;
}
- free(subifd_offsetp);
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -442,7 +666,6 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
}
tdir_tag_old=tdir_tag;
- entry++;
}
if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount)
max_offset = alphaoffset + alphabytecount;
@@ -459,78 +682,211 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
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==-1)
- return -1;
+ 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==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(le32(*tiff_next_diroff) > 0)
{
- const uint64_t new_offset=header_check_tiff_le(fr, le32(*tiff_next_diroff), depth+1, count+1);
- if(new_offset != -1 && max_offset < new_offset)
+ 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;
}
-int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+void file_check_tiff_le(file_recovery_t *fr)
+{
+ static uint64_t calculated_file_size=0;
+ TIFFHeader header;
+ calculated_file_size = 0;
+ if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
+ fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
+ {
+ fr->file_size=0;
+ return;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 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)
+/*@
+ @ 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 char raf_fp[15]={0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x00, 0x01};
- const char *potential_error=NULL;
+ 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 &&
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le) && !defined(MAIN_jpg)
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(MAIN_tiff_be) && !defined(MAIN_tiff_le)) || defined(MAIN_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="tif";
+ file_recovery_new->extension=file_hint_tiff.extension;
/* Canon RAW */
if(buffer[8]=='C' && buffer[9]=='R' && buffer[10]==2)
- file_recovery_new->extension="cr2";
- else if(find_tag_from_tiff_header_le(header, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=NULL)
+ 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="dng";
+ file_recovery_new->extension=extension_dng;
}
else
{
- const char *tag_make;
- tag_make=find_tag_from_tiff_header_le(header, buffer_size, TIFFTAG_MAKE, &potential_error);
- if(tag_make!=NULL && tag_make >= (const char *)buffer && tag_make < (const char *)buffer + buffer_size - 5)
+ 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(tag_make, "SONY", 5)==0)
- file_recovery_new->extension="sr2";
- else if(strncmp(tag_make, "SONY ",5)==0)
- file_recovery_new->extension="arw";
- else if(memcmp(tag_make, "NIKON CORPORATION", 18)==0)
- file_recovery_new->extension="nef";
+ 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(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->time=get_date_from_tiff_header(buffer, buffer_size);
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
+#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/src/file_txt.c b/src/file_txt.c
index f1e7336..52484d8 100644
--- a/src/file_txt.c
+++ b/src/file_txt.c
@@ -33,6 +33,7 @@
#include <time.h>
#endif
#include <ctype.h> /* tolower */
+#include <assert.h>
#include <stdio.h>
#include "types.h"
#include "common.h"
@@ -40,41 +41,109 @@
#include "log.h"
#include "memmem.h"
#include "file_txt.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_txt)
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
-static inline int filtre(unsigned int car);
+typedef struct
+{
+ const char *string;
+ const unsigned int len;
+ const char *extension;
+} txt_header_t;
-static void register_header_check_txt(file_stat_t *file_stat);
-static int header_check_txt(const unsigned char *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 void register_header_check_fasttxt(file_stat_t *file_stat);
static void register_header_check_snz(file_stat_t *file_stat);
-static int header_check_fasttxt(const unsigned char *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 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_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_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 int header_check_le16_txt(const unsigned char *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 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_snz= {
- .extension="snz",
- .description="Olfaction SeeNez odorama",
+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=&register_header_check_snz
+ .register_header_check=&register_header_check_fasttxt
};
-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",
+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=&register_header_check_fasttxt
+ .register_header_check=&register_header_check_snz
};
const file_hint_t file_hint_txt= {
@@ -88,28 +157,6 @@ const file_hint_t file_hint_txt= {
static unsigned char ascii_char[256];
-static void register_header_check_txt(file_stat_t *file_stat)
-{
- unsigned int i;
- for(i=0; i<256; i++)
- ascii_char[i]=i;
- for(i=0; i<256; i++)
- {
- if(filtre(i) || i==0xE2 || i==0xC2 || i==0xC3 || i==0xC5 || i==0xC6 || i==0xCB)
- register_header_check(0, &ascii_char[i], 1, &header_check_txt, file_stat);
- }
-#ifdef UTF16
- register_header_check(1, &ascii_char[0], 1, &header_check_le16_txt, file_stat);
-#endif
-}
-
-typedef struct
-{
- const char *string;
- const unsigned int len;
- const char *extension;
-} txt_header_t;
-
static const txt_header_t fasttxt_headers[] = {
/* Unix shell */
{ "#!/bin/bash", 11, "sh"},
@@ -118,6 +165,11 @@ static const txt_header_t fasttxt_headers[] = {
{ "#! /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 */
@@ -166,6 +218,7 @@ static const txt_header_t fasttxt_headers[] = {
{ "-- phpMyAdmin SQL Dump", 22, "sql"},
{ "--\n-- PostgreSQL database cluster dump", 38, "sql"},
{ "--\r\n-- PostgreSQL database cluster dump", 39, "sql"},
+ { "# ************************************************************\n# Sequel Pro SQL dump", 84, "sql"},
{ "---- BEGIN SSH2 PUBLIC KEY ----", 31, "ppk"},
{ "PuTTY-User-Key-File-2:", 22, "ppk"},
{ "-----BEGIN PGP PRIVATE KEY BLOCK-----", 37, "priv"},
@@ -221,6 +274,9 @@ static const txt_header_t fasttxt_headers[] = {
// #define DEBUG_FILETXT
/* return 1 if char can be found in text file */
+/*@
+ @ assigns \nothing;
+ @*/
static int filtre(unsigned int car)
{
switch(car)
@@ -281,16 +337,192 @@ static int filtre(unsigned int car)
return 0;
}
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
+static int has_newline(const char *buffer, const unsigned int buffer_size)
+{
+ unsigned int i;
+ /*@
+ @ loop invariant 0 <= i <= 512;
+ @ loop assigns i;
+ @ loop variant 512-i;
+ @*/
+ for(i=0; i<512 && i < buffer_size && buffer[i]!='\0'; i++)
+ {
+ if(buffer[i]=='\n')
+ return 1;
+ }
+ /* A text file must contains several lines */
+ return 0;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
+static unsigned int is_csv(const char *buffer, const unsigned int buffer_size)
+{
+ unsigned int csv_per_line_current=0;
+ unsigned int csv_per_line=0;
+ unsigned int line_nbr=0;
+ unsigned int i;
+ /*@
+ @ loop invariant 0 <= i <= buffer_size;
+ @ loop invariant csv_per_line_current <= i+1;
+ @ loop invariant line_nbr <= i+1;
+ @ loop assigns i, csv_per_line_current, csv_per_line, line_nbr;
+ @ loop variant buffer_size-i;
+ @*/
+ for(i=0; i<buffer_size; i++)
+ {
+ if(buffer[i]==';')
+ {
+ csv_per_line_current++;
+ }
+ else if(buffer[i]=='\n')
+ {
+ if(line_nbr==0)
+ {
+ if(csv_per_line_current==0)
+ return 0;
+ csv_per_line=csv_per_line_current;
+ }
+ if(csv_per_line_current!=csv_per_line)
+ return 0;
+ line_nbr++;
+ csv_per_line_current=0;
+ }
+ }
+ if(line_nbr<10)
+ return 0;
+ return 1;
+}
+
+/*@
+ @ requires valid_read_string(buffer);
+ @ assigns \nothing;
+ @*/
+static unsigned int is_fortran(const char *buffer)
+{
+ const char *str=buffer;
+ unsigned int i=0;
+ /* Detect Fortran */
+ /*@ assert valid_read_string(str); */
+ /*@
+ @ loop invariant 0 <= i <= 10;
+ @ loop assigns str,i;
+ @ loop variant 10 - i;
+ @*/
+ for(i=0; i<10; i++)
+ {
+ str=strstr(str, "\n ");
+ if(str==NULL)
+ return 0;
+ /*@ assert valid_read_string(str); */
+#ifdef __FRAMAC__
+ if(*str=='\0')
+ return 0;
+#endif
+ str++;
+ /*@ assert valid_read_string(str); */
+ }
+ if(i < 10)
+ return 0;
+ if(strstr(buffer, "integer")==NULL)
+ return 0;
+ return 1;
+}
+
+/*@
+ @ requires valid_read_string((char *)buffer);
+ @ assigns \nothing;
+ @*/
+static int is_ini(const unsigned char *buffer)
+{
+ const unsigned char *src=buffer;
+ if(*src!='[')
+ return 0;
+ src++;
+ /*@
+ @ loop assigns src;
+ @*/
+ while(*src!='\0')
+ {
+ if(*src==']')
+ {
+ if(src > buffer + 3)
+ return 1;
+ return 0;
+ }
+ if(!isalnum(*src) && *src!=' ')
+ return 0;
+ src++;
+ }
+ return 0;
+}
+
+/*@
+ @ requires buffer_size >= 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @*/
+static double is_random(const unsigned char *buffer, const unsigned int buffer_size)
+{
+ unsigned int stats[256];
+ unsigned int i;
+ double ind;
+ if(buffer_size < 2)
+ return 1;
+ memset(&stats, 0, sizeof(stats));
+ /*@ assert \forall int j; (0 <= j <= 255) ==> (stats[j] == 0); */
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= i <= buffer_size;
+ @ loop invariant \forall integer j; (0 <= j <= 255) ==> (stats[j] <= i+1);
+ @ loop assigns i, stats[0..255];
+ @ loop variant buffer_size-i;
+ @*/
+ for(i=0; i<buffer_size; i++)
+ stats[buffer[i]]++;
+ ind=0;
+ /*@
+ @ loop invariant 0 <= i <= 256;
+ @ loop assigns ind;
+ @ loop variant 256-i;
+ @*/
+ for(i=0; i<256; i++)
+ if(stats[i]>0)
+ ind+=stats[i]*(stats[i]-1);
+#else
+ ind=Frama_C_interval(0, buffer_size*(buffer_size-1));
+#endif
+return ind/buffer_size/(buffer_size-1);
+}
+
/* destination should have an extra byte available for null terminator
- return read size */
-int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int buf_len)
+ return written size */
+/*@
+ @ requires buf_len > 0;
+ @ requires \valid(buffer_lower + (0..buf_len-1));
+ @ requires \valid_read(buffer + (0..buf_len-1));
+ @ ensures \result <= buf_len;
+ @*/
+static int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int buf_len)
{
const unsigned char *p; /* pointers to actual position in source buffer */
unsigned char *q; /* pointers to actual position in destination buffer */
- int i; /* counter of remaining bytes available in destination buffer */
- for (i = buf_len, p = buffer, q = buffer_lower; p-buffer<buf_len && i > 0 && *p!='\0';)
+ unsigned int offset_dst;
+ /* destination will be null terminated */
+ /*@
+ @ loop invariant offset_dst < buf_len;
+ @ loop invariant q == buffer_lower + offset_dst;
+ @ loop variant buf_len - 1 - offset_dst;
+ @*/
+ for (offset_dst = 0, p = buffer, q = buffer_lower;
+ p+2-buffer<buf_len && offset_dst < buf_len-1 && *p!='\0';)
{
- const unsigned char *p_org=p;
if((*p & 0xf0)==0xe0 && (*(p+1) & 0xc0)==0x80 && (*(p+2) & 0xc0)==0x80)
{ /* UTF8 l=3 */
#ifdef DEBUG_TXT
@@ -384,12 +616,17 @@ int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int
}
p+=2;
}
+ else if( 'A' <= *p && *p <='Z')
+ {
+ *q = *p-'A'+'a';
+ p++;
+ }
else
{ /* Ascii UCS */
#ifdef DEBUG_TXT
log_info("UTF8 Ascii UCS 0x%02x\n", *p);
#endif
- *q = tolower(*p);
+ *q = *p;
p++;
}
if (*q=='\0' || filtre(*q)==0)
@@ -398,19 +635,25 @@ int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int
log_warning("UTF2Lat reject 0x%x\n",*q);
#endif
*q = '\0';
- return(p_org-buffer);
+ return offset_dst;
}
q++;
- i--;
+ offset_dst++;
}
*q = '\0';
- return(p-buffer);
+ return offset_dst;
}
-static int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
+int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
{
const unsigned char *p=buffer; /* pointers to actual position in source buffer */
unsigned int i=0;
+ /*@
+ @ loop invariant 0 <= i < buf_len + 3;
+ @ loop invariant p == buffer + i;
+ @ loop assigns i, p;
+ @ loop variant buf_len - 1 - i;
+ @*/
while(i<buf_len && *p!='\0')
{
/* Reject some invalid UTF-8 sequences */
@@ -475,47 +718,68 @@ static int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
return (i<buf_len?i:buf_len);
}
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_html;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
static data_check_t data_check_html(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
const char sign_html_end[] = "</html>";
- const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
- unsigned int j;
- for(j=(buffer_size/2>sizeof(sign_html_end)?buffer_size/2-sizeof(sign_html_end):0);
- j+sizeof(sign_html_end)-1 < buffer_size;
- j++)
+ if(buffer_size/2 > (sizeof(sign_html_end)-1))
{
- if(buffer[j]=='<' && strncasecmp((const char *)&buffer[j], sign_html_end, sizeof(sign_html_end)-1)==0)
+ unsigned int j;
+ /*@
+ @ loop assigns j, file_recovery->calculated_file_size;
+ @*/
+ for(j=buffer_size/2-(sizeof(sign_html_end)-1);
+ j+sizeof(sign_html_end)-1 < buffer_size;
+ j++)
{
- file_recovery->calculated_file_size+=j-buffer_size/2+sizeof(sign_html_end)-1;
- return DC_STOP;
+ if(buffer[j]=='<' && strncasecmp((const char *)&buffer[j], sign_html_end, sizeof(sign_html_end)-1)==0)
+ {
+ j+=sizeof(sign_html_end)-1;
+ /*@ assert j >= buffer_size/2; */
+ /*@ loop assigns j; */
+ while(j < buffer_size && (buffer[j]=='\n' || buffer[j]=='\r'))
+ j++;
+ file_recovery->calculated_file_size+=j-buffer_size/2;
+ return DC_STOP;
+ }
}
}
- if(i<buffer_size/2)
- {
- if(i>=10)
- file_recovery->calculated_file_size=file_recovery->file_size+i;
- return DC_STOP;
- }
- file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
- return DC_CONTINUE;
-}
-
-static data_check_t data_check_txt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
-{
- const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
- if(i<buffer_size/2)
{
- if(i>=10)
- file_recovery->calculated_file_size=file_recovery->file_size+i;
- return DC_STOP;
+ const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
+ if(i<buffer_size/2)
+ {
+ if(i>=10)
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
+ }
}
file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_ttd;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
static data_check_t data_check_ttd(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
unsigned int i;
+ /*@
+ @ loop invariant buffer_size/2 <= i <= buffer_size;
+ @ loop assigns i, file_recovery->calculated_file_size;
+ @ loop variant buffer_size - i;
+ @*/
for(i=buffer_size/2; i<buffer_size; i++)
{
const unsigned char car=buffer[i];
@@ -528,159 +792,139 @@ static data_check_t data_check_ttd(const unsigned char *buffer, const unsigned i
return DC_CONTINUE;
}
-static int header_check_ttd(const unsigned char *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[56]<'0' || buffer[56]>'9')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_ttd;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="ttd";
- return 1;
-}
-
-static void file_check_ers(file_recovery_t *file_recovery)
-{
- file_search_footer(file_recovery, "DatasetHeader End", 17, 0);
- file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
-}
-
-static int header_check_ers(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- /* ER Mapper Rasters (ERS) */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_ers;
- file_recovery_new->extension="ers";
- return 1;
-}
-
-static int header_check_ics(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_txt;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
+static data_check_t data_check_txt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- const char *date_asc;
- char *buffer2;
- if(buffer[15]=='\0')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- /* vcalendar */
- file_recovery_new->extension="ics";
- /* DTSTART:19970714T133000 ;Local time
- * DTSTART:19970714T173000Z ;UTC time
- * DTSTART;TZID=US-Eastern:19970714T133000 ;Local time and time
- */
- buffer2=(char *)MALLOC(buffer_size+1);
- buffer2[buffer_size]='\0';
- memcpy(buffer2, buffer, buffer_size);
- date_asc=strstr(buffer2, "DTSTART");
- if(date_asc!=NULL)
- date_asc=strchr(date_asc, ':');
- if(date_asc!=NULL && date_asc+1+14 < buffer2+buffer_size)
+ const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
+ if(i<buffer_size/2)
{
- file_recovery_new->time=get_time_from_YYYYMMDD_HHMMSS(date_asc+1);
+ if(i>=10)
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
}
- free(buffer2);
- return 1;
+ file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
+ return DC_CONTINUE;
}
-static int header_check_perlm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size >= 10 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_xml_utf8;
+ @ assigns file_recovery->calculated_file_size,file_recovery->data_check;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->data_check==&data_check_txt);
+ @*/
+static data_check_t data_check_xml_utf8(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
unsigned int i;
- const unsigned int buffer_size_test=(buffer_size < 2048 ? buffer_size : 2048);
- for(i=0; i<128 && buffer[i]!=';' && buffer[i]!='\n'; i++);
- if(buffer[i]!=';')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- if( td_memmem(buffer, buffer_size_test, "class", 5)!=NULL ||
- td_memmem(buffer, buffer_size_test, "private static", 14)!=NULL ||
- td_memmem(buffer, buffer_size_test, "public interface", 16)!=NULL)
- {
- /* source code in java */
-#ifdef DJGPP
- file_recovery_new->extension="jav";
-#else
- file_recovery_new->extension="java";
-#endif
- }
- else
+ if(buffer_size<=8)
+ return DC_CONTINUE;
+ i=UTFsize(&buffer[buffer_size/2+4], buffer_size/2-4)+4;
+ if(i<buffer_size/2)
{
- /* perl module */
- file_recovery_new->extension="pm";
- }
- return 1;
-}
-
-static int header_check_dc(const unsigned char *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]=='0')
- { /*
- TSCe Survey Controller DC v10.0
- */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="dc";
- return 1;
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
}
- return 0;
+ file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
+ file_recovery->data_check=&data_check_txt;
+ return DC_CONTINUE;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_fods;
+ @ ensures valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_fods(file_recovery_t *file_recovery)
{
+ const char *meta_title="<office:meta><dc:title>";
FILE *file;
char buffer[4096];
- char *tmp;
+ char *tmp=NULL;
size_t lu;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
+ }
if((lu=fread(&buffer, 1, sizeof(buffer)-1, file)) <= 0)
{
fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
+ fclose(file);
buffer[lu]='\0';
- tmp=strchr(buffer,'<');
- while(tmp!=NULL)
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant tmp==\null || valid_read_string(tmp);
+ @ loop assigns tmp;
+ @*/
+ for(tmp=strchr(buffer,'<');
+ tmp!=NULL && strncasecmp(tmp, meta_title, 23)!=0;
+ tmp=strchr(tmp,'<'))
{
- if(strncasecmp(tmp, "<office:meta><dc:title>", 23)==0)
- {
- const char *title=tmp+23;
- tmp=strchr(title,'<');
- if(tmp!=NULL)
- *tmp='\0';
- file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
- fclose(file);
- return ;
- }
+ /* TODO assert tmp[0]=='<'; */
+ /*@ assert valid_read_string(tmp); */
tmp++;
- tmp=strchr(tmp,'<');
+ /*@ assert valid_read_string(tmp); */
}
- fclose(file);
+ if(tmp!=NULL)
+ {
+ const char *title=tmp+23;
+ /*@ assert valid_read_string(title); */
+ tmp=strchr(title,'<');
+ if(tmp!=NULL)
+ *tmp='\0';
+ file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
+ }
+#endif
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_html;
+ @ ensures valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_html(file_recovery_t *file_recovery)
{
FILE *file;
char buffer[4096];
char *tmp;
size_t lu;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
+ }
if((lu=fread(&buffer, 1, sizeof(buffer)-1, file)) <= 0)
{
fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
+ fclose(file);
buffer[lu]='\0';
+#ifndef __FRAMAC__
tmp=strchr(buffer,'<');
while(tmp!=NULL)
{
if(strncasecmp(tmp, "</head", 5)==0)
{
- fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
if(strncasecmp(tmp, "<title>", 7)==0)
@@ -690,273 +934,381 @@ static void file_rename_html(file_recovery_t *file_recovery)
if(tmp!=NULL)
*tmp='\0';
file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
- fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
tmp++;
tmp=strchr(tmp,'<');
}
- fclose(file);
-}
-
-static int header_check_html(const unsigned char *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_fasttxt &&
- strcmp(file_recovery->extension,"mbox")==0)
- return 0;
- if(buffer[14]==0)
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_html;
- file_recovery_new->file_check=&file_check_size;
- /* Hypertext Markup Language (HTML) */
-#ifdef DJGPP
- file_recovery_new->extension="htm";
-#else
- file_recovery_new->extension="html";
#endif
- file_recovery_new->file_rename=&file_rename_html;
- return 1;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
}
-static void file_check_vbm(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_emlx;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_emlx(file_recovery_t *file_recovery)
{
- file_search_footer(file_recovery, "</BackupMeta>", 13, 0);
- file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
+ 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+2048)
+ file_recovery->file_size=file_recovery->calculated_file_size+2048;
+ file_search_footer(file_recovery, "</plist>\n", 9, 0);
+ }
}
-static int header_check_vbm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_ers;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_ers(file_recovery_t *file_recovery)
{
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->extension="vbm";
- file_recovery_new->file_check=&file_check_vbm;
- return 1;
+ file_search_footer(file_recovery, "DatasetHeader End", 17, 0);
+ file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_gpx;
+ @ ensures \valid(file_recovery->handle);
+ @*/
static void file_check_gpx(file_recovery_t *file_recovery)
{
file_search_footer(file_recovery, "</gpx>", 6, 0);
file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static void file_check_xml(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_svg;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_svg(file_recovery_t *file_recovery)
{
- file_search_footer(file_recovery, ">", 1, 0);
+ file_search_footer(file_recovery, "</svg>", 6, 0);
file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static void file_check_svg(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_smil;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_smil(file_recovery_t *file_recovery)