summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INFO2
-rw-r--r--Makefile.am51
-rw-r--r--NEWS66
-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.spec2
-rw-r--r--linux/testdisk.spec.in15
-rw-r--r--sonar-project.properties2
-rw-r--r--src/Makefile.am3
-rw-r--r--src/askloc.c12
-rw-r--r--src/common.c12
-rw-r--r--src/common.h13
-rw-r--r--src/exfatp.c1
-rw-r--r--src/ext2p.c1
-rw-r--r--src/fatp.c1
-rw-r--r--src/fidentify.c36
-rw-r--r--src/file_ape.c9
-rw-r--r--src/file_bmp.c138
-rw-r--r--src/file_doc.c1826
-rw-r--r--src/file_evtx.c80
-rw-r--r--src/file_exe.c969
-rw-r--r--src/file_exr.c58
-rw-r--r--src/file_fp7.c2
-rw-r--r--src/file_gpg.c271
-rw-r--r--src/file_gz.c6
-rw-r--r--src/file_ico.c30
-rw-r--r--src/file_jpg.c788
-rw-r--r--src/file_list.c4
-rw-r--r--src/file_m2ts.c2
-rw-r--r--src/file_mov.c484
-rw-r--r--src/file_mp3.c446
-rw-r--r--src/file_orf.c4
-rw-r--r--src/file_pf.c118
-rw-r--r--src/file_raf.c14
-rw-r--r--src/file_rw2.c4
-rw-r--r--src/file_sig.c51
-rw-r--r--src/file_tiff.c92
-rw-r--r--src/file_tiff.h87
-rw-r--r--src/file_tiff_be.c527
-rw-r--r--src/file_tiff_le.c533
-rw-r--r--src/file_txt.c52
-rw-r--r--src/file_wdp.c4
-rw-r--r--src/file_x3f.c8
-rw-r--r--src/file_x3i.c1
-rw-r--r--src/file_zip.c590
-rw-r--r--src/filegen.c182
-rw-r--r--src/filegen.h157
-rw-r--r--src/godmode.c4
-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/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/ntfs.c6
-rw-r--r--src/ntfs.h2
-rw-r--r--src/ntfs_fix.c2
-rw-r--r--src/ntfsp.c1
-rw-r--r--src/partgpt.c18
-rw-r--r--src/partgptn.c3
-rw-r--r--src/partgptw.c3
-rw-r--r--src/parti386.c1
-rw-r--r--src/phbf.c2
-rw-r--r--src/phbs.c1
-rw-r--r--src/phmain.c6
-rw-r--r--src/photorec.c6
-rw-r--r--src/photorec.h7
-rw-r--r--src/photorec_check_header.h2
-rw-r--r--src/qphotorec_locale.qrc3
-rw-r--r--src/setdate.c2
-rw-r--r--src/sudo.c26
-rw-r--r--src/sudo.h2
-rw-r--r--src/testdisk.c8
-rw-r--r--src/tpartwr.c7
84 files changed, 6589 insertions, 2412 deletions
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..7b424bf 100644
--- a/Makefile.am
+++ b/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-depth 100000 \
+ -wp-split -wp-literals \
+ -wp-timeout 20 -pp-annot \
+ -kernel-msg-key pp
+
SUBDIRS = icons man src
docdir ?= $(datadir)/doc/$(PACKAGE)
@@ -59,4 +80,34 @@ extras:
extrasstatic:
$(MAKE) LDFLAGS="$(LDFLAGS) -static" LIBS="$(PTHREAD_LIBS) $(LIBS)" CFLAGS="$(PTHREAD_CFLAGS) $(CFLAGS)" CXXFLAGS="$(PTHREAD_CFLAGS) $(CXXFLAGS)" extras
+session_doc.framac: src/file_doc.c src/common.c src/filegen.c src/log.c src/setdate.c
+ gcc -W -Wall -DMAIN_doc -DHAVE_CONFIG_H -O -o demo -I. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_doc -DHAVE_CONFIG_H -D__x86_64__" $(FRAMA_C_FLAGS) -save $@
+
+session_id3.framac: src/file_mp3.c src/common.c src/filegen.c src/log.c
+ gcc -W -Wall -DMAIN_id3 -DHAVE_CONFIG_H -O -o demo -I. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_id3 -DHAVE_CONFIG_H -D__x86_64__" $(FRAMA_C_FLAGS) -save $@
+
+session_jpg.framac: src/file_jpg.c src/file_tiff.c src/file_tiff_be.c src/file_tiff_le.c src/common.c src/filegen.c src/log.c src/suspend_no.c src/setdate.c
+ gcc -W -Wall -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 $(frama-c -print-path)/libc" $(FRAMA_C_FLAGS) -save $@
+
+session_tiff_be.framac: src/file_tiff.c src/file_tiff_be.c src/file_tiff_le.c src/common.c src/filegen.c src/log.c
+ gcc -W -Wall -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_be -DHAVE_CONFIG_H -D__x86_64__" $(FRAMA_C_FLAGS) -save $@
+
+session_tiff_le.framac: src/file_tiff.c src/file_tiff_be.c src/file_tiff_le.c src/common.c src/filegen.c src/log.c
+ gcc -W -Wall -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_le -DHAVE_CONFIG_H -D__x86_64__" $(FRAMA_C_FLAGS) -save $@
+
+session_%.framac: src/file_%.c src/common.c src/filegen.c src/log.c
+ gcc -W -Wall -DMAIN_$* -DHAVE_CONFIG_H -O -o demo -I. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_$* -DHAVE_CONFIG_H -D__x86_64__" $(FRAMA_C_FLAGS) -save $@
+
+frama-c-%: session_%.framac
+ frama-c-gui -load $^
+
+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/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..40ee68d 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="November 2019"
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..e20f914 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
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..a7c2a2b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -120,7 +120,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 \
@@ -369,6 +371,7 @@ photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_clu
QT_TS = \
lang/qphotorec.ca.ts \
+ lang/qphotorec.cs.ts \
lang/qphotorec.es.ts \
lang/qphotorec.fr.ts \
lang/qphotorec.it.ts \
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/common.c b/src/common.c
index 3b1f45b..afcf387 100644
--- a/src/common.c
+++ b/src/common.c
@@ -61,7 +61,7 @@ void *MALLOC(size_t size)
/* Warning, memory leak checker must be posix_memalign/memalign aware, otherwise *
* reports may look strange. Aligned memory is required if the buffer is *
* used for read/write operation with a file opened with O_DIRECT */
-#if defined(HAVE_POSIX_MEMALIGN)
+#if defined(HAVE_POSIX_MEMALIGN) && !defined(__FRAMAC__)
if(size>=512)
{
if(posix_memalign(&res,4096,size)==0)
@@ -70,7 +70,7 @@ void *MALLOC(size_t size)
return res;
}
}
-#elif defined(HAVE_MEMALIGN)
+#elif defined(HAVE_MEMALIGN) && !defined(__FRAMAC__)
if(size>=512)
{
if((res=memalign(4096, size))!=NULL)
@@ -226,12 +226,12 @@ char* strip_dup(char* str)
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-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 day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
- int month,year,secs;
+ unsigned int month,year,secs;
/* first subtract and mask after that... Otherwise, if
f_date == 0, bad things happen */
@@ -247,7 +247,7 @@ int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
void set_secwest(void)
{
const time_t t = time(NULL);
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(__FRAMAC__)
const struct tm *tmptr = localtime(&t);
#else
struct tm tmp;
diff --git a/src/common.h b/src/common.h
index c031222..8a5e5ea 100644
--- a/src/common.h
+++ b/src/common.h
@@ -122,6 +122,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 \
@@ -174,6 +177,8 @@ struct efi_guid_s
#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_MAC_AFS \
+ ((const efi_guid_t){le32(0x7c3457ef),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 \
@@ -433,12 +438,18 @@ 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);
+
unsigned int up2power(const unsigned int number);
void set_part_name(partition_t *partition, const char *src, const unsigned int max_size);
void set_part_name_chomp(partition_t *partition, const unsigned char *src, const unsigned int max_size);
char* strip_dup(char* str);
-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);
void set_secwest(void);
time_t td_ntfs2utc (int64_t ntfstime);
#ifndef BSD_MAXPARTITIONS
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/ext2p.c b/src/ext2p.c
index 84b2ca6..6cbb0f7 100644
--- a/src/ext2p.c
+++ b/src/ext2p.c
@@ -33,6 +33,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
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..24b9544 100644
--- a/src/fidentify.c
+++ b/src/fidentify.c
@@ -57,8 +57,10 @@ extern file_enable_t list_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)
+static int file_identify(const char *filename, const unsigned int options)
{
const unsigned int blocksize=65536;
const unsigned int buffer_size=blocksize + READ_SIZE;
@@ -103,8 +105,11 @@ 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))
+ )
{
file_recovery_new.handle=file;
my_fseek(file_recovery_new.handle, 0, SEEK_END);
@@ -125,8 +130,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
@@ -141,7 +148,7 @@ static int file_identify(const char *filename, const unsigned int check)
}
#ifndef __AFL_COMPILER
-static void file_identify_dir(const char *current_dir, const unsigned int check)
+static void file_identify_dir(const char *current_dir, const unsigned int options)
{
DIR *dir;
struct dirent *entry;
@@ -164,9 +171,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);
}
@@ -200,7 +207,7 @@ static void display_version(void)
int main(int argc, char **argv)
{
int i;
- unsigned int check=0;
+ unsigned int options=0;
FILE *log_handle=NULL;
int log_errno=0;
int enable_all_formats=1;
@@ -211,7 +218,11 @@ int main(int argc, char **argv)
{
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 ||
@@ -268,6 +279,7 @@ int main(int argc, char **argv)
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 +294,17 @@ 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
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_bmp.c b/src/file_bmp.c
index f20326a..42209d2 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,45 @@ 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_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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);
+ @*/
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 +94,110 @@ 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; */
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()
+{
+ const char fn[] = "recup_dir.1/f0000000.bmp";
+ 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);
+ /*@ 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_doc.c b/src/file_doc.c
index 4451796..67b24ac 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,341 @@ 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);
+ @ 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 +449,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 +487,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 +526,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 +547,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 +563,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,388 +592,48 @@ 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);
+ @ 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)
-{
- const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
- const uint32_t *fat;
- unsigned int fat_entries;
- 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);
-#endif
- for(block=le32(header->root_start_block), i=0;
- block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
- block=le32(fat[block]), i++)
- {
- 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)
- return NULL;
- {
- 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";
- }
- }
-#ifdef DEBUG_OLE
- log_info("Root Directory end\n");
-#endif
- return NULL;
-}
-
-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)
-{
- 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)
- {
- if(strcmp(file_recovery_new->extension,"sda")==0)
- {
- if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
- file_recovery_new->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="pub";
- }
- return 1;
- }
- if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL)
- {
- file_recovery_new->extension="doc";
- }
- else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL)
- {
- file_recovery_new->extension="sda";
- }
- else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL)
- {
- file_recovery_new->extension="sdc";
- }
- else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
- {
- file_recovery_new->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="xls";
- }
- else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL)
- {
- file_recovery_new->extension="ppt";
- }
- else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
- {
- file_recovery_new->extension="mdb";
- }
- else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL)
- {
- file_recovery_new->extension="vsd";
- }
- else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL)
- {
- 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";
- }
- else
- file_recovery_new->extension=file_hint_doc.extension;
- return 1;
-}
-
-static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
-{
- 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)]))
- {
- 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;
- }
- }
- 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)))
- {
- if(my_fseek(IN, offset + ((1+le32(dif[j]))<<le16(header->uSectorShift)), SEEK_SET)<0)
- {
- free(dif);
- free(fat);
- return NULL;
- }
- if(fread(data, (1<<le16(header->uSectorShift)), 1, IN)!=1)
- {
- free(dif);
- free(fat);
- return NULL;
- }
- }
- }
- free(dif);
- return fat;
-}
-
+/*@
+ @ 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)
{
+ //@ split uSectorShift;
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))
+ unsigned int i;
+ 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
+ /*@ assert \valid(dataPt + ( 0 .. len-1)); */
+ for(i=0, block=block_start;
+ i < i_max;
+ i++, block=le32(fat[block]))
{
if(!(block < fat_entries))
{
free(dataPt);
return NULL;
}
- if(my_fseek(IN, offset + ((1+block)<<uSectorShift), SEEK_SET)<0)
- {
- free(dataPt);
- return NULL;
- }
- if(fread(&dataPt[size_read], (1<<uSectorShift), 1, IN)!=1)
+ if(OLE_read_block(IN, &dataPt[i<<uSectorShift], uSectorShift, block, offset)<0)
{
free(dataPt);
return NULL;
@@ -582,201 +642,516 @@ static void *OLE_read_stream(FILE *IN,
return dataPt;
}
+/*@
+ @ 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)
{
- unsigned char*minifat_pos;
uint32_t *minifat;
unsigned int block;
unsigned int i;
+ const unsigned int uSectorShift=le16(header->uSectorShift);
if(le32(header->csectMiniFat)==0)
return NULL;
- minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << le16(header->uSectorShift));
- minifat_pos=(unsigned char*)minifat;
+ /*@ assert le32(header->csectMiniFat)!=0; */
+#ifdef __FRAMAC__
+ minifat=(uint32_t*)MALLOC(2048 << 12);
+#else
+ minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << uSectorShift);
+#endif
block=le32(header->MiniFat_block);
- for(i=0; i < le32(header->csectMiniFat) && block < fat_entries; i++)
+ for(i=0; i < le32(header->csectMiniFat); i++)
{
- if(my_fseek(IN, offset + (((uint64_t)1+block) << le16(header->uSectorShift)), SEEK_SET) < 0)
+ unsigned char*minifat_pos=(unsigned char*)minifat + (i << uSectorShift);
+ if(block >= fat_entries)
{
free(minifat);
return NULL;
}
- if(fread(minifat_pos, 1 << le16(header->uSectorShift), 1, IN) != 1)
+ if(OLE_read_block(IN, (unsigned char *)minifat_pos, uSectorShift, block, offset)<0)
{
free(minifat);
return NULL;
}
- minifat_pos+=1 << le16(header->uSectorShift);
block=le32(fat[block]);
}
return minifat;
}
+/*@
+ @ requires \valid_read((char *)buffer + (offset .. offset + 4 - 1));
+ @ requires \initialized((char *)buffer + (offset .. offset + 4 - 1));
+ @*/
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));
+ @*/
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);
}
-static void software2ext(const char **ext, const unsigned int count, const unsigned char *software)
+/*@
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. count-1));
+ @ requires \initialized(software + (0 .. count-1));
+ @ ensures *ext != \null || valid_read_string(*ext);
+ @*/
+static void software2ext(const char **ext, const unsigned char *software, const unsigned int count)
{
if(count>=12 && memcmp(software, "MicroStation", 12)==0)
{
- *ext="dgn";
+ *ext=extension_dgn;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=14 && memcmp(software, "Microsoft Word", 14)==0)
{
- *ext="doc";
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=15 && memcmp(software, "Microsoft Excel", 15)==0)
{
if(*ext==NULL || strcmp(*ext,"sldprt")!=0)
- *ext="xls";
+ {
+ *ext=extension_xls;
+ /*@ assert valid_read_string(*ext); */
+ }
return;
}
if(count>=20 && memcmp(software, "Microsoft PowerPoint", 20)==0)
{
- *ext="ppt";
+ *ext=extension_ppt;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=21 && memcmp(software, "Microsoft Office Word", 21)==0)
{
- *ext="doc";
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count==21 && memcmp(software, "TurboCAD for Windows", 21)==0)
{
- *ext="tcw";
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count==22 && memcmp(software, "TurboCAD pour Windows", 22)==0)
{
- *ext="tcw";
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
return;
}
+ /*@ assert *ext != \null || valid_read_string(*ext); */
return ;
}
-static const char *software_uni2ext(const unsigned int count, const unsigned char *software)
+/*@
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. 2*count-1));
+ @ requires \initialized(software + (0 .. 2*count-1));
+ @ ensures \result == \null || \result == extension_et || \result == extension_psmodel;
+ @ ensures \result == \null || valid_read_string(\result);
+ @*/
+static const char *software_uni2ext(const unsigned char *software, const unsigned int count)
{
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";
+ {
+ /*@ assert valid_read_string(extension_et); */
+ return extension_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";
+ {
+ /*@ assert valid_read_string(extension_psmodel); */
+ return extension_psmodel;
+ }
return NULL;
}
-static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char **title, time_t *file_time)
+struct summary_entry
{
- unsigned int pos;
- assert(dirLen >= 48 && dirLen<=1024*1024);
+ 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);
+ @*/
+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)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert 0 < count <= size; */
+ if(offset_soft + count > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert offset_soft + count <= size; */
#ifdef DEBUG_OLE
- dump_log(dataPt, dirLen);
+ {
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j<count; j++)
+ {
+ log_info("%c", buffer[offset_soft + j]);
+ }
+ log_info("\n");
+ }
#endif
- if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
- return ;
- pos=get32u(dataPt, 44);
- if(pos > dirLen - 8)
+#ifndef MAIN_doc
+ software2ext(ext, &buffer[offset_soft], count);
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+}
+
+/*@
+ @ 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);
+ @*/
+static void OLE_parse_uni_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; */
{
-// unsigned int size;
- unsigned int numEntries;
- unsigned int i;
- numEntries=get32u(dataPt, pos+4);
+ const unsigned int offset8=offset + 8;
+ /*@ assert offset8 < size; */
+ const unsigned int count=get32u(buffer, offset + 4);
+ unsigned int count2;
+ if(count == 0 || count > size/2)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert 0 < count <= size/2; */
+ count2=2*count;
+ /*@ assert 0 < count2 <= size; */
+ if(count2 > size - offset8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert count2 <= size - offset8; */
+ /*@ assert \valid_read(buffer + (0 .. size - 1)) && \initialized(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read(buffer + (0 .. offset8 + count2 - 1)); */
#ifdef DEBUG_OLE
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j < 2 * count; j+=2)
{
- unsigned int size=get32u(dataPt, pos);
- log_info("Property Info %u - %u at 0x%x\n", numEntries, size, pos);
+ log_info("%c", buffer[offset + 8 + j]);
}
+ log_info("\n");
+#endif
+#ifndef __FRAMAC__
+ /*@ assert \initialized(buffer + (0 .. offset8 + count2 - 1)); */
+ *ext=software_uni2ext(&buffer[offset8], count);
#endif
- if(pos + 8 + 8 * numEntries > dirLen)
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(title);
+ @ requires *title == \null || valid_read_string(*title);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
+static void OLE_parse_title_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, char **title)
+{
+ if(offset + 8 > size)
+ {
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert offset + 8 <= size; */
+ {
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ const unsigned int count=get32u(buffer, offset + 4);
+ const unsigned int offset_tmp=offset + 8;
+ char *tmp;
+ if(count <= 1 || count > size)
+ {
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
- for(i=0; i<numEntries; i++)
+ }
+ /*@ assert 1 < count <= size; */
+ if(offset_tmp + count > size)
{
- 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;
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert offset_tmp + count <= size; */
+#ifndef MAIN_doc
+ tmp=(char*)MALLOC(count+1);
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert offset_tmp + count <= size; */
+ /*@ assert \valid_read(buffer + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read((char*)buffer + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read((buffer + offset_tmp) + (0 .. count - 1)); */
+ /*@ assert \valid_read((buffer + offset_tmp) + (1 .. count - 1)); */
+ /*@ assert \valid_read(((char*)(buffer+offset_tmp))+(0..count-1)); */
+ /*@ assert \valid_read(((char*)(buffer+offset_tmp))+(1..count-1)); */
+ /*@ assert \valid_read((char*)(buffer + offset_tmp)); */
+ /*@ assert \valid_read((char*)(buffer + offset_tmp)) && \valid_read(((char*)(buffer+offset_tmp))+(1..count-1)); */
+ /*@ assert valid_read_or_empty((void const *)(buffer + offset_tmp), count); */
+ memcpy(tmp, &buffer[offset_tmp], count);
+ tmp[count]='\0';
+ /*@ assert valid_read_string(tmp); */
+#ifdef DEBUG_OLE
+ log_info("Title %s\n", tmp);
+#endif
+ *title=tmp;
+ /*@ assert valid_read_string(*title); */
+#endif
+ }
+ /*@ assert *title == \null || valid_read_string(*title); */
+}
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(file_time);
+ @*/
+static void OLE_parse_filetime_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, time_t *file_time)
+{
+ uint64_t tmp;
+ if(offset + 12 > size)
+ {
+ return ;
+ }
+ /*@ assert offset + 12 <= size; */
+ tmp=get64u(buffer, offset + 4);
+ tmp/=10000000;
+ if(tmp > (uint64_t)134774 * 24 * 3600)
+ {
+ tmp -= (uint64_t)134774 * 24 * 3600;
+ *file_time=tmp;
+ }
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(ext);
+ @ requires \valid(title);
+ @ requires \valid(file_time);
+ @ requires *title == \null || valid_read_string(*title);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
+static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned int size, const char **ext, char **title, time_t *file_time)
+{
+ const struct summary_entry *entries=(const struct summary_entry *)&buffer[8];
+ const unsigned int numEntries=get32u(buffer, 4);
+ unsigned int i;
+#ifdef DEBUG_OLE
+ log_info("Property Info %u entries - %u bytes\n", numEntries, size);
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ if(numEntries == 0 || numEntries > 1024*1024)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 0 < numEntries <= 1024*1024; */
+ if(8 + numEntries * 8 > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_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 *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_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 *title == \null || valid_read_string(*title);
+ @ loop invariant 0 <= i <= numEntries;
+ @ loop variant numEntries-i;
+ @*/
+ for(i=0; i<numEntries; i++)
+ {
+ const unsigned int entry_offset=8+8*i;
+ if(entry_offset + 8 > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert entry_offset + 8 <= size; */
+ {
+ const struct summary_entry *entry=(const struct summary_entry *)&buffer[entry_offset];
+ const unsigned int tag=le32(entry->tag);
+ const unsigned int offset=le32(entry->offset);
unsigned int type;
- if(valStart >= dirLen)
+ if(offset >= size - 4)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
- type=get32u(dataPt, pos + offset);
+ }
+ /*@ 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, valStart 0x%x, type 0x%x\n",
- entry, tag, offset, valStart, type);
+ log_info("entry 0x%x, tag 0x%x, offset 0x%x, offset + 4 0x%x, type 0x%x\n",
+ entry, tag, offset, offset + 4, 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]);
+ OLE_parse_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
/* 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]);
+ OLE_parse_uni_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
+ /* tag: title, type: VT_LPSTR */
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
+ OLE_parse_title_entry(buffer, size, offset, title);
+ /*@ assert *title == \null || valid_read_string(*title); */
}
/* 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;
- }
+ OLE_parse_filetime_entry(buffer, size, offset, file_time);
}
}
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+}
+
+/*@
+ @ requires 48 <= dirLen <= 1024*1024;
+ @ requires \valid_read(dataPt + (0 .. dirLen-1));
+ @ requires \initialized(dataPt + (0 .. dirLen-1));
+ @ requires \valid(ext);
+ @ requires \valid(title);
+ @ requires \valid(file_time);
+ @ requires *title == \null || valid_read_string(*title);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_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)
+{
+ unsigned int pos;
+ assert(dirLen >= 48 && dirLen<=1024*1024);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+#ifdef DEBUG_OLE
+ dump_log(dataPt, dirLen);
+#endif
+ if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
+ return ;
+ pos=get32u(dataPt, 44);
+ if(pos > dirLen - 8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert pos <= dirLen - 8; */
+ {
+ /* PropertySet */
+ const unsigned int size=get32u(dataPt, pos);
+ if(size <= 8 || size > dirLen || pos + size > dirLen)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ 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 *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+#ifndef __FRAMAC__
+ OLE_parse_PropertySet(&dataPt[pos], size, ext, title, file_time);
+#endif
}
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
}
+/*@
+ @ requires \valid_read(ministream + (0 .. ministream_size-1));
+ @ requires \valid_read(minifat + (0 .. minifat_entries-1));
+ @ requires uMiniSectorShift==6;
+ @ requires 48 <= len <= 1024*1024;
+ @ ensures \result!=\null ==> \valid((char *)\result + (0 .. len-1));
+ @*/
static void *OLE_read_ministream(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)
@@ -784,41 +1159,91 @@ static void *OLE_read_ministream(unsigned char *ministream,
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);
+ @ requires \valid(file_time);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires *title == \null || valid_read_string(*title);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries,
const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size,
const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time,
const uint64_t offset)
{
+ const unsigned int uSectorShift=le16(header->uSectorShift);
unsigned char *summary=NULL;
if(len < 48 || len>1024*1024)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_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)
{
- const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << le16(header->uSectorShift)) / 4;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ if(ministream_size > 1024*1024 || le32(header->csectMiniFat) > 2048)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 0 < le32(header->csectMiniFat) <= 2048; */
+ {
+ const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << uSectorShift) / 4;
uint32_t *minifat;
unsigned char *ministream;
if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries, offset))==NULL)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_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,15 +1257,34 @@ 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)); */
+// OLE_parse_summary_aux(summary, 4096, ext, title, file_time);
+ /*@ assert *title == \null || valid_read_string(*title); */
+ OLE_parse_PropertySet(summary, 4096, ext, title, file_time);
+ 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 *title == \null || valid_read_string(*title); */
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_doc(file_recovery_t *file_recovery)
{
const char *ext=NULL;
@@ -851,8 +1295,10 @@ static void file_rename_doc(file_recovery_t *file_recovery)
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;
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 +1311,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 +1347,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;
@@ -896,15 +1363,12 @@ static void file_rename_doc(file_recovery_t *file_recovery)
block=le32(fat[block]), i++)
{
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);
@@ -912,22 +1376,23 @@ static void file_rename_doc(file_recovery_t *file_recovery)
free(title);
return ;
}
-
#ifdef DEBUG_OLE
log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
{
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++)
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
{
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
if(dir_entry->type!=NO_ENTRY)
{
const char SummaryInformation[40]=
@@ -950,97 +1415,42 @@ static void file_rename_doc(file_recovery_t *file_recovery)
(unsigned int)le32(dir_entry->start_block),
(unsigned int)le32(dir_entry->size));
#endif
+ {
+ const char *tmp=entry2ext(dir_entry);
+ /*@ assert tmp == \null || valid_read_string(tmp); */
+ if(tmp!=NULL)
+ ext=tmp;
+ /*@ assert ext == \null || valid_read_string(ext); */
+ }
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";
+ 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="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;
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;
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;
break;
case 40:
if(memcmp(dir_entry->name, SummaryInformation, 40)==0)
@@ -1050,38 +1460,19 @@ static void file_rename_doc(file_recovery_t *file_recovery)
le32(dir_entry->start_block), le32(dir_entry->size),
&ext, &title, &file_time, 0);
}
- 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";
- 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";
break;
}
if(sid==1 && le16(dir_entry->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));
#endif
}
}
+ if(ext==NULL && is_db==2)
+ ext=extension_db;
}
free(dir_entries);
}
@@ -1099,8 +1490,217 @@ static void file_rename_doc(file_recovery_t *file_recovery)
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->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);
+ @*/
+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); */
+ 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_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..ade58b0 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,141 @@ 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 \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_exe.extension || file_recovery_new->extension == extension_dll);
+ @*/
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)
- {
- /* 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)
+ le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr))
{
- /* 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 +202,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 +245,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 +279,595 @@ 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));
+ @*/
+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)
{
-#ifdef DEBUG_EXE
- log_info("%c", buffer[pos]);
-#endif
+ 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);
+ log_info("parse_String len=%u val_len=%u type=%u\n", len, val_len, type);
+ if(len > end)
+ return -1;
+ if(6 + 2 * val_len > len)
+ return -1;
+ dump_log(buffer, len);
+// type=1 => text
+ if(6+needle_len < end && type==1 && memcmp(&buffer[6], needle, needle_len)==0)
+ {
+ if(6 + needle_len + 2 * val_len > len)
+ return -1;
+ file_rename_unicode(file_recovery, buffer, end, 6+needle_len, NULL, force_ext);
+ }
+ return len;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+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;
+ log_info("parse_StringArray end=%u\n", end);
+ /*@
+ @ loop variant end - pos;
+ @*/
+ while(pos<end)
+ {
+ const int res=parse_String(file_recovery, &buffer[pos], end - pos, needle, needle_len, force_ext);
+ if(res <= 0)
+ return -1;
+ /*@ 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));
+ @*/
+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);
+ log_info("parse_StringTable len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ 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));
+ @*/
+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;
}
- pos+=2;
+ PE_index=(const struct PE_index*)buffer;
+ /*@ assert \valid_read(PE_index); */
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ log_info("parse_StringFileInfo len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ 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;
- return pos;
+ if(pos > len)
+ return -1;
+ return parse_StringTable(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext);
}
-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 end > 0;
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+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;
- while(1)
+ const struct PE_index *PE_index;
+ const char *stringName;
+ unsigned int len;
+ unsigned int val_len;
+ if(6 > end)
{
- const struct PE_index *PE_index;
- pos=(pos + 3) & 0xfffffffc; /* align on a 4-byte boundary */
- if(pos + 6 > end)
- {
- 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;
- }
-#ifdef DEBUG_EXE
- log_info(": ");
-#endif
- pt=ReadUnicodeStr(buffer, pt, pos);
- }
- }
-#ifdef DEBUG_EXE
- log_info("\n");
-#endif
- }
- }
- else
- {
- pos+=le16(PE_index->len)+le16(PE_index->val_len);
- }
- }
+ 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);
+ log_info("parse_VS_VERSIONINFO len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ 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];
+ log_info("PEVersion(file, %u, %u, file_recovery)\n", offset, length);
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
- if(level > 2)
+ nameEntries = buffer[12]+(buffer[13]<<8);
+ idEntries = buffer[14]+(buffer[15]<<8);
+ count = nameEntries + idEntries;
+ }
+ log_info("pe_resource_language count=%u\n", count);
+ 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 ;
+ /*@ 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 ;
- nameEntries = buffer[12]+(buffer[13]<<8);
- idEntries = buffer[14]+(buffer[15]<<8);
- count = nameEntries + idEntries;
+ /*@ 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);
+ @*/
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 +877,95 @@ 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)
+ {
+ 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);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&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..84a5587 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,22 @@ 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;
+ @*/
+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);
+ */
static unsigned int old_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *indeterminate_length)
{
/* Old format */
@@ -119,8 +113,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,6 +125,12 @@ 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);
+ @ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==5);
+ @ ensures (*partial_body_length==0) || (*partial_body_length==1);
+ */
static unsigned int new_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *partial_body_length)
{
*partial_body_length=0;
@@ -135,34 +138,53 @@ static unsigned int new_format_packet_length(const unsigned char *buf, unsigned
if(buf[0]<=191)
{
*length_type=1;
+ /*@ assert 0 <= buf[0] <= 191; */
return buf[0];
}
/* Two-Octet Body Length */
if(buf[0]<=223)
{
+ /*@ assert 192 <= buf[0] <= 223; */
+ unsigned int tmp=buf[0];
+ /*@ assert 192 <= tmp <= 223; */
+ tmp = ((tmp-192) << 8) + buf[1] + 192;
+ /*@ assert 192 <= tmp <= ((223-192) << 8) + 255 + 192; */
*length_type=2;
- return ((buf[0] - 192) << 8) + buf[1] + 192;
+ return tmp;
}
/* Five-Octet Body Length */
if(buf[0]==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];
+ return tmp;
+ }
+ {
+ /*@ assert 224 <= buf[0] <= 254; */
+ const unsigned int tmp=buf[0]&0x1fu;
+ /* Partial Body Lengths */
+ *length_type=1;
+ *partial_body_length=1;
+ return 1u << tmp;
}
- /* 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;
+ @*/
+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;
+ @*/
+static int is_valid_pubkey_algo(const int algo)
{
/* 1 - RSA (Encrypt or Sign)
* 2 - RSA Encrypt-Only
@@ -189,6 +211,9 @@ static int is_valid_pubkey_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @*/
static int is_valid_sym_algo(const int algo)
{
/*
@@ -222,6 +247,9 @@ static int is_valid_sym_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @*/
static int is_valid_S2K(const unsigned int algo)
{
/* ID S2K Type
@@ -235,48 +263,62 @@ static int is_valid_S2K(const unsigned int algo)
return (algo==0 || algo==1 || algo==3);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @*/
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 + 6 >= 0x8000000000000000)
+ return;
+ /*@ assert offset < 0x8000000000000000 - 6; */
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 ||
fread(&buffer, sizeof(buffer), 1, file_recovery->handle) != 1)
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,14 +326,19 @@ 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;
+ /*@ assert offset < 0x8000000000000000; */
+ if(offset + length >= 0x8000000000000000)
+ return ;
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
@@ -311,14 +358,16 @@ static void file_check_gpg(file_recovery_t *file_recovery)
if(buffer[i+1+8]==16 || buffer[i+1+8]==20)
{
int len2;
- unsigned char tmp[2];
+ uint16_t mpi2;
if(my_fseek(file_recovery->handle, offset+1+8+1+2+len, SEEK_SET) < 0 ||
- fread(&tmp, sizeof(tmp), 1, file_recovery->handle) != 1)
+ fread(&mpi2, sizeof(mpi2), 1, file_recovery->handle) != 1)
return;
- mpi=(const uint16_t *)&tmp[0];
- len2=is_valid_mpi(mpi);
+#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(*mpi));
+ log_info(" data: [ %u bits]\n", be16(*mpi2));
#endif
if(len2 <= 0)
return ;
@@ -408,6 +457,18 @@ 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_check == &file_check_gpg);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_gpg.extension || file_recovery_new->extension == extension_pgp);
+ @*/
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 +477,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,21 +491,25 @@ 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",
@@ -452,13 +521,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,6 +537,7 @@ 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],
@@ -473,14 +545,15 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]);
log_info(" data: [ %u bits]\n", be16(*mpi));
#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));
#endif
@@ -600,7 +673,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 +714,85 @@ 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];
+ 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);
+ /*@ 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 31f4e12..0ef52e0 100644
--- a/src/file_gz.c
+++ b/src/file_gz.c
@@ -241,6 +241,12 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
file_recovery_new->extension="prproj";
return 1;
}
+ if(memcmp(buffer_uncompr, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<gnc-v2", 47)==0)
+ {
+ /* GnuCash, http://gnucash.org/ */
+ file_recovery_new->extension="gnucash";
+ return 1;
+ }
if(strstr((const char*)&buffer_uncompr, "<!DOCTYPE KMYMONEY-FILE>")!=NULL)
{
file_recovery_new->extension="kmy";
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..3b0a895 100644
--- a/src/file_jpg.c
+++ b/src/file_jpg.c
@@ -49,16 +49,20 @@
#include "file_jpg.h"
#include "file_tiff.h"
#include "setdate.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#ifndef MAIN_jpg
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 int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned i, const unsigned int size);
@@ -72,12 +76,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;
@@ -120,6 +124,10 @@ struct MP_Entry
uint16_t dep2;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires size >= 8;
+ @ requires \valid(mpo + ( 0 .. size-1));
+ @*/
static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size)
{
const uint16_t *tmp16;
@@ -195,6 +203,10 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
return max_offset;
}
+/*@
+ @ requires size >= 8;
+ @ requires \valid(mpo + ( 0 .. size-1));
+ @*/
static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size)
{
const uint16_t *tmp16;
@@ -270,8 +282,13 @@ static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset
return max_offset;
}
+/*@
+ @ requires size >= 8;
+ @ requires \valid(mpo + ( 0 .. size-1));
+ @*/
static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const unsigned int size)
{
+#ifndef MAIN_jpg
if(mpo[0]=='I' && mpo[1]=='I' && mpo[2]=='*' && mpo[3]==0)
{
return check_mpo_le(mpo, offset, size);
@@ -280,9 +297,15 @@ static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const
{
return check_mpo_be(mpo, offset, size);
}
+#endif
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \initialized(&fr->time);
+ @*/
static void file_check_mpo(file_recovery_t *fr)
{
unsigned char buffer[512];
@@ -306,6 +329,9 @@ static void file_check_mpo(file_recovery_t *fr)
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 +340,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; */
{
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,6 +401,21 @@ static int is_marker_valid(const unsigned int marker)
}
}
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures \result == 1 ==> file_recovery_new->extension == file_hint_jpg.extension;
+ @ ensures \result == 1 ==> valid_read_string(file_recovery_new->extension);
+ @ ensures \result == 1 ==> file_recovery_new->calculated_file_size == 0;
+ @ ensures \result == 1 ==> file_recovery_new->file_size == 0;
+ @ ensures \result == 1 ==> file_recovery_new->offset_ok == 0;
+ @ ensures \result == 1 ==> file_recovery_new->file_check == file_check_jpg;
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ ensures \result == 1 && buffer_size >= 4 ==> file_recovery_new->data_check == data_check_jpg;
+ @*/
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;
@@ -388,17 +432,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);
+#ifndef MAIN_jpg
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 +478,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
return 0;
}
}
+#ifndef MAIN_jpg
/* 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 +501,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);
@@ -488,12 +536,15 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
{
if(buffer[i+1]==0xe1)
{ /* APP1 Exif information */
- if(i+0x0A < buffer_size && 2+(buffer[i+2]<<8)+buffer[i+3] > 0x0A)
+ const unsigned int tmp=2+(buffer[i+2]<<8)+buffer[i+3];
+ if(i+0x0A < buffer_size && tmp > 0x0A)
{
- unsigned int tiff_size=2+(buffer[i+2]<<8)+buffer[i+3]-0x0A;
+ unsigned int tiff_size=tmp-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);
+#ifndef MAIN_jpg
+ jpg_time=get_date_from_tiff_header(&buffer[i+0x0A], tiff_size);
+#endif
}
}
else if(buffer[i+1]==0xc4)
@@ -505,7 +556,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
i+=2+(buffer[i+2]<<8)+buffer[i+3];
}
}
- if(i+1 < file_recovery->blocksize && buffer[i+1]!=0xda)
+ if(i+1 < file_recovery_new->blocksize && buffer[i+1]!=0xda)
return 0;
if(i+1 < 512 && buffer[i+1]!=0xda)
return 0;
@@ -517,9 +568,11 @@ 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;
}
+#ifndef MAIN_jpg
#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields, must be the first field */
@@ -1176,7 +1229,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 +1303,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 +1314,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;
}
@@ -1327,8 +1378,13 @@ static void jpg_check_picture(file_recovery_t *file_recovery)
}
}
#endif
+#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));
+ @*/
+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 */
@@ -1369,299 +1425,387 @@ 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));
+ @*/
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];
+ if(be16(h->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];
+ if(h->precision!=8 || be16(h->width)==0 || h->nbr==0)
+ return 1;
+ if(be16(h->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;
+ @*/
static void jpg_search_marker(file_recovery_t *file_recovery)
{
FILE* infile=file_recovery->handle;
unsigned char buffer[40*8192];
size_t nbytes;
+ uint64_t offset_test=file_recovery->offset_error;
uint64_t offset;
- unsigned int i;
+ /*@ assert offset_test == file_recovery->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 == file_recovery->offset_error; */
+ /*@
+ @ loop invariant offset_test >= file_recovery->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); */
+ /*@ assert offset_test >= file_recovery->offset_error; */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+ if(offset_test > 0x80000000)
+ return ;
+#endif
+ 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 >= file_recovery->offset_error; */
+ /*@
+ @ loop invariant offset + i >= offset_test;
+ @ loop invariant offset_test >= file_recovery->offset_error;
+ @ loop invariant 0 <= i < nbytes + file_recovery->blocksize;
+ @*/
+ while(i+1<nbytes)
{
- for(;i+1<nbytes; i+=file_recovery->blocksize)
+ const uint64_t tmp=offset + i;
+ /*@ assert tmp >= offset_test; */
+ 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 - file_recovery->offset_error;
+ 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);
}
+ 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)
- return 0;
- if((nbytes=fread(&buffer, 1, sizeof(buffer), infile))>0)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires \valid(thumb_offset);
+ @ 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;
+ if(tiff_offset < nbytes && size > 8)
{
- unsigned int offset;
- file_recovery->offset_error=0;
- for(offset=file_recovery->blocksize; offset < nbytes && file_recovery->offset_error==0; offset+=file_recovery->blocksize)
+ /*@ assert tiff_offset < nbytes; */
+ /*@ assert size > 8; */
+ const unsigned char *potential_error=NULL;
+ unsigned int tiff_size=size-0x08;
+ const unsigned char *thumb_data=NULL;
+ unsigned int thumb_size=0;
+ if(nbytes - tiff_offset < tiff_size)
{
- 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;
- }
+ tiff_size=nbytes - tiff_offset;
+ /*@ assert tiff_offset + tiff_size == nbytes; */
}
- offset=2;
- while(offset + 4 < nbytes && (file_recovery->offset_error==0 || offset < file_recovery->offset_error))
+ else
{
- const unsigned int i=offset;
- const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
- if(buffer[i]!=0xff)
+ /*@ 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)); */
+ const unsigned char *tiff=&buffer[tiff_offset];
+ /*@ assert \valid_read(tiff+ (0 .. tiff_size-1)); */
+ if(file_recovery->time==0)
{
-#ifdef 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;
+ /*@ assert \valid_read(tiff+ (0 .. tiff_size-1)); */
+ file_recovery->time=get_date_from_tiff_header(tiff, tiff_size);
}
- if(buffer[i+1]==0xff)
+#ifndef __FRAMAC__
+ *thumb_offset=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFOFFSET, &potential_error);
+ if(*thumb_offset!=0)
{
- /* See B.1.1.2 Markers in http://www.w3.org/Graphics/JPEG/itu-t81.pdf*/
- offset++;
- continue;
+ *thumb_offset+=tiff_offset;
+ thumb_data=buffer+ (*thumb_offset);
+ thumb_size=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFBYTECOUNT, &potential_error);
}
-#ifdef 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 */
+ if(potential_error!=NULL)
{
- file_recovery->offset_ok=i+1;
- return thumb_offset;
+ file_recovery->offset_error=potential_error-buffer;
+ return 0;
}
- else if(buffer[i+1]==0xe1)
- { /* APP1 Exif information */
-#if 1
- if(i+0x0A < nbytes && 2+size > 0x0A)
+ if(file_recovery->offset_ok<i)
+ file_recovery->offset_ok=i;
+#ifndef MAIN_jpg
+ if(thumb_data!=0 && thumb_size!=0)
+ {
+ if(*thumb_offset < nbytes - 1)
{
- 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)
+ 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)
{
- thumb_offset=thumb_data-(const char*)buffer;
- ifbytecount=find_tag_from_tiff_header(tiff, tiff_size, TIFFTAG_JPEGIFBYTECOUNT, &potential_error);
+ file_recovery->offset_error=*thumb_offset;
+ jpg_search_marker(file_recovery);
+ return 0;
}
- if(potential_error!=NULL)
+ if(buffer[*thumb_offset+1]!=0xd8)
{
- file_recovery->offset_error=potential_error-(const char*)buffer;
+ file_recovery->offset_error=*thumb_offset+1;
return 0;
}
- if(file_recovery->offset_ok<i)
- file_recovery->offset_ok=i;
- if(thumb_data!=NULL && ifbytecount!=NULL)
+ while(j+4<nbytes && thumb_sos_found==0)
{
- const unsigned int thumb_size=ifbytecount-(const char*)tiff;
- if(thumb_offset < nbytes - 1)
+ if(buffer[j]!=0xff)
{
- unsigned int j=thumb_offset+2;
- unsigned int thumb_sos_found=0;
+ file_recovery->offset_error=j;
#ifdef DEBUG_JPEG
- unsigned int j_old=j;
+ 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
- if(buffer[thumb_offset]!=0xff)
- {
- file_recovery->offset_error=thumb_offset;
- jpg_search_marker(file_recovery);
- return 0;
- }
- if(buffer[thumb_offset+1]!=0xd8)
+ jpg_search_marker(file_recovery);
+ return 0;
+ }
+ if(buffer[j+1]==0xff)
+ {
+ /* See B.1.1.2 Markers in http://www.w3.org/Graphics/JPEG/itu-t81.pdf*/
+ j++;
+ continue;
+ }
+#ifdef DEBUG_JPEG
+ log_info("%s thumb marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j);
+#endif
+ if(buffer[j+1]==0xda) /* Thumb SOS: Start Of Scan */
+ thumb_sos_found=1;
+ else if(buffer[j+1]==0xc4) /* DHT */
+ {
+ if(jpg_check_dht(buffer, nbytes, j, 2+(buffer[j+2]<<8)+buffer[j+3])!=0)
{
- file_recovery->offset_error=thumb_offset+1;
+ file_recovery->offset_error=j+2;
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;
- }
+ }
+ 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
- log_info("%s thumb marker 0x%02x at 0x%x\n", file_recovery->filename, buffer[j+1], j);
-#endif
- if(buffer[j+1]==0xda) /* Thumb SOS: Start Of Scan */
- thumb_sos_found=1;
- else if(buffer[j+1]==0xc4) /* DHT */
- {
-#if 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;
- }
+ j_old=j;
#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
+ 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(&buffer[*thumb_offset], thumb_size, 1, out) < 1)
{
- 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;
+ log_error("Can't write to %s: %s\n", thumbname, strerror(errno));
}
- if(file_recovery->offset_ok<j)
- file_recovery->offset_ok=j;
-#ifdef DEBUG_JPEG
- j_old=j;
-#endif
- j+=2U+(buffer[j+2]<<8)+buffer[j+3];
+ fclose(out);
+ if(file_recovery->time!=0 && file_recovery->time!=(time_t)-1)
+ set_date(thumbname, file_recovery->time, file_recovery->time);
}
- if(thumb_sos_found>0 && extract_thumb>0
- && offset < nbytes && buffer[offset]==0xff)
+ else
{
- 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);
+ log_error("fopen %s failed\n", thumbname);
}
}
+ free(thumbname);
}
}
-#endif
}
- else if(buffer[i+1]==0xc4) /* DHT */
- {
-#if 1
- if(jpg_check_dht(buffer, nbytes, i, 2+size)!=0)
- {
- file_recovery->offset_error=i+2;
- return thumb_offset;
- }
#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);
+ */
+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)
+ {
+#ifdef 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;
+ }
+#ifdef 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 */
{
- file_recovery->offset_error=nbytes;
+ if(file_recovery->offset_ok<i+1)
+ file_recovery->offset_ok=i+1;
+ }
+ else
+ {
+ 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;
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 \initialized(&file_recovery->time);
+ @*/
static void file_check_jpg(file_recovery_t *file_recovery)
{
uint64_t thumb_offset;
@@ -1684,6 +1828,7 @@ static void file_check_jpg(file_recovery_t *file_recovery)
#ifdef DEBUG_JPEG
log_info("jpg_check_structure error at %llu\n", (long long unsigned)file_recovery->offset_error);
#endif
+#ifndef MAIN_jpg
#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
if(thumb_offset!=0 &&
(file_recovery->checkpoint_status==0 || thumb_error!=0) &&
@@ -1712,7 +1857,7 @@ static void file_check_jpg(file_recovery_t *file_recovery)
#endif
if(file_recovery->offset_error!=0)
return ;
-#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) && ! defined(MAIN_jpg)
jpg_check_picture(file_recovery);
#else
file_recovery->file_size=file_recovery->calculated_file_size;
@@ -1729,8 +1874,13 @@ static void file_check_jpg(file_recovery_t *file_recovery)
return ;
}
#endif
+#endif
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @*/
static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
#if 0
@@ -1745,7 +1895,7 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
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;
if(buffer[i-1]==0xFF)
{
if(buffer[i]==0xd9)
@@ -1793,6 +1943,15 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size >= 8;
+ @ requires \valid(file_recovery);
+ @ requires buffer_size >= 4;
+ @ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @*/
+/* 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); */
data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
/* Skip the SOI */
@@ -1802,7 +1961,8 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
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;
+ 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)
@@ -1834,27 +1994,49 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
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=file_recovery->calculated_file_size-(2+size)+8;
if(i>=buffer_size/2)
{
+ /* Restore previous value */
file_recovery->calculated_file_size-=2+size;
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; */
+ 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; */
+#ifndef __FRAMAC__
+ const uint64_t calculated_file_size=check_mpo(buffer+i+8, offset, size-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;
+ return DC_CONTINUE;
+ }
+#endif
+ }
+ }
+ 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;
+ return DC_CONTINUE;
+ }
}
}
}
@@ -1869,6 +2051,8 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
return DC_STOP;
}
}
+ /*@ 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; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */
return DC_CONTINUE;
}
@@ -1892,3 +2076,111 @@ 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);
+ 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_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ /*@ assert file_recovery_new.offset_ok == 0; */
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_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.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_jpg(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ {
+ 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..f706680 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;
@@ -458,7 +460,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 },
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..6e71676 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,138 @@ 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 \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 >= 0x80000000)
+ 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);
+#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 \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_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 +233,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 >= 0x80000000)
+ return 0;
+ /*@ assert 8 <= atom_size < 0x80000000; */
+ 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 +302,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 +318,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 +439,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..25d688a 100644
--- a/src/file_mp3.c
+++ b/src/file_mp3.c
@@ -31,9 +31,14 @@
#include "common.h"
#include "filegen.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
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);
@@ -112,6 +117,22 @@ static const unsigned int bit_rate_table[4][4][16]=
},
};
+#ifndef MAIN_mp3
+/*@
+ @ requires buffer_size >= 10;
+ @ 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_mp3.extension);
+ @ 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->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_id3);
+ @*/
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)
@@ -133,6 +154,7 @@ static int header_check_id3(const unsigned char *buffer, const unsigned int buff
*/
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;
@@ -141,7 +163,26 @@ static int header_check_id3(const unsigned char *buffer, const unsigned int buff
}
return 0;
}
+#endif
+#ifndef MAIN_id3
+/*@
+ @ requires buffer_size >= 6;
+ @ 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_mp3.extension);
+ @ 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->file_check == &file_check_size);
+ @ 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 == \null);
+ @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->data_check == \null);
+ @*/
static int header_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
unsigned int potential_frame_offset=0;
@@ -165,12 +206,16 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
return 0;
if(file_recovery->file_stat!=NULL)
{
- if(file_recovery->file_stat->file_hint==&file_hint_mp3 ||
- file_recovery->file_stat->file_hint==&file_hint_mkv)
+ if(file_recovery->file_stat->file_hint==&file_hint_mp3
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
+ || file_recovery->file_stat->file_hint==&file_hint_mkv
+#endif
+ )
{
header_ignored(file_recovery_new);
return 0;
}
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
/* 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])
@@ -178,7 +223,12 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
}
+ /*@ assert nbr == 0; */
+ /*@
+ @ loop invariant 0 <= nbr <= potential_frame_offset <= 2048 + 8065;
+ @*/
while(potential_frame_offset+1 < buffer_size &&
potential_frame_offset+1 < 2048)
{
@@ -195,6 +245,8 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
unsigned int frameLengthInBytes=0;
if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
return 0;
+ /*@ assert 8 <= bit_rate <= 448; */
+ /*@ assert 8000 <= sample_rate <= 48000; */
if(mpeg_layer==MPEG_L3)
{
if(mpeg_version==MPEG_V1)
@@ -212,17 +264,24 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
#endif
if(frameLengthInBytes==0)
return 0;
+ /*@ assert 0 < frameLengthInBytes <= 8065; */
potential_frame_offset+=frameLengthInBytes;
+ /*@ assert potential_frame_offset > 0; */
nbr++;
}
}
if(nbr>1)
{
+ /*@ 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)
@@ -234,13 +293,25 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
}
return 0;
}
+#endif
+#ifndef MAIN_mp3
+/*@
+ @ requires buffer_size >= 32;
+ @ 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);
+ @*/
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)
{
- 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 - 1 ; */
if(buffer[i]==0)
{ /* Padding is present */
file_recovery->calculated_file_size++;
@@ -249,12 +320,29 @@ static data_check_t data_check_id3(const unsigned char *buffer, const unsigned i
{ /* 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);
+ 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->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;
}
+#endif
+/*@
+ @ requires buffer_size >= 32;
+ @ 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);
+ @*/
+ /* TODO: 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
@@ -265,7 +353,8 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
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,
@@ -290,6 +379,8 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
*/
if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
return DC_STOP;
+ /*@ assert 8 <= bit_rate <= 448; */
+ /*@ assert 8000 <= sample_rate <= 48000; */
if(mpeg_layer==MPEG_L3)
{
if(mpeg_version==MPEG_V1)
@@ -303,7 +394,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 +411,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 pos_lyrics > 0; */
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 pos_lyrics > 0; */
file_recovery->calculated_file_size+=pos_lyrics;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else
{
@@ -339,42 +436,64 @@ 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 MMT_size > 0; */
/*
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;
}
+/*@
+ @ requires needle_size > 0;
+ @ requires haystack_size > 0;
+ @ requires \valid_read(needle+(0..needle_size-1));
+ @ requires \valid_read(haystack+(0..haystack_size-1));
+ @ ensures \result == 0 || needle_size <= \result <= haystack_size;
+ @ assigns \nothing;
+ @*/
static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
{
unsigned int i;
if(haystack_size < needle_size)
return 0;
+ /*@ assert haystack_size >= needle_size; */
+ /*@
+ @ loop assigns i;
+ @ loop invariant 0 <= i <= haystack_size - needle_size + 1;
+ @ loop variant haystack_size - needle_size - i;
+ @*/
for(i=0; i <= haystack_size - needle_size; i++)
if(memcmp(&haystack[i],needle,needle_size)==0)
return (i+needle_size);
return 0;
}
+/*@
+ @ requires buffer_size > 0;
+ @ requires i <= buffer_size;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size)
{
/*
@@ -397,12 +516,12 @@ static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i
*/
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";
+ 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)
return 0;
+ /*@ assert i + sizeof(mm_header) <= buffer_size; */
if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header
{
size=256;
@@ -412,61 +531,90 @@ static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i
else
{
/* 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( memcmp(&buffer[i]," ",4)!=0 &&
+ memcmp(&buffer[i],"bmp ",4)!=0 &&
+ memcmp(&buffer[i],"jpg ",4)!=0)
return 0;
/* log_info("search_MMT: image extension present\n"); */
}
-/* 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"); */
- return 0;
+ {
+ const unsigned int tmp=i+size;
+ const uint32_t *image_size_ptr;
+ uint32_t image_size;
+ if(tmp+8>buffer_size)
+ return 0;
+ /*@ assert tmp + 8 <= buffer_size; */
+ image_size_ptr = (const uint32_t *)&buffer[tmp+4];
+ image_size = le32(*image_size_ptr);
+ /* Check if the image size */
+ if(image_size > 10 * 1024 * 1024)
+ return 0;
+ /*@ assert image_size <= 10 * 1024 * 1024; */
+ /* Image binary */
+ size+=8+image_size;
}
- if(memcmp(&buffer[i+size], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
{
- /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
- return 0;
+ const unsigned int tmp=i+size;
+ /* check null padding + version_info */
+ if(tmp+sizeof(mm_pad_version_info)>buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch Tag 1\n"); */
+ return 0;
+ }
+ /*@ assert tmp + sizeof(mm_pad_version_info) <= buffer_size; */
+ if(memcmp(&buffer[tmp], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
+ {
+ /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
+ return 0;
+ }
}
size+=4+256; /* padding + version_info */
size+=20; /* data offset */
- /* 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;
+ {
+ const unsigned int tmp=i+size;
+ /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */
+ if(tmp+8132+sizeof(mm_footer) > buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch 2\n"); */
+ return 0;
+ }
+ /*@ assert tmp + 8132 + sizeof(mm_footer) <= buffer_size; */
+ if( memcmp(&buffer[tmp+7868], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7868], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7868;
+ else if(memcmp(&buffer[tmp+7936], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7936], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7936;
+ else if(memcmp(&buffer[tmp+8004], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8004], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=8004;
+ else if(memcmp(&buffer[tmp+8132], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8132], mm_footer_tag, sizeof(mm_footer_tag)-1)==0)
+ size+=8132;
+ else
+ {
+ /* log_trace("search_MMT: no mm_footer present\n"); */
+ return 0;
+ }
}
- 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
{
- /* log_trace("search_MMT: no mm_footer present\n"); */
- return 0;
+ const unsigned int tmp=i+size;
+ if(tmp + sizeof(mm_footer) > buffer_size)
+ return 0;
+ /*@ assert tmp + sizeof(mm_footer) <= buffer_size; */
+ /* dump_log(&buffer[tmp], 16); */
+ if(memcmp(&buffer[tmp],mm_footer, sizeof(mm_footer)-1)==0)
+ size+=48; /* footer */
+ else
+ size+=0x80; /* TAG footer */
}
- /* 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);
}
+/*@
+ @ 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};
@@ -475,11 +623,197 @@ static void register_header_check_mp3(file_stat_t *file_stat)
static const unsigned char mpeg2_L3_header2[2]= {0xFF, 0xF3};
static const unsigned char mpeg25_L3_header1[2]={0xFF, 0xE2};
static const unsigned char mpeg25_L3_header2[2]={0xFF, 0xE3};
+#ifndef MAIN_mp3
register_header_check(0, "ID3", 3, &header_check_id3, file_stat);
+#endif
+#ifndef MAIN_id3
register_header_check(0, mpeg1_L3_header1, sizeof(mpeg1_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg1_L3_header2, sizeof(mpeg1_L3_header2), &header_check_mp3, file_stat);
register_header_check(0, mpeg2_L3_header1, sizeof(mpeg2_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg2_L3_header2, sizeof(mpeg2_L3_header2), &header_check_mp3, file_stat);
register_header_check(0, mpeg25_L3_header1, sizeof(mpeg25_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg25_L3_header2, sizeof(mpeg25_L3_header2), &header_check_mp3, file_stat);
+#endif
+}
+
+#ifdef MAIN_id3
+#define BLOCKSIZE 65536u
+int main()
+{
+ 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; */
+ {
+ 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);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&file_recovery_new);
+ }
+ return 0;
}
+#elif defined(MAIN_mp3)
+#define BLOCKSIZE 65536u
+int main()
+{
+ 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;
+ file_hint_mp3.register_header_check(&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; */
+ 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);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&file_recovery_new);
+ }
+ 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_pf.c b/src/file_pf.c
index 8aab2f1..787a8a6 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,6 +57,10 @@ struct pf_header
uint32_t unknown2;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
static void file_rename_pf(file_recovery_t *file_recovery)
{
FILE *file;
@@ -69,20 +76,129 @@ static void file_rename_pf(file_recovery_t *file_recovery)
file_rename_unicode(file_recovery, &hdr.name, sizeof(hdr.name), 0, "pf", 0);
}
+/*@
+ @ 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 separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_pf.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= sizeof(struct pf_header));
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename==&file_rename_pf);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check==&data_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check==&file_check_size);
+ @*/
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_sig.c b/src/file_sig.c
index 7908d3c..e75a2e8 100644
--- a/src/file_sig.c
+++ b/src/file_sig.c
@@ -42,7 +42,6 @@
#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 +59,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 +106,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 +209,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 +401,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
{
@@ -416,5 +447,3 @@ static void register_header_check_sig(file_stat_t *file_stat)
}
free(buffer);
}
-
-
diff --git a/src/file_tiff.c b/src/file_tiff.c
index 02d0bf7..0262457 100644
--- a/src/file_tiff.c
+++ b/src/file_tiff.c
@@ -38,6 +38,9 @@
#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);
@@ -50,6 +53,8 @@ const file_hint_t file_hint_tiff= {
.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,53 @@ 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;
+ if(buffer_size < sizeof(TIFFHeader))
+ return 0;
+#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)); */
+ if(buffer_size < sizeof(TIFFHeader) || buffer_size < 19)
+ return (time_t)0;
+ /*@ assert buffer_size >= sizeof(TIFFHeader); */
/* 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..b030da2 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,83 @@ 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 buffer_size >= sizeof(TIFFHeader);
+ @ 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);
+ @ ensures \valid_read(buffer+(0..buffer_size-1));
+ @*/
+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);
+ @ ensures \valid_read(buffer+(0..tiff_size-1));
+ @*/
+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);
+ @ 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 \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_le);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(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);
+ @ ensures \valid_read(buffer+(0..tiff_size-1));
+ @*/
+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 \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(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..8ad2bc5 100644
--- a/src/file_tiff_be.c
+++ b/src/file_tiff_be.c
@@ -38,105 +38,201 @@
#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));
+ @ requires \valid(potential_error);
+ @ requires \separated(potential_error, buffer+(..));
+ @
+ */
+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 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=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;
+ unsigned int offset_ptr_offset_ifd1;
+ /*@ 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; */
+ /*@ 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)
+ {
+ const unsigned char *ptr_ifd0;
+ const struct ifd_header *ifd0;
+ ptr_ifd0=buffer+offset_ifd0;
+ /*@ assert \valid_read(ptr_ifd0 + (0 .. sizeof(struct ifd_header)-1)); */
+ ifd0=(const struct ifd_header *)ptr_ifd0;
+ /*@ assert \valid_read(ifd0); */
+ offset_ptr_offset_ifd1=offset_ifd0+2+be16(ifd0->nbr_fields);
+ }
+#ifndef MAIN_jpg
+ if(offset_ptr_offset_ifd1 > tiff_size-4)
+ return 0;
+ /*@ assert offset_ptr_offset_ifd1 + 4 <= tiff_size; */
{
/* 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);
+ /*@ assert \valid_read(buffer + (0 .. offset_ptr_offset_ifd1 + 4 - 1)); */
+ const unsigned char *ptr_offset_ifd1=&buffer[offset_ptr_offset_ifd1];
+ /*@ assert \valid_read(ptr_offset_ifd1 + (0 .. 4 - 1)); */
+ const uint32_t *ptr32_offset_ifd1=(const uint32_t *)ptr_offset_ifd1;
+ /*@ assert \valid_read(ptr32_offset_ifd1); */
+ const unsigned int offset_ifd1=be32(*ptr32_offset_ifd1);
+ if(offset_ifd1 > 0 && offset_ifd1 <= tiff_size - sizeof(struct ifd_header))
+ {
+ const unsigned int tmp=find_tag_from_tiff_header_be_aux(buffer, tiff_size, tag, potential_error, offset_ifd1);
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ if(tmp)
+ return tmp;
+ }
}
- return NULL;
+#endif
+ /*@ 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 +241,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 +260,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 +284,16 @@ 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;
+#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 +304,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 +326,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 +364,24 @@ 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)
+/*@
+ @ 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->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 +395,50 @@ 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;
#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 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++)
{
+ 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 +446,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)
@@ -353,29 +485,35 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break;
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
case TIFFTAG_SUBIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
#ifdef ENABLE_TIFF_MAKERNOTE
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 +521,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 +531,38 @@ 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
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= j <= nbr <=32;
+ @ loop variant nbr-j;
+ @*/
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)
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, be32(subifd_offsetp[j]), depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ 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);
+#endif
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -434,7 +580,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 +596,206 @@ 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)
+ if(data_read < 6)
+ return max_offset;
+ /*@ assert data_read >= 6; */
+#ifndef __FRAMAC__
+ if ( 2 + n*12 + 4 <= (unsigned int)data_read)
{
- 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)
- max_offset=new_offset;
+ /*@ assert n <= (data_read - 6) /12; */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)&entries[n];
+ if(be32(*tiff_next_diroff) > 0)
+ {
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, be32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
+#endif
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);
+ @*/
+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..f0f0c21 100644
--- a/src/file_tiff_le.c
+++ b/src/file_tiff_le.c
@@ -38,106 +38,202 @@
#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));
+ @ requires \valid(potential_error);
+ @ requires \separated(potential_error, buffer+(..));
+ @
+ */
+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;
+ unsigned int offset_ptr_offset_ifd1;
+ /*@ 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)
+ {
+ const unsigned char *ptr_ifd0;
+ const struct ifd_header *ifd0;
+ ptr_ifd0=buffer+offset_ifd0;
+ /*@ assert \valid_read(ptr_ifd0 + (0 .. sizeof(struct ifd_header)-1)); */
+ ifd0=(const struct ifd_header *)ptr_ifd0;
+ /*@ assert \valid_read(ifd0); */
+ offset_ptr_offset_ifd1=offset_ifd0+2+le16(ifd0->nbr_fields);
+ }
+ if(offset_ptr_offset_ifd1 > tiff_size-4)
+ return 0;
+ /*@ assert offset_ptr_offset_ifd1 + 4 <= tiff_size; */
{
/* 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);
+ /*@ assert \valid_read(buffer + (0 .. offset_ptr_offset_ifd1 + 4 - 1)); */
+ const unsigned char *ptr_offset_ifd1=&buffer[offset_ptr_offset_ifd1];
+ /*@ assert \valid_read(ptr_offset_ifd1 + (0 .. 4 - 1)); */
+ const uint32_t *ptr32_offset_ifd1=(const uint32_t *)ptr_offset_ifd1;
+ /*@ assert \valid_read(ptr32_offset_ifd1); */
+ const unsigned int offset_ifd1=le32(*ptr32_offset_ifd1);
+ if(offset_ifd1 > 0 && offset_ifd1 <= tiff_size - sizeof(struct ifd_header))
+ {
+ const unsigned int tmp=find_tag_from_tiff_header_le_aux(buffer, tiff_size, tag, potential_error, offset_ifd1);
+ /*@ assert \valid_read(buffer+(0..tiff_size-1)); */
+ if(tmp)
+ return tmp;
+ }
}
- 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 +242,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 +261,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 +285,16 @@ 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;
+#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 +305,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 +327,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 +365,24 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
return max_offset;
}
#endif
+#endif
-uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+#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 \separated(&errno, 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 +396,50 @@ 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;
#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 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++)
{
+ 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 +447,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)
@@ -354,36 +487,42 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break;
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
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)
max_offset=tmp;
}
+#ifndef __FRAMAC__
else
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
#ifdef ENABLE_TIFF_MAKERNOTE
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 +530,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 +540,38 @@ 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
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= j <= nbr <=32;
+ @ loop variant nbr-j;
+ @*/
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)
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, le32(subifd_offsetp[j]), depth+1, 0);
+ /*@ assert \valid(fr->handle); */
+ 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);
+#endif
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -442,7 +589,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 +605,217 @@ 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)
+ if(data_read < 6)
+ return max_offset;
+ /*@ assert data_read >= 6; */
+#ifndef __FRAMAC__
+ if ( 2 + n*12 + 4 <= (unsigned int)data_read)
{
- 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)
- max_offset=new_offset;
+ /*@ assert n <= (data_read - 6) /12; */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)&entries[n];
+ if(le32(*tiff_next_diroff) > 0)
+ {
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, le32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
+#endif
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)
{
- 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;
+ 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 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..19ea286 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"
@@ -118,6 +119,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 */
@@ -771,10 +777,31 @@ static data_check_t data_check_xml_utf8(const unsigned char *buffer, const unsig
static int header_check_xml_utf8(const unsigned char *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 *tmp;
+ /* buffer may not be null-terminated */
+ char *buf=(char *)MALLOC(buffer_size+1);
+ memcpy(buf, buffer, buffer_size);
+ buf[buffer_size]='\0';
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_xml_utf8;
- file_recovery_new->extension="xml";
+ file_recovery_new->extension=NULL;
+ tmp=strchr(buf,'<');
+ while(tmp!=NULL && file_recovery_new->extension==NULL)
+ {
+ if(strncasecmp(tmp, "<Archive name=\"Root\">", 8)==0)
+ {
+ /* Grasshopper archive */
+ file_recovery_new->extension="ghx";
+ }
+ tmp++;
+ tmp=strchr(tmp,'<');
+ }
+ if(file_recovery_new->extension==NULL)
+ {
+ file_recovery_new->extension="xml";
+ }
file_recovery_new->file_check=&file_check_xml;
+ free(buf);
return 1;
}
@@ -1090,7 +1117,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- /* Dos/Windows bath */
+ /* Dos/Windows batch */
file_recovery_new->extension="bat";
return 1;
}
@@ -1135,6 +1162,15 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
res=(const unsigned char *)memchr(haystack,'\n',ll);
if(res!=NULL)
ll=res-haystack;
+ if(td_memmem(haystack, ll, "groovy", 6) != NULL)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /* Groovy script */
+ file_recovery_new->extension="groovy";
+ return 1;
+ }
if(td_memmem(haystack, ll, "perl", 4) != NULL)
{
reset_file_recovery(file_recovery_new);
@@ -1144,6 +1180,15 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->extension="pl";
return 1;
}
+ if(td_memmem(haystack, ll, "php", 3) != NULL)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /* PHP script */
+ file_recovery_new->extension="php";
+ return 1;
+ }
if(td_memmem(haystack, ll, "python", 6) != NULL)
{
reset_file_recovery(file_recovery_new);
@@ -1209,7 +1254,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- /* Dos/Windows bath */
+ /* Dos/Windows batch */
file_recovery_new->extension="bat";
return 1;
}
@@ -1470,6 +1515,7 @@ static void register_header_check_fasttxt(file_stat_t *file_stat)
const txt_header_t *header=&fasttxt_headers[0];
while(header->len > 0)
{
+ assert(strlen(header->string) == header->len);
register_header_check(0, header->string, header->len, &header_check_fasttxt, file_stat);
header++;
}
diff --git a/src/file_wdp.c b/src/file_wdp.c
index 7948cc6..0be5694 100644
--- a/src/file_wdp.c
+++ b/src/file_wdp.c
@@ -51,8 +51,8 @@ static int header_check_wdp(const unsigned char *buffer, const unsigned int buff
return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="wdp";
- 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_x3f.c b/src/file_x3f.c
index 896ac1a..0cba13f 100644
--- a/src/file_x3f.c
+++ b/src/file_x3f.c
@@ -31,6 +31,7 @@
#include "filegen.h"
#include "common.h"
+extern const file_hint_t file_hint_x3i;
static void register_header_check_x3f(file_stat_t *file_stat);
static int header_check_x3f(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
@@ -63,8 +64,15 @@ static int header_check_x3f(const unsigned char *buffer, const unsigned int buff
return 0;
if(rotation!=0 && rotation!=90 && rotation!=180 && rotation!=270)
return 0;
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_x3i &&
+ safe_header_only==0)
+ {
+ return 0;
+ }
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_x3f.extension;
+ file_recovery_new->min_filesize=1024;
return 1;
}
diff --git a/src/file_x3i.c b/src/file_x3i.c
index b4b9b93..c1a001f 100644
--- a/src/file_x3i.c
+++ b/src/file_x3i.c
@@ -45,6 +45,7 @@ static int header_check_x3i(const unsigned char *buffer, const unsigned int buff
{
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_x3i.extension;
+ file_recovery_new->min_filesize=1024;
return 1;
}
diff --git a/src/file_zip.c b/src/file_zip.c
index ab25947..417bd3d 100644
--- a/src/file_zip.c
+++ b/src/file_zip.c
@@ -22,9 +22,6 @@
Information about ZIP file format: http://www.info-zip.org/doc/appnote-iz-latest.zip
*/
-/* Abolutely required for the zip64 stuff */
-/* #define _FILE_OFFSET_BITS 64 */
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -39,10 +36,15 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
/* #define DEBUG_ZIP */
+#ifndef MAIN_zip
extern const file_hint_t file_hint_doc;
+#endif
static void register_header_check_zip(file_stat_t *file_stat);
static int header_check_zip(const unsigned char *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_zip(file_recovery_t *file_recovery);
@@ -106,8 +108,13 @@ struct zip64_extra_entry
typedef struct zip_file_entry zip_file_entry_t;
typedef struct zip64_extra_entry zip64_extra_entry_t;
-static uint32_t expected_compressed_size=0;
+static uint64_t expected_compressed_size=0;
+/*@
+ @ requires \valid(f);
+ @ requires 0 < size <= 4096;
+ @ requires \valid_read((const char *)needle + (0 .. size-1));
+ @*/
static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size)
{
char *buffer =(char *)MALLOC(4096);
@@ -118,26 +125,39 @@ static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size
while (!feof(f))
{
- int count = 0;
- unsigned int left;
- const unsigned int read_size= fread(buffer, 1, 4096, f);
- left = read_size;
-
- while (left>=size)
+ const size_t read_size=fread(buffer, 1, 4096, f);
+ if(read_size <= 0 || total > (0x7fffffffffffffff - 4096))
+ {
+ free(buffer);
+ return -1;
+ }
+ /*@ assert 0 < read_size <= 4096; */
+ /*@ assert total <= 0x8000000000000000 - 4096; */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(buffer, 4096);
+#endif
+ if(read_size >= size)
{
- if (buffer[count]==*(const char *)needle && memcmp(buffer+count, needle, size)==0)
+ /*@ assert read_size >= size; */
+ unsigned int count = 0;
+ /*@
+ @ loop invariant 0 <= count <= read_size - size + 1;
+ @ loop variant read_size - size - count;
+ @*/
+ for(count=0; count <= read_size - size; count++)
{
- free(buffer);
- if(my_fseek(f, (off_t)count-read_size, SEEK_CUR)<0)
+ if (buffer[count]==*(const char *)needle && memcmp(buffer+count, needle, size)==0)
{
- log_trace("zip: file_get_pos count-read failed\n");
- return -1;
+ free(buffer);
+ if(my_fseek(f, (off_t)count-(off_t)read_size, SEEK_CUR)<0)
+ {
+ log_trace("zip: file_get_pos count-read failed\n");
+ return -1;
+ }
+ return total+count;
}
- return total;
}
- count++;
- total++;
- left--;
+ total+=count;
}
if(feof(f) || my_fseek(f, (off_t)1-size, SEEK_CUR)<0)
{
@@ -150,6 +170,173 @@ static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size
return -1;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid(ext);
+ @ requires \valid(krita);
+ @ requires fr->file_size < 0x8000000000000000 - 65535;
+ @ requires 0 < len <= 65535;
+ @ ensures fr->file_size < 0x8000000000000000;
+ @ ensures \result == -1 || \result == 0;
+ @ ensures *krita==0 || *krita==19;
+ @*/
+static int zip_parse_file_entry_fn(file_recovery_t *fr, const char **ext, const unsigned int file_nbr, const zip_file_entry_t file, const uint64_t len, unsigned int *krita)
+{
+#ifdef __FRAMAC__
+ char *filename=(char *)MALLOC(65535+1);
+#else
+ char *filename=(char *)MALLOC(len+1);
+#endif
+ *krita=0;
+ if (fread(filename, len, 1, fr->handle) != 1)
+ {
+#ifdef DEBUG_ZIP
+ log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
+#endif
+ free(filename);
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(filename, len);
+#endif
+ fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
+ filename[len]='\0';
+ if(first_filename[0]=='\0')
+ {
+ const unsigned int len_tmp=(len<255?len:255);
+ strncpy(first_filename, filename, len_tmp);
+ first_filename[len_tmp]='\0';
+ }
+#ifdef DEBUG_ZIP
+ log_info("%s\n", filename);
+#endif
+ if(*ext==NULL)
+ {
+ static int msoffice=0;
+ static int sh3d=0;
+ static const char *ext_msoffice=NULL;
+ if(file_nbr==0)
+ {
+ msoffice=0;
+ sh3d=0;
+ ext_msoffice=NULL;
+ }
+ if(len==19 && memcmp(filename, "[Content_Types].xml", 19)==0)
+ msoffice=1;
+ else if(file_nbr==0)
+ {
+ if(len==8 && memcmp(filename, "mimetype", 8)==0 && le16(file.extra_length)==0)
+ {
+ unsigned char buffer[128];
+ const unsigned int compressed_size=le32(file.compressed_size);
+ const int to_read=(compressed_size < 128 ? compressed_size: 128);
+ if( fread(buffer, to_read, 1, fr->handle)!=1)
+ {
+#ifdef DEBUG_ZIP
+ log_trace("zip: Unexpected EOF in file_entry data: %u bytes expected\n",
+ compressed_size);
+#endif
+ free(filename);
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(buffer, 128);
+#endif
+ if (my_fseek(fr->handle, -to_read, SEEK_CUR) < 0)
+ {
+ log_info("fseek failed\n");
+ free(filename);
+ return -1;
+ }
+ if(compressed_size==16 && memcmp(buffer,"image/openraster",16)==0)
+ *ext="ora";
+ else if(compressed_size==20 && memcmp(buffer,"application/epub+zip",20)==0)
+ *ext="epub";
+ else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.calc",28)==0)
+ *ext="sxc";
+ else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.draw",28)==0)
+ *ext="sxd";
+ else if(compressed_size==31 && memcmp(buffer,"application/vnd.sun.xml.impress",31)==0)
+ *ext="sxi";
+ else if(compressed_size==30 && memcmp(buffer,"application/vnd.sun.xml.writer",30)==0)
+ *ext="sxw";
+ else if(compressed_size==39 && memcmp(buffer,"application/vnd.oasis.opendocument.text",39)==0)
+ *ext="odt";
+ else if(compressed_size==43 && memcmp(buffer,"application/vnd.oasis.opendocument.graphics",43)==0)
+ *ext="odg";
+ else if(compressed_size==46 && memcmp(buffer,"application/vnd.oasis.opendocument.spreadsheet",46)==0)
+ *ext="ods";
+ else if(compressed_size==47 && memcmp(buffer,"application/vnd.oasis.opendocument.presentation",47)==0)
+ *ext="odp";
+ else if(memcmp(buffer,"application/x-krita",19)==0)
+ {
+ *ext="kra";
+ *krita=19;
+ }
+ else
+ { /* default to writer */
+ *ext="sxw";
+ }
+ }
+ /* Zipped Keyhole Markup Language (KML) used by Google Earth */
+ else if(len==7 && memcmp(filename, "doc.kml", 7)==0)
+ *ext="kmz";
+ else if(len==4 && memcmp(filename, "Home", 4)==0)
+ sh3d=1;
+ /* Celtx, Screenwriting & Media Pre-production file */
+ else if(len==9 && memcmp(filename, "local.rdf", 9)==0)
+ *ext="celtx";
+ else if(len==13 && memcmp(filename, "document.json", 13)==0)
+ *ext="sketch";
+ }
+ else if(file_nbr==1 && sh3d==1)
+ {
+ if(len==1 && filename[0]=='0')
+ *ext="sh3d";
+ }
+ if(strncmp(filename, "word/", 5)==0)
+ ext_msoffice="docx";
+ else if(strncmp(filename, "xl/", 3)==0)
+ ext_msoffice="xlsx";
+ else if(strncmp(filename, "ppt/", 4)==0)
+ ext_msoffice="pptx";
+ else if(strncmp(filename, "visio/", 6)==0)
+ ext_msoffice="vsdx";
+ if(msoffice && ext_msoffice!=NULL)
+ *ext=ext_msoffice;
+ }
+ if(*ext==NULL)
+ {
+ /* iWork */
+ if(len==23 && memcmp(filename, "QuickLook/Thumbnail.jpg", 23)==0)
+ *ext="pages";
+ else if(len==20 && strncasecmp(filename, "META-INF/MANIFEST.MF", 20)==0)
+ *ext="jar";
+ else if(len==15 && strncasecmp(filename, "chrome.manifest", 15)==0)
+ *ext="xpi";
+ /* SMART Notebook */
+ else if(len==15 && memcmp(filename, "imsmanifest.xml", 15)==0)
+ *ext="notebook";
+ /* Apple Numbers */
+ else if(len==18 && memcmp(filename, "Index/Document.iwa", 18)==0)
+ *ext="numbers";
+ else if(len==19 && memcmp(filename, "AndroidManifest.xml", 19)==0)
+ *ext="apk";
+ else if(len==30 && memcmp(filename, "xsd/MindManagerApplication.xsd", 30)==0)
+ *ext="mmap";
+ }
+ free(filename);
+ return 0;
+}
+
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid(ext);
+ @ requires fr->file_size < 0x8000000000000000 + 4;
+ @*/
static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const unsigned int file_nbr)
{
zip_file_entry_t file;
@@ -163,6 +350,9 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&file, sizeof(file));
+#endif
fr->file_size += sizeof(file);
#ifdef DEBUG_ZIP
log_info("%u Comp=%u %u CRC32=0x%08X extra_length=%u ",
@@ -180,140 +370,20 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
if(fr->time < tmp)
fr->time=tmp;
}
+ if(fr->file_size + 65535 >= 0x8000000000000000)
+ {
+ return -1;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 65535; */
len = le16(file.filename_length);
if (len)
{
- char *filename=(char *)MALLOC(len+1);
- if (fread(filename, len, 1, fr->handle) != 1)
- {
-#ifdef DEBUG_ZIP
- log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
-#endif
- free(filename);
+ /*@ assert 0 < len <= 65535; */
+ if(zip_parse_file_entry_fn(fr, ext, file_nbr, file, len, &krita) < 0)
return -1;
- }
- fr->file_size += len;
- filename[len]='\0';
- if(first_filename[0]=='\0')
- {
- const unsigned int len_tmp=(len<255?len:255);
- strncpy(first_filename, filename, len_tmp);
- first_filename[len_tmp]='\0';
- }
-#ifdef DEBUG_ZIP
- log_info("%s\n", filename);
-#endif
- if(*ext==NULL)
- {
- static int msoffice=0;
- static int sh3d=0;
- static const char *ext_msoffice=NULL;
- if(file_nbr==0)
- {
- msoffice=0;
- sh3d=0;
- ext_msoffice=NULL;
- }
- if(len==19 && memcmp(filename, "[Content_Types].xml", 19)==0)
- msoffice=1;
- else if(file_nbr==0)
- {
- if(len==8 && memcmp(filename, "mimetype", 8)==0 && le16(file.extra_length)==0)
- {
- unsigned char buffer[128];
- const unsigned int compressed_size=le32(file.compressed_size);
- const int to_read=(compressed_size < 128 ? compressed_size: 128);
- if( fread(buffer, to_read, 1, fr->handle)!=1)
- {
-#ifdef DEBUG_ZIP
- log_trace("zip: Unexpected EOF in file_entry data: %u bytes expected\n",
- compressed_size);
-#endif
- free(filename);
- return -1;
- }
- if (my_fseek(fr->handle, -to_read, SEEK_CUR) < 0)
- {
- log_info("fseek failed\n");
- free(filename);
- return -1;
- }
- if(compressed_size==16 && memcmp(buffer,"image/openraster",16)==0)
- *ext="ora";
- else if(compressed_size==20 && memcmp(buffer,"application/epub+zip",20)==0)
- *ext="epub";
- else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.calc",28)==0)
- *ext="sxc";
- else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.draw",28)==0)
- *ext="sxd";
- else if(compressed_size==31 && memcmp(buffer,"application/vnd.sun.xml.impress",31)==0)
- *ext="sxi";
- else if(compressed_size==30 && memcmp(buffer,"application/vnd.sun.xml.writer",30)==0)
- *ext="sxw";
- else if(compressed_size==39 && memcmp(buffer,"application/vnd.oasis.opendocument.text",39)==0)
- *ext="odt";
- else if(compressed_size==43 && memcmp(buffer,"application/vnd.oasis.opendocument.graphics",43)==0)
- *ext="odg";
- else if(compressed_size==46 && memcmp(buffer,"application/vnd.oasis.opendocument.spreadsheet",46)==0)
- *ext="ods";
- else if(compressed_size==47 && memcmp(buffer,"application/vnd.oasis.opendocument.presentation",47)==0)
- *ext="odp";
- else if(memcmp(buffer,"application/x-krita",19)==0)
- {
- *ext="kra";
- krita=19;
- }
- else
- { /* default to writer */
- *ext="sxw";
- }
- }
- /* Zipped Keyhole Markup Language (KML) used by Google Earth */
- else if(len==7 && memcmp(filename, "doc.kml", 7)==0)
- *ext="kmz";
- else if(len==4 && memcmp(filename, "Home", 4)==0)
- sh3d=1;
- /* Celtx, Screenwriting & Media Pre-production file */
- else if(len==9 && memcmp(filename, "local.rdf", 9)==0)
- *ext="celtx";
- else if(len==13 && memcmp(filename, "document.json", 13)==0)
- *ext="sketch";
- }
- else if(file_nbr==1 && sh3d==1)
- {
- if(len==1 && filename[0]=='0')
- *ext="sh3d";
- }
- if(strncmp(filename, "word/", 5)==0)
- ext_msoffice="docx";
- else if(strncmp(filename, "xl/", 3)==0)
- ext_msoffice="xlsx";
- else if(strncmp(filename, "ppt/", 4)==0)
- ext_msoffice="pptx";
- else if(strncmp(filename, "visio/", 6)==0)
- ext_msoffice="vsdx";
- if(msoffice && ext_msoffice!=NULL)
- *ext=ext_msoffice;
- }
- if(*ext==NULL)
- {
- /* iWork */
- if(len==23 && memcmp(filename, "QuickLook/Thumbnail.jpg", 23)==0)
- *ext="pages";
- else if(len==20 && strncasecmp(filename, "META-INF/MANIFEST.MF", 20)==0)
- *ext="jar";
- else if(len==15 && strncasecmp(filename, "chrome.manifest", 15)==0)
- *ext="xpi";
- /* SMART Notebook */
- else if(len==15 && memcmp(filename, "imsmanifest.xml", 15)==0)
- *ext="notebook";
- else if(len==19 && memcmp(filename, "AndroidManifest.xml", 19)==0)
- *ext="apk";
- else if(len==30 && memcmp(filename, "xsd/MindManagerApplication.xsd", 30)==0)
- *ext="mmap";
- }
- free(filename);
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
#ifdef DEBUG_ZIP
log_info("\n");
#endif
@@ -321,12 +391,21 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
memset(&extra, 0, sizeof(extra));
if (len>0)
{
+ /*@ assert 0 < len <= 65535; */
+ if(fr->file_size + 65535 >= 0x8000000000000000)
+ {
+ return -1;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 65535; */
if (fread(&extra, sizeof(extra), 1, fr->handle) != 1)
{
#ifdef DEBUG_ZIP
log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
#endif
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&extra, sizeof(extra));
+#endif
if (my_fseek(fr->handle, fr->file_size, SEEK_SET) == -1 ||
my_fseek(fr->handle, len, SEEK_CUR) == -1)
{
@@ -336,11 +415,15 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
return -1;
}
fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
len = le32(file.compressed_size);
if(len==0xffffffff && le16(extra.tag)==1)
{
len = le64(extra.compressed_size);
+ if(len >= 0x8000000000000000)
+ return -1;
/* Avoid endless loop */
if( fr->file_size + len < fr->file_size)
return -1;
@@ -349,6 +432,10 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
len=krita;
if (len>0)
{
+ /*@ assert len < 0x8000000000000000; */
+ if(fr->file_size + len >= 0x8000000000000000)
+ return -1;
+ /*@ assert fr->file_size + len < 0x8000000000000000; */
if (my_fseek(fr->handle, len, SEEK_CUR) == -1)
{
#ifdef DEBUG_ZIP
@@ -359,8 +446,11 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
#ifdef DEBUG_ZIP
log_trace("zip: Data of length %lu\n", len);
#endif
+ /*@ assert fr->file_size + len < 0x8000000000000000; */
fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
expected_compressed_size=len;
if (file.has_descriptor && (le16(file.compression)==8 || le16(file.compression)==9))
{
@@ -379,13 +469,22 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
return -1;
if (pos > 0)
{
+ if(fr->file_size + pos > 0x7fffffffffffffff)
+ return -1;
fr->file_size += pos;
expected_compressed_size=pos;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_central_dir(file_recovery_t *fr)
{
zip_file_entry_t file;
@@ -414,6 +513,9 @@ static int zip_parse_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&file, sizeof(file));
+#endif
fr->file_size += sizeof(file);
#ifdef DEBUG_ZIP
log_trace("zip: Central dir with CRC 0x%08X\n", file.crc32);
@@ -426,6 +528,9 @@ static int zip_parse_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
/* Rest of the block - could attempt CRC check */
@@ -444,6 +549,12 @@ static int zip_parse_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires fr->file_size < 0x8000000000000000;
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip64_parse_end_central_dir(file_recovery_t *fr)
{
struct {
@@ -465,11 +576,16 @@ static int zip64_parse_end_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
if (dir.end_size > 0)
{
const uint64_t len = le64(dir.end_size);
+ if(len >= 0x8000000000000000 - sizeof(dir) - 4)
+ return -1;
/* Avoid endless loop */
if( fr->file_size + len <= fr->file_size)
return -1;
@@ -489,6 +605,11 @@ static int zip64_parse_end_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_end_central_dir(file_recovery_t *fr)
{
struct {
@@ -508,6 +629,9 @@ static int zip_parse_end_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
if (dir.comment_length)
@@ -528,6 +652,11 @@ static int zip_parse_end_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_data_desc(file_recovery_t *fr)
{
struct {
@@ -543,6 +672,9 @@ static int zip_parse_data_desc(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&desc, sizeof(desc));
+#endif
fr->file_size += sizeof(desc);
#ifdef DEBUG_ZIP
log_info("compressed_size=%u/%u uncompressed_size=%u CRC32=0x%08X\n",
@@ -556,6 +688,11 @@ static int zip_parse_data_desc(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_signature(file_recovery_t *fr)
{
uint16_t len;
@@ -567,6 +704,9 @@ static int zip_parse_signature(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&len, 2);
+#endif
fr->file_size += 2;
if (len)
@@ -585,6 +725,11 @@ static int zip_parse_signature(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip64_parse_end_central_dir_locator(file_recovery_t *fr)
{
struct {
@@ -600,10 +745,17 @@ static int zip64_parse_end_central_dir_locator(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&loc, sizeof(loc));
+#endif
fr->file_size += sizeof(loc);
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @*/
static void file_check_zip(file_recovery_t *fr)
{
const char *ext=NULL;
@@ -619,7 +771,13 @@ static void file_check_zip(file_recovery_t *fr)
uint64_t file_size_old;
uint32_t header;
int status;
-
+ if(file_nbr>=0xffffffff || fr->file_size >= 0x8000000000000000 - 4)
+ {
+ fr->offset_error = fr->file_size;
+ fr->file_size = 0;
+ return;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 4; */
if (fread(&header, 4, 1, fr->handle)!=1)
{
#ifdef DEBUG_ZIP
@@ -629,7 +787,9 @@ static void file_check_zip(file_recovery_t *fr)
fr->file_size=0;
return;
}
-
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 4);
+#endif
header = le32(header);
#ifdef DEBUG_ZIP
log_trace("Header 0x%08X at 0x%llx\n", header, (long long unsigned int)fr->file_size);
@@ -637,6 +797,7 @@ static void file_check_zip(file_recovery_t *fr)
#endif
fr->file_size += 4;
file_size_old=fr->file_size;
+ /*@ assert fr->file_size < 0x8000000000000000; */
switch (header)
{
@@ -687,6 +848,10 @@ static void file_check_zip(file_recovery_t *fr)
}
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_zip(file_recovery_t *file_recovery)
{
const char *ext=NULL;
@@ -707,6 +872,12 @@ static void file_rename_zip(file_recovery_t *file_recovery)
{
uint32_t header;
int status;
+ if(file_nbr>=0xffffffff || fr.file_size >= 0x8000000000000000 - 4)
+ {
+ fclose(fr.handle);
+ return;
+ }
+ /*@ assert fr.file_size < 0x8000000000000000 - 4; */
if (fread(&header, 4, 1, fr.handle)!=1)
{
@@ -716,6 +887,9 @@ static void file_rename_zip(file_recovery_t *file_recovery)
fclose(fr.handle);
return;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 4);
+#endif
header = le32(header);
#ifdef DEBUG_ZIP
@@ -788,6 +962,19 @@ static void file_rename_zip(file_recovery_t *file_recovery)
}
}
+/*@
+ @ requires buffer_size >= 85;
+ @ 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->min_filesize == 21);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_zip || file_recovery_new->file_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_zip || file_recovery_new->file_rename == \null);
+ @*/
static int header_check_zip(const unsigned char *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 zip_file_entry_t *file=(const zip_file_entry_t *)&buffer[4];
@@ -795,12 +982,14 @@ static int header_check_zip(const unsigned char *buffer, const unsigned int buff
#ifdef DEBUG_ZIP
log_trace("header_check_zip\n");
#endif
+#ifndef MAIN_zip
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_doc)
{
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
/* A zip file begins by ZIP_FILE_ENTRY, this signature can also be
* found for each compressed file */
if(file_recovery->file_stat!=NULL &&
@@ -876,6 +1065,18 @@ static int header_check_zip(const unsigned char *buffer, const unsigned int buff
return 1;
}
+/*@
+ @ requires buffer_size >= 85;
+ @ 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 == 1;
+ @ ensures file_recovery_new->file_check == &file_check_zip;
+ @ ensures file_recovery_new->extension == file_hint_zip.extension;
+ @*/
static int header_check_winzip(const unsigned char *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);
@@ -884,20 +1085,109 @@ static int header_check_winzip(const unsigned char *buffer, const unsigned int b
return 1;
}
+/*@
+ @ requires haystack_size > 0;
+ @ requires needle_size > 0;
+ @ requires \valid_read(haystack + (0 .. haystack_size-1));
+ @ requires \valid_read(needle + (0 .. needle_size-1));
+ @ assigns \nothing;
+ @ ensures \result <= haystack_size;
+ @*/
static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
{
unsigned int i;
if(haystack_size < needle_size)
return 0;
+ /*@
+ @ loop invariant 0 <= i <= haystack_size - needle_size + 1;
+ @ loop assigns i;
+ @ loop variant haystack_size - needle_size - i;
+ @*/
for(i=0; i <= haystack_size - needle_size; i++)
if(memcmp(&haystack[i],needle,needle_size)==0)
return (i+needle_size);
return 0;
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_zip(file_stat_t *file_stat)
{
static const unsigned char zip_header2[8] = { 'P', 'K', '0', '0', 'P', 'K', 0x03, 0x04}; /* WinZIPv8-compressed files. */
register_header_check(0, zip_header,sizeof(zip_header), &header_check_zip, file_stat);
register_header_check(0, zip_header2,sizeof(zip_header2), &header_check_winzip, file_stat);
}
+
+#if defined(MAIN_zip)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.zip";
+ 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);
+ /*@ 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_zip;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_zip(&file_stats);
+ if(header_check_zip(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.min_filesize == 21; */
+ /*@ assert file_recovery_new.file_check == &file_check_zip || file_recovery_new.file_check == \null; */
+ /*@ 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 */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_zip(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");
+ if(file_recovery_new.handle!=NULL && file_recovery_new.file_check !=NULL)
+ {
+ /*@ assert file_recovery_new.file_check == &file_check_zip; */
+ file_check_zip(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert file_recovery_new.file_rename == &file_rename_zip; */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_zip(&file_recovery_new);
+ }
+ return 0;
+}
+#endif
diff --git a/src/filegen.c b/src/filegen.c
index f48f21d..c197b5e 100644
--- a/src/filegen.c
+++ b/src/filegen.c
@@ -38,7 +38,6 @@
#include "types.h"
#include "common.h"
#include "filegen.h"
-#include "photorec.h"
#include "log.h"
static file_check_t file_check_plist={
@@ -66,7 +65,7 @@ static int file_check_cmp(const struct td_list_head *a, const struct td_list_hea
res=memcmp(fc_a->value,fc_b->value, (fc_a->length<=fc_b->length?fc_a->length:fc_b->length));
if(res!=0)
return res;
- return fc_b->length-fc_a->length;
+ return (int)fc_b->length-(int)fc_a->length;
}
static void file_check_add_tail(file_check_t *file_check_new, file_check_list_t *pos)
@@ -98,12 +97,12 @@ void register_header_check(const unsigned int offset, const void *value, const u
static void index_header_check_aux(file_check_t *file_check_new)
{
- struct td_list_head *tmp;
- td_list_for_each(tmp, &file_check_list.list)
+ if(file_check_new->length>0)
{
- file_check_list_t *pos=td_list_entry(tmp, file_check_list_t, list);
- if(file_check_new->length>0)
+ struct td_list_head *tmp;
+ td_list_for_each(tmp, &file_check_list.list)
{
+ file_check_list_t *pos=td_list_entry(tmp, file_check_list_t, list);
if(pos->offset >= file_check_new->offset &&
pos->offset < file_check_new->offset+file_check_new->length)
{
@@ -237,7 +236,12 @@ void file_search_footer(file_recovery_t *file_recovery, const void*footer, const
}
#if 0
-void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
+static void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length)
{
const unsigned int read_size=4096;
unsigned char*buffer;
@@ -317,7 +321,6 @@ void reset_file_recovery(file_recovery_t *file_recovery)
file_recovery->file_size=0;
file_recovery->location.list.prev=&file_recovery->location.list;
file_recovery->location.list.next=&file_recovery->location.list;
- file_recovery->location.start=0;
file_recovery->location.end=0;
file_recovery->location.data=0;
file_recovery->extension=NULL;
@@ -330,7 +333,6 @@ void reset_file_recovery(file_recovery_t *file_recovery)
file_recovery->offset_ok=0;
file_recovery->checkpoint_status=0;
file_recovery->checkpoint_offset=0;
-// file_recovery->blocksize=512;
file_recovery->flags=0;
file_recovery->extra=0;
}
@@ -368,9 +370,77 @@ file_stat_t * init_file_stats(file_enable_t *files_enable)
return file_stats;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ /* new_filename is large enough to avoid a buffer overflow */
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=NULL;
+ char *dst;
+ char *directory_sep;
+ int len;
+ len=strlen(src)+1;
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ new_filename=(char*)MALLOC(len);
+ dst=new_filename;
+ directory_sep=new_filename;
+ while(*src!='\0')
+ {
+ if(*src=='/')
+ {
+ directory_sep=dst;
+ ext=NULL;
+ }
+ if(*src=='.')
+ ext=src;
+ *dst++ = *src++;
+ }
+ *dst='\0';
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ if(ext!=NULL)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ }
+ *dst='\0';
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ if(strlen(new_filename)<sizeof(file_recovery->filename))
+ {
+ strcpy(file_recovery->filename, new_filename);
+ }
+ free(new_filename);
+ return 0;
+}
+
/* The original filename begins at offset in buffer and is null terminated */
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
+ /* TODO: make the code from frama-c friendly */
+#ifndef __FRAMAC__
/* new_filename is large enough to avoid a buffer overflow */
char *new_filename;
const char *src=file_recovery->filename;
@@ -475,19 +545,75 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
strcpy(file_recovery->filename, new_filename);
}
free(new_filename);
+#endif
+ return 0;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_unicode_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=src;
+ char *dst;
+ char *directory_sep;
+ unsigned int len=strlen(file_recovery->filename)+1;
+ /*@ assert len < sizeof(file_recovery->filename); */
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ if(len > sizeof(file_recovery->filename))
+ return -1;
+ new_filename=(char*)MALLOC(len);
+ strcpy(new_filename, (char *)&file_recovery->filename);
+ directory_sep=strrchr(file_recovery->filename, '/');
+ ext=strrchr(file_recovery->filename, '.');
+ /*@ assert directory_sep != \null; */
+#if 1
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ *dst='\0';
+#endif
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ strcpy(file_recovery->filename, new_filename);
+ free(new_filename);
return 0;
}
/* The original filename begins at offset in buffer and is null terminated */
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
+ /* TODO: make the code from frama-c friendly */
+#ifndef __FRAMAC__
/* new_filename is large enough to avoid a buffer overflow */
char *new_filename;
const char *src=file_recovery->filename;
@@ -585,18 +711,25 @@ int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, cons
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename_unicode(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_unicode_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
strcpy(file_recovery->filename, new_filename);
}
free(new_filename);
+#endif
return 0;
}
static uint64_t offset_skipped_header=0;
+void header_ignored_cond_reset(uint64_t start, uint64_t end)
+{
+ if(start <= offset_skipped_header && offset_skipped_header <= end)
+ offset_skipped_header=0;
+}
+
/* 0: file_recovery is bad *
* 1: file_recovery is ok */
int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new)
@@ -612,13 +745,15 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
}
if(file_recovery->handle==NULL)
{
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
+ {
offset_skipped_header=file_recovery_new->location.start;
+ }
return 0;
}
memcpy(&fr_test, file_recovery, sizeof(fr_test));
-#ifdef HAVE_FTELLO
+#if defined(HAVE_FTELLO) && !defined(__FRAMAC__)
if((offset=ftello(file_recovery->handle)) < 0)
offset=ftell(file_recovery->handle);
#else
@@ -626,15 +761,17 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
#endif
assert(offset >= 0);
file_recovery->file_check(&fr_test);
- if(fr_test.file_size>0)
- return 1;
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0)
{
log_error("BUG in header_ignored_adv: my_fseek() failed\n");
return 1;
}
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(fr_test.file_size>0)
+ return 1;
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
+ {
offset_skipped_header=file_recovery_new->location.start;
+ }
return 0;
}
@@ -645,7 +782,7 @@ void header_ignored(const file_recovery_t *file_recovery_new)
offset_skipped_header=0;
return ;
}
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
offset_skipped_header=file_recovery_new->location.start;
}
@@ -669,7 +806,7 @@ void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **cur
if(file_space->start < prev_location)
break;
}
-#ifdef DEBUG_HEADER_CHECK
+#ifdef DEBUG_PREV_LOCATION
log_info("get_prev_location_smart: reset offset_skipped_header=%llu, offset=%llu\n",
(long long unsigned)(offset_skipped_header/512),
(long long unsigned)(*offset/512));
@@ -682,24 +819,25 @@ void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **cur
offset_skipped_header=0;
return;
}
+ *current_search_space=file_space;
if(file_space->start < prev_location || file_space->start < offset_skipped_header)
{
-#ifdef DEBUG_HEADER_CHECK
+#ifdef DEBUG_PREV_LOCATION
log_info("get_prev_location_smart: file_space->start < prev_location=%llu (in 512-bytes sectors), offset=%llu\n",
(long long unsigned)(prev_location/512),
(long long unsigned)(*offset/512));
#endif
+ *offset=offset_skipped_header;
offset_skipped_header=0;
return ;
}
- *current_search_space=file_space;
*offset=file_space->start;
}
}
int my_fseek(FILE *stream, off_t offset, int whence)
{
-#if defined(HAVE_FSEEKO) && !defined(__MINGW32__) && !defined(__ARM_EABI__)
+#if defined(HAVE_FSEEKO) && !defined(__MINGW32__) && !defined(__ARM_EABI__) && !defined(__FRAMAC__)
{
int res;
if((res=fseeko(stream, offset, whence))>=0)
@@ -725,7 +863,7 @@ time_t get_time_from_YYMMDDHHMMSS(const char *date_asc)
return mktime(&tm_time);
}
-time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const char *date_asc)
+time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const unsigned char *date_asc)
{
struct tm tm_time;
if(memcmp(date_asc, "0000", 4)==0)
diff --git a/src/filegen.h b/src/filegen.h
index af8e793..31aabfa 100644
--- a/src/filegen.h
+++ b/src/filegen.h
@@ -119,30 +119,181 @@ typedef struct
#define NL_BARECR (1 << 2)
void free_header_check(void);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode);
+
+/*@
+ @ requires \valid(handle);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const unsigned int footer_length);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
void file_search_footer(file_recovery_t *file_recovery, const void*footer, const unsigned int footer_length, const unsigned int extra_length);
-void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length);
-void del_search_space(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end);
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ assigns \nothing;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
data_check_t data_check_size(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size(file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size_min(file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size_max(file_recovery_t *file_recovery);
+
+/*@
+ requires \valid(file_recovery);
+ ensures file_recovery->filename[0]=='\0';
+ ensures file_recovery->time==0;
+ ensures file_recovery->file_stat==\null;
+ ensures file_recovery->handle==\null;
+ ensures file_recovery->file_size==0;
+ ensures file_recovery->location.list.prev==&file_recovery->location.list;
+ ensures file_recovery->location.list.next==&file_recovery->location.list;
+ ensures file_recovery->location.end==0;
+ ensures file_recovery->location.data==0;
+ ensures file_recovery->extension==\null;
+ ensures file_recovery->min_filesize==0;
+ ensures file_recovery->calculated_file_size==0;
+ ensures file_recovery->data_check==\null;
+ ensures file_recovery->file_check==\null;
+ ensures file_recovery->file_rename==\null;
+ ensures file_recovery->offset_error==0;
+ ensures file_recovery->offset_ok==0;
+ ensures file_recovery->checkpoint_status==0;
+ ensures file_recovery->checkpoint_offset==0;
+ ensures file_recovery->flags==0;
+ ensures file_recovery->extra==0;
+ assigns file_recovery->filename[0];
+ assigns file_recovery->time;
+ assigns file_recovery->file_stat;
+ assigns file_recovery->handle;
+ assigns file_recovery->file_size;
+ assigns file_recovery->location.list.prev;
+ assigns file_recovery->location.list.next;
+ assigns file_recovery->location.end;
+ assigns file_recovery->location.data;
+ assigns file_recovery->extension;
+ assigns file_recovery->min_filesize;
+ assigns file_recovery->calculated_file_size;
+ assigns file_recovery->data_check;
+ assigns file_recovery->file_check;
+ assigns file_recovery->file_rename;
+ assigns file_recovery->offset_error;
+ assigns file_recovery->offset_ok;
+ assigns file_recovery->checkpoint_status;
+ assigns file_recovery->checkpoint_offset;
+ assigns file_recovery->flags;
+ assigns file_recovery->extra;
+*/
void reset_file_recovery(file_recovery_t *file_recovery);
+
+/*@
+ @ requires 0 < length <= 4096;
+ @ requires \valid_read((char *)value+(0..length-1));
+ @ requires \valid_function(header_check);
+ @ requires \valid(file_stat);
+ @*/
void register_header_check(const unsigned int offset, const void *value, const unsigned int length, int (*header_check)(const unsigned char *buffer, const unsigned int buffer_size,
const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new),
file_stat_t *file_stat);
+
+/*@
+ @ requires \valid(files_enable);
+ @*/
file_stat_t * init_file_stats(file_enable_t *files_enable);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
+void header_ignored_cond_reset(uint64_t start, uint64_t end);
+
+/*@
+ @ requires file_recovery_new==\null || \valid_read(file_recovery_new);
+ @*/
void header_ignored(const file_recovery_t *file_recovery_new);
+
+/*@
+ @ requires separation: \separated(file_recovery, file_recovery_new, &errno);
+ @ requires \valid_read(file_recovery);
+ @ requires \valid_read(file_recovery_new);
+ @ requires \initialized(&file_recovery->file_check);
+ @ requires \initialized(&file_recovery->handle);
+ @ ensures \result == 0 || \result == 1;
+ @*/
int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new);
+
+/*@
+ requires valid_stream: \valid(stream);
+ requires whence_enum: whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END;
+ requires \separated(&errno, stream);
+ assigns *stream \from *stream, indirect:offset, indirect:whence;
+ assigns \result, errno \from indirect:*stream, indirect:offset,
+ indirect:whence;
+*/
int my_fseek(FILE *stream, off_t offset, int whence);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 11));
+ @*/
time_t get_time_from_YYMMDDHHMMSS(const char *date_asc);
-time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 18));
+ @*/
+time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const unsigned char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 16));
+ @*/
time_t get_time_from_YYYY_MM_DD_HHMMSS(const char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 14));
+ @*/
time_t get_time_from_YYYYMMDD_HHMMSS(const char *date_asc);
+/*@
+ @ requires \valid(list_search_space);
+ @ requires \valid(current_search_space);
+ @ requires \valid(offset);
+ @*/
+void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset, const uint64_t prev_location);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/godmode.c b/src/godmode.c
index ca3d333..0b41b0e 100644
--- a/src/godmode.c
+++ b/src/godmode.c
@@ -602,7 +602,7 @@ static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_o
old_cylinder=start.cylinder;
wmove(stdscr,ANALYSE_Y,ANALYSE_X);
wclrtoeol(stdscr);
- wprintw(stdscr,"Analyse cylinder %5u/%u: %02u%%",
+ wprintw(stdscr, "Analyse cylinder %5lu/%lu: %02u%%",
start.cylinder, disk_car->geom.cylinders-1,
(unsigned int)(search_location*100/disk_car->disk_size));
wrefresh(stdscr);
@@ -846,7 +846,7 @@ static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_o
#ifdef HAVE_NCURSES
wmove(stdscr,ANALYSE_Y+1,ANALYSE_X);
wclrtoeol(stdscr);
- wprintw(stdscr,msg_READ_ERROR_AT, start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size));
+ wprintw(stdscr, "Read error at %lu/%u/%u (lba=%lu)\n", start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size));
#endif
/* Stop reading after the end of the disk */
if(search_location >= disk_car->disk_real_size)
diff --git a/src/icon_ph.rc b/src/icon_ph.rc
index 4987614..d65fe73 100644
--- a/src/icon_ph.rc
+++ b/src/icon_ph.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/photorec.ico"
1 24 "../win/photorec_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "PhotoRec"
VALUE "OriginalFilename", "photorec_win.exe"
VALUE "Comments", "Signature based file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/icon_qph.rc b/src/icon_qph.rc
index 391828e..057ff52 100644
--- a/src/icon_qph.rc
+++ b/src/icon_qph.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/photorec.ico"
1 24 "../win/qphotorec_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "PhotoRec"
VALUE "OriginalFilename", "qphotorec_win.exe"
VALUE "Comments", "Signature based file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/icon_tst.rc b/src/icon_tst.rc
index 67b041d..63d5da3 100644
--- a/src/icon_tst.rc
+++ b/src/icon_tst.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/testdisk.ico"
1 24 MOVEABLE PURE "../win/testdisk_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "TestDisk"
VALUE "OriginalFilename", "testdisk_win.exe"
VALUE "Comments", "Partition and file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/lang.h b/src/lang.h
index f20dce7..3f43d48 100644
--- a/src/lang.h
+++ b/src/lang.h
@@ -21,7 +21,6 @@
*/
#define msg_DUMP_HEXA "Dump Hexa\n"
-#define msg_READ_ERROR_AT "Read error at %u/%u/%u (lba=%lu)\n"
#define c_YES 'Y'
#define c_NO 'N'
#define msg_TBL_NMARK "\nPartition sector doesn't have the endmark 0xAA55\n"
diff --git a/src/lang/qphotorec.ca.ts b/src/lang/qphotorec.ca.ts
index dbdcd5c..1e26ea8 100644
--- a/src/lang/qphotorec.ca.ts
+++ b/src/lang/qphotorec.ca.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Seleccioneu la destinació on guardar els fitxers recuperats.</translation>
</message>
@@ -61,22 +61,22 @@ Heu de ser usuari root per utilitzar el PhotoRec.</translation>
<translation>No hi ha disc</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Afegeix una imatge de disc en brut...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>El PhotoRec és programari lliure i ve SENSE CAP TIPUS DE GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Seleccioneu un mitjà des d&apos;on recuperar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Si algun dels discs llistats a sobre té una mida incorrecta, comproveu la confi
detecció a la BIOS, i instal·leu la última versió dels controladors del disc.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Indicadors</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipus</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistema de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Mida</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipus de sistema de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>sistema de fitxers ext2/ext3/ext4 </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Lliure: Explora només l&apos;espai no assignat</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Sencer: Extreu fitxers de la partició sencera</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Navega</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Cerca</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Quant a</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Format dels fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destinació:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperació completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Força bruta %1 sectors restants (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passa %1 - Llegint sector %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 capçaleres trobades</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 fitxers trobats</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Surt</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Família de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Surt</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Nombre de fitxers recuperats</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: No s&apos;ha pogut crear el fitxer</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>No s&apos;ha pogut crear el fitxer. Trieu una altra destinació</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: No hi ha espai suficient</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>No hi ha prou espai disponible. Heu d&apos;alliberar espai de disc i/o escollir una altra destinació</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,25 +234,25 @@ El QPhotoRec es distribueix amb l&apos;esperança que serà útil, però SENSE C
Hauríeu d&apos;haver rebut una còpia de la Llicència Pública General GNU juntament amb el QPhotoRec. En cas contrari, consulteu &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Quant a</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formats de fitxer</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Reinicialitzar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>
Res&amp;taura</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.cs.ts b/src/lang/qphotorec.cs.ts
new file mode 100644
index 0000000..57c630e
--- /dev/null
+++ b/src/lang/qphotorec.cs.ts
@@ -0,0 +1,256 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs" version="2.1">
+<context>
+ <name>QPhotorec</name>
+ <message>
+ <location filename="src/qphotorec.cpp" line="125"/>
+ <source>QPhotoRec</source>
+ <translation>QPhotoRec</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="156"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
+ <source>Please select a destination to save the recovered files to.</source>
+ <translation>Vyberte umístění do kterého ukládat obnovené soubory.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="170"/>
+ <source>Please select a raw file</source>
+ <translation>Vyberte soubor s daty pro zpracování</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="172"/>
+ <source>Raw Files (*.dd *.raw *.img)</source>
+ <translation>Soubory s daty pro zpracování (*.dd *.raw *.img)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="259"/>
+ <source>Sys=</source>
+ <translation>Sys=</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="261"/>
+ <source>Unknown</source>
+ <translation>Neznámé</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="377"/>
+ <source>No harddisk found</source>
+ <translation>Nenalezeno žádné datové úložiště</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="379"/>
+ <source>No harddisk found
+You need to be administrator to use this program.
+Under Win9x, use the DOS version instead.
+Under Vista or later, select this program, right-click and choose &quot;Run as administrator&quot;.</source>
+ <translation>Nenalezen žádný pevný disk
+Tento program je třeba spouštět s oprávněními pro správu systému.
+V systému Windows 9x použijte namísto toho verzi pro DOS.
+Pro Vista a novější vyberte tento program, klikněte na něj pravým tlačítkem a zvolte „Spustit jako správce“.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="388"/>
+ <source>No harddisk found
+You need to be root to use PhotoRec.</source>
+ <translation>Nenalezen žádný pevný disk
+PhotoRec je třeba spouštět s oprávněními pro správu systému.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="393"/>
+ <source>No Disk!</source>
+ <translation>Žádné datové úložiště!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="455"/>
+ <source>Add a raw disk image...</source>
+ <translation>Přidat obraz disku pro zpracování…</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="461"/>
+ <source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
+ <translation>PhotoRec je svobodný (libre) software a NEJSOU NA NĚJ POSKYTOVÁNY ŽÁDNÉ ZÁRUKY.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="462"/>
+ <source>Please select a media to recover from</source>
+ <translation>Vyberte médium ze kterého obnovit</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="465"/>
+ <source>Disk capacity must be correctly detected for a successful recovery.
+If a disk listed above has an incorrect size, check HD jumper settings and BIOS
+detection, and install the latest OS patches and disk drivers.</source>
+ <translation>Pro úspěšné obnovení je třeba, aby byla správně zjištěna velikost datového úložiště.
+Pokud má výše uvedený disk nesprávnou velikost, zkontrolujte pozici příslušné zkratovací propojky (jumper) a detekci v BIOS a nainstalujte nejnovější opravy pro operační systém a ovladače disků. </translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="472"/>
+ <source>Flags</source>
+ <translation>Příznaky</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="473"/>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="474"/>
+ <source>File System</source>
+ <translation>Souborový systém</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="475"/>
+ <source>Size</source>
+ <translation>Velikost</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="476"/>
+ <source>Label</source>
+ <translation>Štítek</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="491"/>
+ <source>File System type</source>
+ <translation>Typ souborového systému</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="492"/>
+ <source>ext2/ext3/ext4 filesystem</source>
+ <translation>Souborový systém ext2/ext3/ext4</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="493"/>
+ <source>FAT/NTFS/HFS+/ReiserFS/...</source>
+ <translation>FAT/NTFS/HFS+/ReiserFS/…</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="497"/>
+ <source>Free: Scan for file from unallocated space only</source>
+ <translation>Volné: hledat soubory pouze na nepřiděleném prostoru</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="498"/>
+ <source>Whole: Extract files from whole partition</source>
+ <translation>Celé: vytáhnout soubory z celého oddílu</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="525"/>
+ <source>&amp;Browse</source>
+ <translation>&amp;Procházet</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="541"/>
+ <source>&amp;Search</source>
+ <translation>&amp;Hledat</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="544"/>
+ <source>&amp;About</source>
+ <translation>O &amp;aplikaci</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="545"/>
+ <source>&amp;File Formats</source>
+ <translation>Souborové &amp;formáty</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="645"/>
+ <source>Destination:</source>
+ <translation>Cíl:</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="650"/>
+ <source>Recovery completed</source>
+ <translation>Obnovení dokončeno</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="655"/>
+ <source>Bruteforce %1 sectors remaining (test %2)</source>
+ <translation>Zbývá %1 sektorů pro zkoušení hrubou silou (test %2)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="663"/>
+ <source>Pass %1 - Reading sector %2/%3</source>
+ <translation>Průchod %1 – čtení sektoru %2/%3</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="668"/>
+ <source>%1/10 headers found</source>
+ <translation>Nalezeno %1/10 hlaviček</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="670"/>
+ <source>%1 files found</source>
+ <translation>Nalezeno %1 souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="753"/>
+ <source>File family</source>
+ <translation>Kategorie souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Ukončit</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
+ <source>Number of files recovered</source>
+ <translation>Počet obnovených souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="837"/>
+ <source>QPhotoRec: Failed to create file!</source>
+ <translation>QPhotoRec: Nepodařilo se vytvořit soubor!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="838"/>
+ <source>Failed to create file! Please choose another destination</source>
+ <translation>Soubor se nepodařilo vytvořit! Zvolte jiný cíl</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="857"/>
+ <source>QPhotoRec: Not enough space!</source>
+ <translation>QPhotoRec: Nedostatek dostupného prostoru!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="858"/>
+ <source>There is not enough space left! Please free disk space and/or choose another destination</source>
+ <translation>Nezbývá dostatek volného prostoru! Uvolněte nějaký a/nebo zvolte jiný cíl</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="927"/>
+ <source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
+
+QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with QPhotoRec. If not, see &lt;http://www.gnu.org/licenses/&gt;.</source>
+ <translation>QPhotoRec je svobodný (libre) software: můžete ho šířit a/nebo upravovat za podmínek licence GNU General Public License, vydané nadací Free Software Foundation, buď verze 2 této licence, nebo (dle své volby) libovolné novější.
+
+QPhotoRec je šířen v naději, že bude užitečný, ale BEZ JAKÝCHKOLI ZÁRUK; dokonce bez předpokládané záruky PRODEJNOSTI nebo VHODNOSTI PRO KONKRÉTNÍ ÚČEL. Podrobnosti viz text GNU General Public License.
+
+Společně s QPhotoRec byste měli obdržet text znění GNU General Public License. Pokud ne, naleznete ho na &lt;http://www.gnu.org/licenses/&gt;.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="928"/>
+ <source>QPhotoRec: About</source>
+ <translation>QPhotoRec: O aplikaci</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="957"/>
+ <source>File Formats</source>
+ <translation>Souborové formáty</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="960"/>
+ <source>&amp;Reset</source>
+ <translation>V&amp;rátit na výchozí</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="961"/>
+ <source>Res&amp;tore</source>
+ <translation>Obnovi&amp;t</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.es.ts b/src/lang/qphotorec.es.ts
index d82bf94..3f35b77 100644
--- a/src/lang/qphotorec.es.ts
+++ b/src/lang/qphotorec.es.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Por favor escoje un directorio para grabar los archivos recuperados.</translation>
</message>
@@ -43,13 +43,16 @@
You need to be administrator to use this program.
Under Win9x, use the DOS version instead.
Under Vista or later, select this program, right-click and choose &quot;Run as administrator&quot;.</source>
- <translation type="unfinished"/>
+ <translation>No se encontró ningún disco duro
+Necesitas ser Administrador par usar este programa
+Si estas en Win9x, usa la versión DOS
+Si estas en Vista o posterior, botón derecho y selecciona &quot;Ejecutar como Administrador&quot;</translation>
</message>
<message>
<location filename="src/qphotorec.cpp" line="388"/>
<source>No harddisk found
You need to be root to use PhotoRec.</source>
- <translation>No se pudo encontrar los discos duros
+ <translation>No se pudo encontrar ningún disco duro
Necesitas ser root para usar PhotoRec.</translation>
</message>
<message>
@@ -58,189 +61,195 @@ Necesitas ser root para usar PhotoRec.</translation>
<translation>Sin disco</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
- <translation>Añade imagen de disco raw</translation>
+ <translation>Añade un imagen raw de disco</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
- <translation>Photorec es un program gatis y no TIENE NINGUNA GARANTIA.</translation>
+ <translation>Photorec es un program gratuito y no TIENE NINGUNA GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Por favor escoje un medio para recuperarse de </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
- <translation type="unfinished"/>
+ <translation>El tamaño del disco debe ser correctamente detectado
+Si el tamaño de alguno de los disco listados es incorrecto, comprueba la Bios
+y los jumpers y/o Instala los los controladadores más recientes</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Bandera</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistem de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
- <translation>tamaño</translation>
+ <translation>Tamaño</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo de sistema de archivo </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>sistema de archivos ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
- <translation>Libre: Escanea por un archivo en el espacio que no es usado solamente.</translation>
+ <translation>Libre: Escanear por un archivo solamente en el espacio que no esta usado.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
- <translation>Todo: Sacar los archivos de toda la directoria</translation>
+ <translation>Todo: Extraer los archivos de toda la partición</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
- <translation>&amp;Mirar</translation>
+ <translation>&amp;Explorar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Buscar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Acerca de</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
- <translation>&amp;Formatos de el archivo</translation>
+ <translation>&amp;Formatos de archivo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
- <translation>destinación:</translation>
+ <translation>Destino:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperación completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
- <translation>Bruteforce quedan 1% sectores (testiar %2)</translation>
+ <translation>Bruteforce quedan 1% sectores (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Pass %1 - Leyendo el sector %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 headers encontrado</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 de archivos encontrado</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;abandonar</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familia de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Abandonar</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
- <translation>El numero de archivos recuperados</translation>
+ <translation>Archivos recuperados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
- <translation>QPhotoRec: fallo en crear un archivo!</translation>
+ <translation>QPhotoRec: No pudo crear un archivo!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
- <translation>No se pudo crear un achivo! Por favor escoje otro directorio</translation>
+ <translation>No se pudo crear un archivo! Por favor escoje otro directorio</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: No hay suficiente espacio </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
- <translation>No quedan bastante espacio! Por favor escoje otro disco duro con espacio o otro directorio</translation>
+ <translation> No hay suficiente espacio! Por favor libera espacio o escoje otro disco duro</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with QPhotoRec. If not, see &lt;http://www.gnu.org/licenses/&gt;.</source>
- <translation>QPhotoRect is es un programa gratis: Tu puedes redistribuirlo o modificarlo bajo el contrato de GNU General Public License como publicado por Free Software Foundation usando version 2 de la licensia o tu opcion de una de las ultima versiones.</translation>
+ <translation>QPhotoRect is es software libre: Tu puedes redistribuirlo y/o modificarlo bajo el contrato de GNU General Public License publicado por la Free Software Foundation usando la version 2 de la licencia o ( a tu elección) cualquier versión posterior.
+
+QPhotoRec se distribuye con la esperanza de que será útil, pero SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de comerciabilidad o aptitud para un propósito en particular. Vea la Licencia Pública General de GNU para más detalles.
+
+Debería haber recibido una copia de la Licencia Pública General de GNU junto con QPhotoRec. Si no es así, consulte &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
- <translation>QPhotoRec: Sobre</translation>
+ <translation>QPhotoRec: Acerca de</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
- <translation>EL formato de los archivos</translation>
+ <translation>Tipos de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
- <translation>&amp;Empesar</translation>
+ <translation>&amp;Reiniciar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Res&amp;tore</translation>
</message>
diff --git a/src/lang/qphotorec.fr.ts b/src/lang/qphotorec.fr.ts
index bff0426..17ce6fa 100644
--- a/src/lang/qphotorec.fr.ts
+++ b/src/lang/qphotorec.fr.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Merci de sélectionner une destination pour sauvegarder les fichiers récupérés.</translation>
</message>
@@ -61,22 +61,22 @@ Il faut être root pour utiliser ce programme.</translation>
<translation>Pas de disque!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Ajouter une image disque...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec est un logiciel libre, il vient avec ABSOLUMENT AUCUNE GARANTIE.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Merci de sélectionner un média à partir duquel récupérer les données</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -84,143 +84,143 @@ detection, and install the latest OS patches and disk drivers.</source>
Si un disque listé ci dessus a une taille incorrecte, vérifier le paramétrage des cavaliers du disque et la détection au niveau du BIOS, installer les derniers correctifs au niveau de votre système d&apos;exploitation et des gestionnaires de disques.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Drapeaux</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Type</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Système de fichiers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Taille</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Label</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Type de système de fichiers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Système de fichier ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Free: Rechercher des fichiers depuis l&apos;espace non alloué uniquement</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Whole: Extraire les fichiers depuis la totalité de la partition</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Parcourir</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Rechercher</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;A propos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formats de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destination:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Récupération de données terminée</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Force brute %1 secteurs restants (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passe %1 - Lecture du secteur %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 entêtes trouvés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 fichiers trouvés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Quitter</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familles de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Quitter</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Nombre de fichiers récupérés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Échec de création de fichier!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Impossible de créer un fichier! Merci de sélectionner une autre destination</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Pas assez d&apos;espace!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Il n&apos;y a pas assez d&apos;espace disponible! Merci de libérer de l&apos;espace disque et/ou de choisir une autre destination</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -233,24 +233,24 @@ QPhotoRec est distribué dans l&apos;espoir qu&apos;il sera utile, mais SANS AUC
Vous avez du recevoir un exemplaire de la Licence Publique Générale GNU avec ce programme ; si ce n&apos;est pas le cas, consulter &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: A propos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formats de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Réinitialiser</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Res&amp;taurer</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.it.ts b/src/lang/qphotorec.it.ts
index 2e4d7b6..55a87f0 100644
--- a/src/lang/qphotorec.it.ts
+++ b/src/lang/qphotorec.it.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Scegliere la destinazione in cui si desidera salvare i documenti recuperati.</translation>
</message>
@@ -61,22 +61,22 @@ Si deve disporre di privilegi di root per usare PhotoRec.</translation>
<translation>Nessun Disco!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Aggiungere un&apos;immagine raw del disco...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec è un software libero e viene fornito ASSOLUTAMENTE SENZA ALCUNA GARANZIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Selezionare un supporto dal quale eseguire l&apos;operazione di recupero</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -86,143 +86,143 @@ detection, e installare gli aggiornamenti del sistema operativo e i driver del d
</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Flag</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>File System</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Dimensione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etichetta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo di File System</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>File system ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Libero: ricerca di documenti unicamente nello spazio non allocato</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Completo: Estrazione dei documenti da tutta la partizione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Naviga</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Cerca</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Info</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formati dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destinazione:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recupero terminato</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Esaustiva %1 settori rimanenti (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Iterazione %1 - Lettura del settore %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 intestazioni trovate</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 documenti trovati</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Uscire</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>famiglia dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Uscire</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>numero dei file recuperati</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Impossibile creare il file!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Impossibile creare il file! Selezionare un&apos;altra destinazione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Spazio insufficiente!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Spazio disponibile insufficiente. Liberare spazio su disco e/o scegliere un&apos;altra destinazione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -235,24 +235,24 @@ QPhotoRec viene distribuito con la speranza che possa essere utile ma SENZA ALCU
Una copia della GNU General Public License è distribuita con QPhotoRec. In caso contrario se ne può ottenere una all&apos;indirizzo &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: A proposito</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formati dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Resettare</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Ripri&amp;stinare</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.ja.ts b/src/lang/qphotorec.ja.ts
index dd222e1..4258334 100644
--- a/src/lang/qphotorec.ja.ts
+++ b/src/lang/qphotorec.ja.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>復元したファイルの保存先を選択してください。</translation>
</message>
@@ -61,22 +61,22 @@ PhotoRecを使うにはrootユーザになる必要があります。</translati
<translation>ディスクがありません!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>復元元ディスクイメージを追加</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRecは無料のソフトウェアで、一切の保証はありません。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>復元元のメディアを選択してください</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -84,143 +84,143 @@ detection, and install the latest OS patches and disk drivers.</source>
上に列挙されたディスクに正しくない容量が表示されていたら、ハードディスクのジャンパ設定とBIOSで検知されている内容を確認し、最新のOSパッチとディスクドライバをインストールしてください。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>フラグ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>タイプ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>ファイルシステム</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>サイズ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>ラベル</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>ファイルシステムの種類</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 ファイルシステム</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>すべて: すべてのパーティションからファイルを抽出する</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;参照</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;検索</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;ファイルフォーマット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>復元先</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>復元完了</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 ヘッダーが見つかりました</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 個のファイルが見つかりました。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;終了</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;終了</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>復元したファイルの数</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: ファイル作成に失敗しました!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>ファイルの作成に失敗しました! 別の保存先を選んでください。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: 十分な空き容量がありません!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>十分な空き容量がありません! ディスクの空き容量を増やすかまたは別の復元先を指定してください</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -229,24 +229,24 @@ You should have received a copy of the GNU General Public License along with QPh
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>ファイルフォーマット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;リセット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation type="unfinished"/>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.pt.ts b/src/lang/qphotorec.pt.ts
index c6af4fd..cddfb18 100644
--- a/src/lang/qphotorec.pt.ts
+++ b/src/lang/qphotorec.pt.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Por favor selecionar o destino para salvar os arquivos recuperados.</translation>
</message>
@@ -61,22 +61,22 @@ Você precisa ser root para usar PhotoRec.</translation>
<translation>Sem disco!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Adicionar imagem de disco raw...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec é um software livre, e não vem com ABSOLUTAMENTE NENHUMA GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Por favor selecionar a midia para recuperar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Se o disco listado abaixo não tem o tamanho certo, verificar o jumper do HD nas
detecar, e instalar o ultimo patch do SO e drivers do disco.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Flags</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistema de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Tamanho</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo de sistema de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Sistemas de arquivos ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Livre: Esconear por arquivos de espaços não alocados somente.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Inteiro: Extrair arquivos da partição inteira</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Browse</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Pesquisar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Sobre</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formatos de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destino:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperação completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Bruteforce %1 setores restantes (teste %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passar %1 - Lendo setor %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 headers encontrados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 arquivos encontrados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Sair</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familia do arquivo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Sair</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Número de arquivos recuperados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Falha ao criar o arquivo!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Falha ao criar o arquivo! Por favor selecionar outro destino</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Sem espaço suficiente!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Não tem espaço suficiente! Por favor mais espaço em disco e/ou selecione outro destino</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ QPhotoRec é distribuido na esperança de ser util, porém sem qualquer garantia
Você deve receber uma cópia do licença GNU durante o uso de QPhotoRec. Se não, visite &lt;https://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Sobre</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formatos de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Reconfigurar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Restaurar</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.ru.ts b/src/lang/qphotorec.ru.ts
index 3f0f709..ba2d4cd 100644
--- a/src/lang/qphotorec.ru.ts
+++ b/src/lang/qphotorec.ru.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Выберите назначение для сохранения восстановленных файлов.</translation>
</message>
@@ -61,22 +61,22 @@ You need to be root to use PhotoRec.</source>
<translation>Нет диска!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Добавить образ raw диска...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec является свободным программным обеспечением и поставляется с БЕЗ ВСЯКИХ ГАРАНТИЙ.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Выберите носитель для восстановления из</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ detection, and install the latest OS patches and disk drivers.</source>
и обнаружение BIOS, и установите последние обновления операционной системы и дисковых накопителей.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Флаги</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Тип</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Файловая система</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Размер</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Метка</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Тип файловой системы</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Файловая система ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>Файловая система FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Свободное: Сканирование файла только из незанятого пространства</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Весь: Извлечение файлов из всего раздела</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>О&amp;бзор</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Поиск</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;О программе</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Форматы файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Назначение:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Восстановление завершено</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Полный перебор %1 оставшихся секторов (тест %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Проход %1 - Чтение сектора %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>Найдено %1/10 заголовков</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>Найдено %1 файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>В&amp;ыход</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Семейство файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>В&amp;ыход</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Количество восстановленных</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Не удалось создать файл!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Не удалось создать файл! Выберите другое назначение</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>PhotoRec: Не хватает места!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Там не осталось свободного места! Освободите место на диске или выберите другое место назначения</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ PhotoRec распространяется в надежде, что она бу
Вы должны были получить копию GNU General Public License вместе с PhotoRec. Если нет, смотрите &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>О программе QPhotoRec</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Форматы файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>Сб&amp;росить</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Вернуть</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.tr.ts b/src/lang/qphotorec.tr.ts
index 9b49693..0b226be 100644
--- a/src/lang/qphotorec.tr.ts
+++ b/src/lang/qphotorec.tr.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Lütfen kurtarılan dosyaların kaydedeceği konumu seçin.</translation>
</message>
@@ -61,22 +61,22 @@ PhotoRec&apos;i kullanmanız için &quot;root&quot; kullanıcısı olmalısını
<translation>Disk yok</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Ham (Raw) disk imajı ekleyin</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec ücresiz bir yazılımdır ve verilerin kurtarılması konusunda herhangi bir garanti vermez.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Lütfen kurtarılmasını istediğiniz ortamı seçin</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Eğer aşağıdaki listedeki bir disk yanlış boyutta belirlenmişse disk jumpe
</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>İşareti</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Dosya Sistemi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Boyutu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiketi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Dosya Sistemi türü</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 dosya sistemleri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Boş alan: Sadece bir disk olarak tanımlanmamış alanı tara</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Tamamı: Tüm bölümden dosyaları çıkart</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Gözat</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Ara</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Hakkında</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Dosya Formatları</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Hedef:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Kurtarma tamamlandı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Bruteforce %1 sektör kaldı (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Tamamlanan %1 - Okunan sektör %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 kafa bulundu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 dosya bulundu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Çıkış</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Dosya ailesi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Çıkış</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Kurtarılan dosya sayısı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Dosya oluşturulamadı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Dosya oluşturulamadı! Lütfen başka bir konum seçin.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Yeterli alan yok!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Diskte yeterli alan kalmadı! Lütfen diskte boş alan açın ve/veya başka bir hedef disk seçin.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ QPhotoRec işe yarayacağı öngörüsü ile dağıtılmıştır fakat; TİCAR
QPhotoRec ile birlikte GNU Genel Kamu Lisansı&apos;nın bir kopyasını almış olmalısınız. Eğer yoksa &lt;http://www.gnu.org/licenses/&gt; .</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Hakkında</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Dosya Türleri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Hiçbiri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Tümü</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.zh_TW.ts b/src/lang/qphotorec.zh_TW.ts
index ab7468d..e8c00df 100644
--- a/src/lang/qphotorec.zh_TW.ts
+++ b/src/lang/qphotorec.zh_TW.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>請選擇要儲存還原檔案的目的地。</translation>
</message>
@@ -61,22 +61,22 @@ You need to be root to use PhotoRec.</source>
<translation>沒有磁碟!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>加入一個原始磁碟影像...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec 是自由軟體,並不提供任何擔保。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>請選擇需要還原的媒體</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ detection, and install the latest OS patches and disk drivers.</source>
並請安裝最近更新的作業系統修補包以及磁碟驅動程式。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>旗標</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>類型</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>檔案系統</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>大小</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>標籤</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>檔案系統類型</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 檔案系統</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>空間:僅掃瞄未分配空間裡的檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>完整:從整個分割區內提取檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>瀏覽(&amp;B)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>搜尋(&amp;S)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>關於(&amp;A)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>檔案系統(&amp;F)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>目的地:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>完成還原</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>尚餘強力破解 %1 個磁區 (測試 %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>通過 %1 - 正在選取磁區 %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>找到標願 %1/10</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>找到 %1 個檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>離開(&amp;Q)</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>檔案家族</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>離開(&amp;Q)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>完成還原的檔案數目</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: 建立檔案失敗!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>建立檔案失敗!請選取另一目的地</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: 空間不足!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>磁碟空間不足!請騰出空間並/或選取另一目的地</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ You should have received a copy of the GNU General Public License along with QPh
您應該連同 QPhotoRec 取得 GNU 通用公共許可證 (GPL) 的複本,否則您可以參見&lt;http://www.gnu.org/licenses/&gt;。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: 關於</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>檔案格式</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>重設(&amp;R)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>還原(&amp;T)</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/ntfs.c b/src/ntfs.c
index ee47e0a..1cbdeaa 100644
--- a/src/ntfs.c
+++ b/src/ntfs.c
@@ -184,7 +184,7 @@ int test_NTFS(const disk_t *disk_car, const struct ntfs_boot_sector*ntfs_header,
return 0;
}
-const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record)
+static const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record)
{
const char* location = (const char*)record;
if(le32(record->magic)!=NTFS_Magic ||
@@ -225,10 +225,12 @@ const ntfs_attribheader* ntfs_findattribute(const ntfs_recordheader* record, uin
return ntfs_searchattribute(attrib, attrType, end, 0);
}
-const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end)
+#if 0
+static const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end)
{
return ntfs_searchattribute(attrib, attrType, end, 1);
}
+#endif
const char* ntfs_getattributedata(const ntfs_attribresident* attrib, const char* end)
{
diff --git a/src/ntfs.h b/src/ntfs.h
index 353a7f3..faaa1ac 100644
--- a/src/ntfs.h
+++ b/src/ntfs.h
@@ -254,9 +254,7 @@ int test_NTFS(const disk_t *disk_car, const struct ntfs_boot_sector*ntfs_header,
#define NTFS_GETU64(p) (le64(*(const uint64_t*)(p)))
unsigned int ntfs_sector_size(const struct ntfs_boot_sector *ntfs_header);
int rebuild_NTFS_BS(disk_t *disk_car,partition_t *partition, const int verbose, const unsigned int expert, char**current_cmd);
-const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record);
const ntfs_attribheader* ntfs_findattribute(const ntfs_recordheader* record, uint32_t attrType, const char* end);
-const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end);
const char* ntfs_getattributedata(const ntfs_attribresident* attrib, const char* end);
long int ntfs_get_first_rl_element(const ntfs_attribnonresident *attrnr, const char* end);
diff --git a/src/ntfs_fix.c b/src/ntfs_fix.c
index e0157a2..37542a3 100644
--- a/src/ntfs_fix.c
+++ b/src/ntfs_fix.c
@@ -226,7 +226,7 @@ int repair_MFT(disk_t *disk_car, partition_t *partition, const int verbose, cons
{
/* Use MFT mirror */
#ifdef HAVE_NCURSES
- if(ask_confirmation("Fix MFT using its mirror ? (Y/N) - DANGEROUS NON REVERSIBLE OPERATION\nUse it ONLY IF Windows failed to access this filesystem.")!=0)
+ if(ask_confirmation("Fix MFT using its mirror ? (Y/N) - DANGEROUS NON REVERSIBLE OPERATION\nUse it ONLY IF TestDisk and Windows failed to access this filesystem.")!=0)
use_MFT=2;
else
#endif
diff --git a/src/ntfsp.c b/src/ntfsp.c
index 6da6822..b6a040a 100644
--- a/src/ntfsp.c
+++ b/src/ntfsp.c
@@ -37,6 +37,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#ifdef HAVE_LIBNTFS
#include <ntfs/attrib.h>
#endif
diff --git a/src/partgpt.c b/src/partgpt.c
index 806ac75..025439d 100644
--- a/src/partgpt.c
+++ b/src/partgpt.c
@@ -38,8 +38,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include <assert.h>
@@ -78,6 +77,7 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt);
const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_EFI, "EFI System" },
+ { GPT_ENT_TYPE_EBP, "Extended Boot" },
{ GPT_ENT_TYPE_MBR, "MBR" },
{ GPT_ENT_TYPE_FREEBSD, "FreeBSD" },
{ GPT_ENT_TYPE_FREEBSD_SWAP, "FreeBSD Swap" },
@@ -90,6 +90,7 @@ const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_MS_LDM_METADATA, "MS LDM MetaData" },
{ GPT_ENT_TYPE_MS_LDM_DATA, "MS LDM Data" },
{ GPT_ENT_TYPE_MS_RECOVERY, "Windows Recovery Env" },
+// { GPT_ENT_TYPE_LINUX_DATA
{ GPT_ENT_TYPE_LINUX_RAID, "Linux Raid" },
{ GPT_ENT_TYPE_LINUX_SWAP, "Linux Swap" },
{ GPT_ENT_TYPE_LINUX_LVM, "Linux LVM" },
@@ -99,6 +100,7 @@ const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_LINUX_DATA, "Linux filesys. data" },
{ GPT_ENT_TYPE_HPUX_DATA, "HPUX Data" },
{ GPT_ENT_TYPE_HPUX_SERVICE, "HPUX Service" },
+ { GPT_ENT_TYPE_MAC_AFS, "Apple APFS" },
{ GPT_ENT_TYPE_MAC_HFS, "Mac HFS" },
{ GPT_ENT_TYPE_MAC_UFS, "Mac UFS" },
{ GPT_ENT_TYPE_MAC_RAID, "Mac Raid" },
@@ -511,6 +513,18 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt)
for(i=0; gpt_sys_types[i].name!=NULL; i++)
if(guid_cmp(gpt_sys_types[i].part_type, part_type_gpt)==0)
return gpt_sys_types[i].name;
+ log_info("%8x %04x %04x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ part_type_gpt.time_low,
+ part_type_gpt.time_mid,
+ part_type_gpt.time_hi_and_version,
+ part_type_gpt.clock_seq_hi_and_reserved,
+ part_type_gpt.clock_seq_low,
+ part_type_gpt.node[0],
+ part_type_gpt.node[1],
+ part_type_gpt.node[2],
+ part_type_gpt.node[3],
+ part_type_gpt.node[4],
+ part_type_gpt.node[5]);
return NULL;
}
diff --git a/src/partgptn.c b/src/partgptn.c
index dbe320a..74b76ce 100644
--- a/src/partgptn.c
+++ b/src/partgptn.c
@@ -38,8 +38,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include "common.h"
diff --git a/src/partgptw.c b/src/partgptw.c
index 65cbaac..0621e1b 100644
--- a/src/partgptw.c
+++ b/src/partgptw.c
@@ -37,8 +37,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include "common.h"
diff --git a/src/parti386.c b/src/parti386.c
index 350a38b..2c334b1 100644
--- a/src/parti386.c
+++ b/src/parti386.c
@@ -199,6 +199,7 @@ static const struct systypes i386_sys_types[] = {
{0xe1, "SpeedStor FAT12 ext"},
{0xe3, "DOS RO"},
{0xe4, "SpeedStor FAT16 ext"},
+ {0xea, "Boot (BLS)"},
{P_BEOS, "BeFS"},
{0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
{0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
diff --git a/src/phbf.c b/src/phbf.c
index 5d501a3..523abe4 100644
--- a/src/phbf.c
+++ b/src/phbf.c
@@ -170,6 +170,7 @@ pstatus_t photorec_bf(struct ph_param *params, const struct ph_options *options,
file_recovery_t file_recovery_new;
// memset(&file_recovery_new, 0, sizeof(file_recovery_t));
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
file_recovery_new.file_stat=NULL;
td_list_for_each(tmpl, &file_check_list.list)
{
@@ -190,7 +191,6 @@ pstatus_t photorec_bf(struct ph_param *params, const struct ph_options *options,
}
if(file_recovery_new.file_stat!=NULL)
{
- file_recovery_new.location.start=offset;
if(options->verbose>0)
{
log_info("%s header found at sector %lu\n",
diff --git a/src/phbs.c b/src/phbs.c
index b1135d8..9ce2d0d 100644
--- a/src/phbs.c
+++ b/src/phbs.c
@@ -100,6 +100,7 @@ pstatus_t photorec_find_blocksize(struct ph_param *params, const struct ph_optio
{
file_recovery_t file_recovery_new;
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint==&file_hint_tar &&
header_check_tar(buffer-0x200,0x200,0,&file_recovery,&file_recovery_new))
{ /* Currently saving a tar, do not check the data for know header */
diff --git a/src/phmain.c b/src/phmain.c
index 6a9c382..0949376 100644
--- a/src/phmain.c
+++ b/src/phmain.c
@@ -182,6 +182,10 @@ int main( int argc, char **argv )
}
logfile=argv[++i];
}
+ else if((strcmp(argv[i],"/nolog")==0) ||(strcmp(argv[i],"-nolog")==0))
+ {
+ create_log=TD_LOG_NONE;
+ }
else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0))
{
if(create_log==TD_LOG_NONE)
@@ -387,7 +391,7 @@ int main( int argc, char **argv )
printf("PhotoRec will try to restart itself using the sudo command to get\n");
printf("root (superuser) privileges.\n");
printf("\n");
- run_sudo(argc, argv);
+ run_sudo(argc, argv, create_log);
}
#endif
delete_list_disk(list_disk);
diff --git a/src/photorec.c b/src/photorec.c
index d8b0da1..c84d54c 100644
--- a/src/photorec.c
+++ b/src/photorec.c
@@ -85,6 +85,11 @@ void del_search_space(alloc_data_t *list_search_space, const uint64_t start, con
update_search_space_aux(list_search_space, start, end, NULL, NULL);
}
+/*@
+ @ requires \valid(list_search_space);
+ @ requires new_current_search_space == \null || \valid(*new_current_search_space);
+ @ requires offset == \null || \valid(*offset);
+ @*/
static void update_search_space_aux(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end, alloc_data_t **new_current_search_space, uint64_t *offset)
{
struct td_list_head *search_walker = NULL;
@@ -510,6 +515,7 @@ void file_block_free(alloc_list_t *list_allocation)
{
alloc_list_t *allocated_space;
allocated_space=td_list_entry(tmp, alloc_list_t, list);
+ header_ignored_cond_reset(allocated_space->start, allocated_space->end);
free_list_allocation_end=allocated_space->end;
td_list_del(tmp);
free(allocated_space);
diff --git a/src/photorec.h b/src/photorec.h
index 4aa30e0..a6ab7ed 100644
--- a/src/photorec.h
+++ b/src/photorec.h
@@ -64,7 +64,6 @@ struct ph_param
uint64_t offset;
};
-void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset, const uint64_t prev_location);
int get_prev_file_header(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset);
int file_finish_bf(file_recovery_t *file_recovery, struct ph_param *params,
alloc_data_t *list_search_space);
@@ -93,6 +92,12 @@ void file_block_log(const file_recovery_t *file_recovery, const unsigned int sec
void file_block_free(alloc_list_t *list_allocation);
void file_block_append(file_recovery_t *file_recovery, alloc_data_t *list_search_space, alloc_data_t **new_current_search_space, uint64_t *offset, const unsigned int blocksize, const unsigned int data);
void file_block_truncate_and_move(file_recovery_t *file_recovery, alloc_data_t *list_search_space, const unsigned int blocksize, alloc_data_t **new_current_search_space, uint64_t *offset, unsigned char *buffer);
+
+/*@
+ @ requires \valid(list_search_space);
+ @*/
+void del_search_space(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end);
+
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/photorec_check_header.h b/src/photorec_check_header.h
index 7767ca1..6522d9f 100644
--- a/src/photorec_check_header.h
+++ b/src/photorec_check_header.h
@@ -97,7 +97,6 @@ static pstatus_t photorec_header_found(file_recovery_t *file_recovery_new, file_
*file_recovered=PFSTATUS_BAD;
if(file_recovery_new->file_stat==NULL || file_recovery_new->file_stat->file_hint==NULL)
return PSTATUS_OK;
- file_recovery_new->location.start=offset;
if(file_recovery->file_stat!=NULL)
{
if(options->verbose > 1)
@@ -132,6 +131,7 @@ inline static pstatus_t photorec_check_header(file_recovery_t *file_recovery, st
const unsigned int read_size=(blocksize>65536?blocksize:65536);
file_recovery_t file_recovery_new;
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
if(file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_tar &&
header_check_tar(buffer-0x200,0x200, 0, file_recovery, &file_recovery_new))
{ /* Currently saving a tar, do not check the data for know header */
diff --git a/src/qphotorec_locale.qrc b/src/qphotorec_locale.qrc
index 409ab01..f838120 100644
--- a/src/qphotorec_locale.qrc
+++ b/src/qphotorec_locale.qrc
@@ -1,11 +1,14 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>lang/qphotorec.ca.qm</file>
+<file>lang/qphotorec.cs.qm</file>
<file>lang/qphotorec.es.qm</file>
<file>lang/qphotorec.fr.qm</file>
<file>lang/qphotorec.it.qm</file>
+<file>lang/qphotorec.ja.qm</file>
<file>lang/qphotorec.pt.qm</file>
<file>lang/qphotorec.ru.qm</file>
+<file>lang/qphotorec.tr.qm</file>
<file>lang/qphotorec.zh_TW.qm</file>
</qresource>
</RCC>
diff --git a/src/setdate.c b/src/setdate.c
index d05e716..5e26e1a 100644
--- a/src/setdate.c
+++ b/src/setdate.c
@@ -49,10 +49,12 @@ int set_date(const char *pathname, time_t actime, time_t modtime)
return -1;
ut.actime = actime;
ut.modtime = modtime;
+#ifndef __FRAMAC__
if (utime(pathname, &ut)) {
log_error("ERROR: Couldn't set the file's date and time for %s\n", pathname);
return -1;
}
#endif
+#endif
return 0;
}
diff --git a/src/sudo.c b/src/sudo.c
index 5f346ba..245b006 100644
--- a/src/sudo.c
+++ b/src/sudo.c
@@ -38,16 +38,28 @@
#include "types.h"
#include "common.h"
#include "sudo.h"
+#include "log.h"
-void run_sudo(int argc, char **argv)
+void run_sudo(const int argc, char **argv, const int create_log)
{
- int i;
char **argv2;
- argv2 = (char **)MALLOC(sizeof(char *) * (argc + 2));
- argv2[0]=strdup(SUDO_BIN);
- for (i=0; i < argc; i++)
- argv2[i+1] = argv[i];
- argv2[i+1]=NULL;
+ if(argc==1)
+ {
+ argv2 = (char **)MALLOC(sizeof(char *) * 4);
+ argv2[0] = strdup(SUDO_BIN);
+ argv2[1] = argv[0];
+ argv2[2] = strdup(create_log==TD_LOG_NONE?"/nolog":"/debug");
+ argv2[3] = NULL;
+ }
+ else
+ {
+ int i;
+ argv2 = (char **)MALLOC(sizeof(char *) * (argc + 2));
+ argv2[0]=strdup(SUDO_BIN);
+ for (i=0; i < argc; i++)
+ argv2[i+1] = argv[i];
+ argv2[i+1]=NULL;
+ }
printf("sudo may ask your user password, it doesn't ask for the root password.\n");
printf("Usually there is no echo or '*' displayed when you type your password.\n");
printf("\n");
diff --git a/src/sudo.h b/src/sudo.h
index fce6f3c..d16ee66 100644
--- a/src/sudo.h
+++ b/src/sudo.h
@@ -23,7 +23,7 @@
#ifdef __cplusplus
extern "C" {
#endif
-void run_sudo(int argc, char **argv);
+void run_sudo(const int argc, char **argv, const int create_log);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/testdisk.c b/src/testdisk.c
index 891833a..4317cc7 100644
--- a/src/testdisk.c
+++ b/src/testdisk.c
@@ -43,9 +43,7 @@
#include "types.h"
#include "common.h"
#include "intrf.h"
-#ifdef HAVE_NCURSES
#include "intrfn.h"
-#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -259,6 +257,10 @@ int main( int argc, char **argv )
}
logfile=argv[++i];
}
+ else if((strcmp(argv[i],"/nolog")==0) ||(strcmp(argv[i],"-nolog")==0))
+ {
+ create_log=TD_LOG_NONE;
+ }
else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0))
{
if(create_log==TD_LOG_NONE)
@@ -515,7 +517,7 @@ int main( int argc, char **argv )
printf("TestDisk will try to restart itself using the sudo command to get\n");
printf("root (superuser) privileges.\n");
printf("\n");
- run_sudo(argc, argv);
+ run_sudo(argc, argv, create_log);
}
#endif
return 0;
diff --git a/src/tpartwr.c b/src/tpartwr.c
index d6c3d43..0eece16 100644
--- a/src/tpartwr.c
+++ b/src/tpartwr.c
@@ -84,9 +84,14 @@ int interface_write(disk_t *disk_car,list_part_t *list_part,const int can_search
}
else
{
+ char options[10];
+ options[0]='R';
+ options[1]=0;
+ if(can_search_deeper)
+ strcat(options,"S");
log_flush();
#ifdef HAVE_NCURSES
- command=screen_buffer_display_ext(stdscr,(can_search_deeper?"S":""),menuWrite,menu);
+ command=screen_buffer_display_ext(stdscr, options, menuWrite,menu);
#endif
}
}