summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am50
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile.am57
-rw-r--r--src/common.c48
-rw-r--r--src/common.h4
-rw-r--r--src/fat_unformat.c9
-rw-r--r--src/fidentify.c35
-rw-r--r--src/file_bmp.c37
-rw-r--r--src/file_doc.c505
-rw-r--r--src/file_emf.c193
-rw-r--r--src/file_exe.c39
-rw-r--r--src/file_gpg.c21
-rw-r--r--src/file_gz.c35
-rw-r--r--src/file_jpg.c416
-rw-r--r--src/file_list.c6
-rw-r--r--src/file_mov.c13
-rw-r--r--src/file_mp3.c699
-rw-r--r--src/file_pdf.c6
-rw-r--r--src/file_pf.c19
-rw-r--r--src/file_sdsk.c66
-rw-r--r--src/file_spe.c177
-rw-r--r--src/file_tiff.h25
-rw-r--r--src/file_tiff_be.c43
-rw-r--r--src/file_tiff_le.c41
-rw-r--r--src/file_txt.c3781
-rw-r--r--src/file_txt.h9
-rw-r--r--src/file_win.c5
-rw-r--r--src/file_zip.c36
-rw-r--r--src/filegen.c319
-rw-r--r--src/filegen.h20
-rw-r--r--src/list.h55
-rw-r--r--src/memmem.h8
-rw-r--r--src/misc.c4
-rw-r--r--src/partgpt.c1
-rw-r--r--src/pdiskseln.c5
-rw-r--r--src/phbf.c3
-rw-r--r--src/phbs.c6
-rw-r--r--src/phcli.c3
-rw-r--r--src/phmain.c26
-rw-r--r--src/phrecn.c6
-rw-r--r--src/ppartseln.c3
-rw-r--r--src/psearchn.c3
42 files changed, 5270 insertions, 1569 deletions
diff --git a/Makefile.am b/Makefile.am
index 7b424bf..94e0926 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,24 +1,3 @@
-.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)
@@ -80,32 +59,11 @@ 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 $@
+session_%.framac:
+ (cd src && $(MAKE) $@) || exit 1;
-frama-c-%: session_%.framac
- frama-c-gui -load $^
+frama-c-%:
+ (cd src && $(MAKE) $@) || exit 1;
cppcheck:
cppcheck --quiet --enable=all -DHAVE_CONFIG_H -I$(builddir) -I/usr/include $(srcdir)/src
diff --git a/configure.ac b/configure.ac
index 40ee68d..451ef50 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@ AC_INIT([testdisk],[7.2-WIP],[grenier@cgsecurity.org])
AC_LANG(C)
sinclude(acx_pthread.m4)
sinclude(mkdir.m4)
-TESTDISKDATE="November 2019"
+TESTDISKDATE="January 2020"
AC_SUBST(TESTDISKDATE)
AC_DEFINE_UNQUOTED([TESTDISKDATE],"$TESTDISKDATE",[Date of release])
AC_CONFIG_AUX_DIR(config)
diff --git a/src/Makefile.am b/src/Makefile.am
index a7c2a2b..aea1b3b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,3 +1,24 @@
+.PRECIOUS: session_%.framac
+FRAMA_C_FLAGS=-machdep x86_64 \
+ -warn-left-shift-negative \
+ -warn-right-shift-negative \
+ -warn-signed-downcast \
+ -warn-signed-overflow \
+ -warn-unsigned-downcast \
+ -warn-unsigned-overflow \
+ -rte \
+ -eva \
+ -eva-slevel 6 \
+ -eva-warn-undefined-pointer-comparison none \
+ -eva-ignore-recursive-calls \
+ -then \
+ -wp \
+ -wp-dynamic \
+ -wp-steps 100000 \
+ -wp-split -wp-literals \
+ -wp-timeout 10 -pp-annot \
+ -kernel-msg-key pp
+
.rc.o:
$(WINDRES) --include-dir $(srcdir) $< $@
@@ -285,6 +306,7 @@ file_C = filegen.c \
file_rw2.c \
file_rx2.c \
file_save.c \
+ file_sdsk.c \
file_ses.c \
file_sgcta.c \
file_shn.c \
@@ -362,12 +384,12 @@ file_C = filegen.c \
file_H = ext2.h ext2_common.h filegen.h file_doc.h file_jpg.h file_gz.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
-photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c pdisksel.c phcli.c poptions.c sessionp.c setdate.c dfxml.c
+photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c pdisksel.c poptions.c sessionp.c setdate.c dfxml.c
-photorec_H = photorec.h phcfg.h addpart.h chgarch.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h geometry.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h pdisksel.h phcli.h poptions.h sessionp.h setdate.h dfxml.h
+photorec_H = photorec.h phcfg.h addpart.h chgarch.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h geometry.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h pdisksel.h poptions.h sessionp.h setdate.h dfxml.h
-photorec_ncurses_C = addpartn.c askloc.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdiskseln.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartseln.c psearchn.c
-photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h photorec_check_header.h
+photorec_ncurses_C = addpartn.c askloc.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdiskseln.c pfree_whole.c phbf.c phbs.c phcli.c phnc.c phrecn.c ppartseln.c psearchn.c
+photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phcli.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h photorec_check_header.h
QT_TS = \
lang/qphotorec.ca.ts \
@@ -404,6 +426,33 @@ small: $(sbin_PROGRAMS) $(bin_PROGRAMS)
extras: $(EXTRA_PROGRAMS)
+frama-c-%: session_%.framac
+ frama-c-gui -load $^
+
+session_doc.framac: file_doc.c common.c filegen.c log.c setdate.c
+ gcc $(CFLAGS) -DMAIN_doc -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_doc -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_jpg.framac: file_jpg.c file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c suspend_no.c setdate.c
+ gcc $(CFLAGS) -DMAIN_jpg -DHAVE_CONFIG_H -O -o demo -I.. $^ -ljpeg
+ frama-c $^ -cpp-extra-args="-DMAIN_jpg -DHAVE_CONFIG_H -D__x86_64__ -I/usr/include -I.. -I $(frama-c -print-path)/libc" $(FRAMA_C_FLAGS) -save $@ 2>&1 | tee session_jpg.log
+
+session_tiff_be.framac: file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_be -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_tiff_le.framac: file_tiff.c file_tiff_be.c file_tiff_le.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_tiff_le -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_tiff_le -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_%.framac: file_%.c common.c filegen.c log.c
+ gcc $(CFLAGS) -DMAIN_$* -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_$* -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
+session_fidentify.framac: fidentify.c common.c misc.c filegen.c log.c setdate.c file_bmp.c file_list.c
+ gcc $(CFLAGS) -DMAIN_fidentify -DHAVE_CONFIG_H -O -o demo -I.. $^
+ frama-c $^ -cpp-extra-args="-DMAIN_fidentify -DHAVE_CONFIG_H -D__x86_64__ -I.." $(FRAMA_C_FLAGS) -save $@
+
moc_qphotorec.cpp: qphotorec.h
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $< -o $@
diff --git a/src/common.c b/src/common.c
index afcf387..8e9e7de 100644
--- a/src/common.c
+++ b/src/common.c
@@ -225,22 +225,50 @@ char* strip_dup(char* str)
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
+/*
+ * The epoch of FAT timestamp is 1980.
+ * : bits : value
+ * date: 0 - 4: day (1 - 31)
+ * date: 5 - 8: month (1 - 12)
+ * date: 9 - 15: year (0 - 127) from 1980
+ * time: 0 - 4: sec (0 - 29) 2sec counts
+ * time: 5 - 10: min (0 - 59)
+ * time: 11 - 15: hour (0 - 23)
+ */
+#define SECS_PER_MIN 60
+#define SECS_PER_HOUR (60 * 60)
+#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+/* days between 1.1.70 and 1.1.80 (2 leap days) */
+#define DAYS_DELTA (365 * 10 + 2)
+/* 120 (2100 - 1980) isn't leap year */
+#define YEAR_2100 120
+#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100)
time_t date_dos2unix(const unsigned short f_time, const unsigned short f_date)
{
- static const unsigned int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ static const unsigned int days_in_year[] = { 0, 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0 };
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
- unsigned int month,year,secs;
+ unsigned long int day,leap_day,month,year,days;
+ unsigned long int secs;
+ year = f_date >> 9;
+ month = td_max(1, (f_date >> 5) & 0xf);
+ day = td_max(1, f_date & 0x1f) - 1;
+
+ leap_day = (year + 3) / 4;
+ if (year > YEAR_2100) /* 2100 isn't leap year */
+ leap_day--;
+ if (IS_LEAP_YEAR(year) && month > 2)
+ leap_day++;
+ days = days_in_year[month];
+ /*@ assert days <= 334; */
+ days += year * 365 + leap_day + day + DAYS_DELTA;
+
+ secs = (f_time & 0x1f)<<1;
+ secs += ((f_time >> 5) & 0x3f) * SECS_PER_MIN;
+ secs += (f_time >> 11)* SECS_PER_HOUR;
+ secs += days * SECS_PER_DAY;
- /* first subtract and mask after that... Otherwise, if
- f_date == 0, bad things happen */
- month = ((f_date >> 5) - 1) & 15;
- year = f_date >> 9;
- secs = (f_time & 31)*2+60*((f_time >> 5) & 63)+(f_time >> 11)*3600+86400*
- ((f_date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
- month < 2 ? 1 : 0)+3653);
- /* days since 1.1.70 plus 80's leap day */
return secs+secwest;
}
diff --git a/src/common.h b/src/common.h
index 8a5e5ea..69c5e12 100644
--- a/src/common.h
+++ b/src/common.h
@@ -193,6 +193,8 @@ struct efi_guid_s
((const efi_guid_t){le32(0x4c616265),le16(0x6c00),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
#define GPT_ENT_TYPE_MAC_TV_RECOVERY \
((const efi_guid_t){le32(0x5265636f),le16(0x7665),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_APPLE_CORE_STORAGE \
+ ((const efi_guid_t){le32(0x53746F72),le16(0x6167),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
#define GPT_ENT_TYPE_SOLARIS_BOOT \
((const efi_guid_t){le32(0x6a82cb45),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
@@ -449,6 +451,8 @@ 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);
+
+/*@ assigns \nothing; */
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);
diff --git a/src/fat_unformat.c b/src/fat_unformat.c
index 4cf6a83..a31883c 100644
--- a/src/fat_unformat.c
+++ b/src/fat_unformat.c
@@ -55,6 +55,8 @@
#include "fat_common.h"
#include <assert.h>
+extern int need_to_stop;
+
#define READ_SIZE 4*1024*1024
static int pfind_sectors_per_cluster(disk_t *disk, partition_t *partition, const int verbose, unsigned int *sectors_per_cluster, uint64_t *offset_org, alloc_data_t *list_search_space)
{
@@ -386,6 +388,13 @@ static pstatus_t fat_unformat_aux(struct ph_param *params, const struct ph_optio
}
}
#endif
+ if(need_to_stop!=0)
+ {
+ log_info("PhotoRec has been stopped\n");
+ params->offset=offset;
+ offset = offset_end;
+ ind_stop=PSTATUS_STOP;
+ }
}
}
free(buffer_start);
diff --git a/src/fidentify.c b/src/fidentify.c
index 24b9544..149487f 100644
--- a/src/fidentify.c
+++ b/src/fidentify.c
@@ -60,6 +60,9 @@ extern file_check_list_t file_check_list;
#define OPT_CHECK 1
#define OPT_TIME 2
+/*@
+ @ requires valid_read_string(filename);
+ @*/
static int file_identify(const char *filename, const unsigned int options)
{
const unsigned int blocksize=65536;
@@ -85,9 +88,10 @@ static int file_identify(const char *filename, const unsigned int options)
file_recovery_t file_recovery_new;
file_recovery_t file_recovery;
reset_file_recovery(&file_recovery);
+ reset_file_recovery(&file_recovery_new);
file_recovery.blocksize=blocksize;
file_recovery_new.blocksize=blocksize;
- file_recovery_new.file_stat=NULL;
+ /*@ assert file_recovery_new.file_stat==NULL; */
td_list_for_each(tmpl, &file_check_list.list)
{
struct td_list_head *tmp;
@@ -95,6 +99,7 @@ static int file_identify(const char *filename, const unsigned int options)
td_list_for_each(tmp, &pos->file_checks[buffer[pos->offset]].list)
{
const file_check_t *file_check=td_list_entry_const(tmp, const file_check_t, list);
+ /*@ assert &file_check->header_check != \null; */
if((file_check->length==0 || memcmp(buffer + file_check->offset, file_check->value, file_check->length)==0) &&
file_check->header_check(buffer, blocksize, 0, &file_recovery, &file_recovery_new)!=0)
{
@@ -111,13 +116,15 @@ static int file_identify(const char *filename, const unsigned int options)
((options&OPT_CHECK)!=0 || ((options&OPT_TIME)!=0 && file_recovery_new.time==0))
)
{
+ off_t file_size;
file_recovery_new.handle=file;
my_fseek(file_recovery_new.handle, 0, SEEK_END);
-#ifdef HAVE_FTELLO
- file_recovery_new.file_size=ftello(file_recovery_new.handle);
+#if defined(HAVE_FTELLO) && !defined(__FRAMAC__)
+ file_size=ftello(file_recovery_new.handle);
#else
- file_recovery_new.file_size=ftell(file_recovery_new.handle);
+ file_size=ftell(file_recovery_new.handle);
#endif
+ file_recovery_new.file_size=(file_size==-1?0:file_size);
file_recovery_new.calculated_file_size=file_recovery_new.file_size;
(file_recovery_new.file_check)(&file_recovery_new);
if(file_recovery_new.file_size < file_recovery_new.min_filesize)
@@ -147,7 +154,7 @@ static int file_identify(const char *filename, const unsigned int options)
return 0;
}
-#ifndef __AFL_COMPILER
+#if !defined(__AFL_COMPILER) && !defined(MAIN_fidentify)
static void file_identify_dir(const char *current_dir, const unsigned int options)
{
DIR *dir;
@@ -200,20 +207,27 @@ static void display_version(void)
#ifdef RECORD_COMPILATION_DATE
printf("Compilation date: %s\n", get_compilation_date());
#endif
+#ifndef MAIN_fidentify
printf("libjpeg: %s, zlib: %s\n", td_jpeg_version(), td_zlib_version());
printf("OS: %s\n" , get_os());
+#endif
}
int main(int argc, char **argv)
{
int i;
+#ifdef MAIN_fidentify
+ unsigned int options=OPT_CHECK|OPT_TIME;
+#else
unsigned int options=0;
+#endif
FILE *log_handle=NULL;
int log_errno=0;
int enable_all_formats=1;
int scan_dir=1;
file_stat_t *file_stats;
log_set_levels(LOG_LEVEL_DEBUG|LOG_LEVEL_TRACE|LOG_LEVEL_QUIET|LOG_LEVEL_INFO|LOG_LEVEL_VERBOSE|LOG_LEVEL_PROGRESS|LOG_LEVEL_WARNING|LOG_LEVEL_ERROR|LOG_LEVEL_PERROR|LOG_LEVEL_CRITICAL);
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
if( strcmp(argv[i], "/check")==0 || strcmp(argv[i], "-check")==0 || strcmp(argv[i], "--check")==0)
@@ -238,24 +252,28 @@ int main(int argc, char **argv)
return 0;
}
}
+#endif
#ifndef __AFL_COMPILER
log_handle=log_open("fidentify.log", TD_LOG_CREATE, &log_errno);
if(log_handle!=NULL)
{
time_t my_time;
-#ifdef HAVE_DUP2
+#if defined(HAVE_DUP2) && !defined(__FRAMAC__)
dup2(fileno(log_handle),2);
#endif
my_time=time(NULL);
log_info("\n\n%s",ctime(&my_time));
log_info("Command line: fidentify");
+#ifndef MAIN_fidentify
for(i=1;i<argc;i++)
log_info(" %s", argv[i]);
+#endif
log_info("\n\n");
log_flush();
}
log_info("fidentify %s, Data Recovery Utility, %s\nChristophe GRENIER <grenier@cgsecurity.org>\nhttps://www.cgsecurity.org\n", VERSION, TESTDISKDATE);
#endif
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
file_enable_t *file_enable;
@@ -268,6 +286,7 @@ int main(int argc, char **argv)
enable_all_formats=0;
}
}
+#endif
if(enable_all_formats)
{
/* Enable all file formats */
@@ -276,6 +295,7 @@ int main(int argc, char **argv)
file_enable->enable=1;
}
file_stats=init_file_stats(list_file_enable);
+#ifndef MAIN_fidentify
for(i=1; i<argc; i++)
{
if(strcmp(argv[i], "/check")==0 || strcmp(argv[i], "-check")==0 || strcmp(argv[i], "--check")==0 ||
@@ -306,6 +326,9 @@ int main(int argc, char **argv)
if(scan_dir)
file_identify_dir(".", options);
#endif
+#else
+ file_identify("demo", options);
+#endif
free_header_check();
free(file_stats);
log_close();
diff --git a/src/file_bmp.c b/src/file_bmp.c
index 42209d2..afef52b 100644
--- a/src/file_bmp.c
+++ b/src/file_bmp.c
@@ -63,15 +63,45 @@ struct bmp_header
@ 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);
+ @ requires separation: \separated(&file_hint_bmp, buffer+(..), file_recovery, file_recovery_new);
+ @ assigns file_recovery_new->filename[0];
+ @ assigns file_recovery_new->time;
+ @ assigns file_recovery_new->file_stat;
+ @ assigns file_recovery_new->handle;
+ @ assigns file_recovery_new->file_size;
+ @ assigns file_recovery_new->location.list.prev;
+ @ assigns file_recovery_new->location.list.next;
+ @ assigns file_recovery_new->location.end;
+ @ assigns file_recovery_new->location.data;
+ @ assigns file_recovery_new->extension;
+ @ assigns file_recovery_new->min_filesize;
+ @ assigns file_recovery_new->calculated_file_size;
+ @ assigns file_recovery_new->data_check;
+ @ assigns file_recovery_new->file_check;
+ @ assigns file_recovery_new->file_rename;
+ @ assigns file_recovery_new->offset_error;
+ @ assigns file_recovery_new->offset_ok;
+ @ assigns file_recovery_new->checkpoint_status;
+ @ assigns file_recovery_new->checkpoint_offset;
+ @ assigns file_recovery_new->flags;
+ @ assigns file_recovery_new->extra;
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> \initialized(&file_recovery_new->time);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
@ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bmp.extension);
@ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 65);
@ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
@ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 65);
@ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size);
@ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @ ensures *buffer==\old(*buffer);
@*/
+ /* TODO ensures *file_recovery==\old(*file_recovery); */
static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const struct bmp_header *bm=(const struct bmp_header *)buffer;
@@ -100,6 +130,8 @@ static int header_check_bmp(const unsigned char *buffer, const unsigned int buff
/*@ assert file_recovery_new->min_filesize == 65; */
/*@ assert file_recovery_new->data_check == &data_check_size; */
/*@ assert file_recovery_new->file_check == &file_check_size; */
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ /*@ assert \initialized(&file_recovery_new->time); */
return 1;
}
return 0;
@@ -115,11 +147,10 @@ static void register_header_check_bmp(file_stat_t *file_stat)
#if defined(MAIN_bmp)
#define BLOCKSIZE 65536u
-int main()
+int main(void)
{
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;
diff --git a/src/file_doc.c b/src/file_doc.c
index 67b24ac..4c25d08 100644
--- a/src/file_doc.c
+++ b/src/file_doc.c
@@ -134,6 +134,7 @@ static int OLE_read_block(FILE *IN, unsigned char *buf, const unsigned int uSect
/*@
@ requires \valid_read(dir_entry);
+ @ requires \initialized(dir_entry);
@ ensures \result == \null || valid_read_string(\result);
@*/
static const char *entry2ext(const struct OLE_DIR *dir_entry)
@@ -595,6 +596,7 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
/*@
@ requires \valid(file_recovery);
@ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_doc;
@ ensures \valid(file_recovery->handle);
@*/
static void file_check_doc(file_recovery_t *file_recovery)
@@ -656,16 +658,19 @@ static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const
unsigned int block;
unsigned int i;
const unsigned int uSectorShift=le16(header->uSectorShift);
- if(le32(header->csectMiniFat)==0)
+ /*@ assert uSectorShift==9 || uSectorShift==12; */
+ const unsigned int csectMiniFat=le32(header->csectMiniFat);
+ if(csectMiniFat==0)
return NULL;
- /*@ assert le32(header->csectMiniFat)!=0; */
+ /*@ assert 0 < csectMiniFat; */
+ /*@ assert 0 < csectMiniFat <= 2048; */
#ifdef __FRAMAC__
minifat=(uint32_t*)MALLOC(2048 << 12);
#else
- minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << uSectorShift);
+ minifat=(uint32_t*)MALLOC(csectMiniFat << uSectorShift);
#endif
block=le32(header->MiniFat_block);
- for(i=0; i < le32(header->csectMiniFat); i++)
+ for(i=0; i < csectMiniFat; i++)
{
unsigned char*minifat_pos=(unsigned char*)minifat + (i << uSectorShift);
if(block >= fat_entries)
@@ -686,6 +691,7 @@ static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const
/*@
@ requires \valid_read((char *)buffer + (offset .. offset + 4 - 1));
@ requires \initialized((char *)buffer + (offset .. offset + 4 - 1));
+ @ assigns \nothing;
@*/
static uint32_t get32u(const void *buffer, const unsigned int offset)
{
@@ -696,6 +702,7 @@ static uint32_t get32u(const void *buffer, const unsigned int offset)
/*@
@ requires \valid_read((char *)buffer + (offset .. offset + 8 - 1));
@ requires \initialized((char *)buffer + (offset .. offset + 8 - 1));
+ @ assigns \nothing;
@*/
static uint64_t get64u(const void *buffer, const unsigned int offset)
{
@@ -708,78 +715,115 @@ static uint64_t get64u(const void *buffer, const unsigned int offset)
@ 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);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ assigns *ext;
@*/
static void software2ext(const char **ext, const unsigned char *software, const unsigned int count)
{
- if(count>=12 && memcmp(software, "MicroStation", 12)==0)
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ if(count>=12)
{
- *ext=extension_dgn;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "MicroStation", 12)==0)
+ {
+ *ext=extension_dgn;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- if(count>=14 && memcmp(software, "Microsoft Word", 14)==0)
+ if(count>=14)
{
- *ext=file_hint_doc.extension;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft Word", 14)==0)
+ {
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- if(count>=15 && memcmp(software, "Microsoft Excel", 15)==0)
+ if(count>=15)
{
- if(*ext==NULL || strcmp(*ext,"sldprt")!=0)
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft Excel", 15)==0)
{
- *ext=extension_xls;
- /*@ assert valid_read_string(*ext); */
+ if(*ext==NULL || strcmp(*ext,"sldprt")!=0)
+ {
+ *ext=extension_xls;
+ /*@ assert valid_read_string(*ext); */
+ }
+ return;
}
- return;
}
- if(count>=20 && memcmp(software, "Microsoft PowerPoint", 20)==0)
+ if(count>=20)
{
- *ext=extension_ppt;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft PowerPoint", 20)==0)
+ {
+ *ext=extension_ppt;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- if(count>=21 && memcmp(software, "Microsoft Office Word", 21)==0)
+ if(count>=21)
{
- *ext=file_hint_doc.extension;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "Microsoft Office Word", 21)==0)
+ {
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- if(count==21 && memcmp(software, "TurboCAD for Windows", 21)==0)
+ if(count==21)
{
- *ext=extension_tcw;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "TurboCAD for Windows", 21)==0)
+ {
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- if(count==22 && memcmp(software, "TurboCAD pour Windows", 22)==0)
+ if(count==22)
{
- *ext=extension_tcw;
- /*@ assert valid_read_string(*ext); */
- return;
+ /*@ assert \valid_read(software + (0 .. count-1)); */
+ if(memcmp(software, "TurboCAD pour Windows", 22)==0)
+ {
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
+ return;
+ }
}
- /*@ assert *ext != \null || valid_read_string(*ext); */
+ /*@ assert *ext == \null || valid_read_string(*ext); */
return ;
}
/*@
@ 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);
+ @ assigns \nothing;
@*/
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)
+ if(count>=15)
{
- /*@ assert valid_read_string(extension_et); */
- return extension_et;
+ /*@ assert \valid_read(software + (0 .. 2*count-1)); */
+ if(memcmp(software, "M\0i\0c\0r\0o\0s\0o\0f\0t\0 \0E\0x\0c\0e\0l\0", 30)==0)
+ {
+ /*@ assert valid_read_string(extension_et); */
+ return extension_et;
+ }
}
- if(count>=17 && memcmp(software, "D\0e\0l\0c\0a\0m\0 \0P\0o\0w\0e\0r\0S\0H\0A\0P\0E\0", 34)==0)
+ if(count>=17)
{
- /*@ assert valid_read_string(extension_psmodel); */
- return extension_psmodel;
+ /*@ assert \valid_read(software + (0 .. 2*count-1)); */
+ if(memcmp(software, "D\0e\0l\0c\0a\0m\0 \0P\0o\0w\0e\0r\0S\0H\0A\0P\0E\0", 34)==0)
+ {
+ /*@ assert valid_read_string(extension_psmodel); */
+ return extension_psmodel;
+ }
}
return NULL;
}
@@ -797,6 +841,7 @@ struct summary_entry
@ requires \valid(ext);
@ requires *ext == \null || valid_read_string(*ext);
@ ensures *ext == \null || valid_read_string(*ext);
+ @ assigns *ext;
@*/
static void OLE_parse_software_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, const char **ext)
{
@@ -822,20 +867,25 @@ static void OLE_parse_software_entry(const unsigned char *buffer, const unsigned
return ;
}
/*@ assert offset_soft + count <= size; */
+ /*@ assert count <= size - offset_soft; */
+ /*@ assert \valid_read(buffer + (0 .. size-1)); */
+ /*@ assert \valid_read(buffer + (0 .. offset_soft + count -1)); */
#ifdef DEBUG_OLE
{
unsigned int j;
log_info("Software ");
for(j=0; j<count; j++)
{
- log_info("%c", buffer[offset_soft + j]);
+ /*@ assert 0 <= j < count; */
+ /*@ assert offset_soft + count <= size; */
+ const unsigned int tmp=offset_soft+j;
+ /*@ assert tmp < size; */
+ log_info("%c", buffer[tmp]);
}
log_info("\n");
}
#endif
-#ifndef MAIN_doc
software2ext(ext, &buffer[offset_soft], count);
-#endif
/*@ assert *ext == \null || valid_read_string(*ext); */
}
/*@ assert *ext == \null || valid_read_string(*ext); */
@@ -848,6 +898,7 @@ static void OLE_parse_software_entry(const unsigned char *buffer, const unsigned
@ requires \valid(ext);
@ requires *ext == \null || valid_read_string(*ext);
@ ensures *ext == \null || valid_read_string(*ext);
+ @ assigns *ext;
@*/
static void OLE_parse_uni_software_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, const char **ext)
{
@@ -858,8 +909,8 @@ static void OLE_parse_uni_software_entry(const unsigned char *buffer, const unsi
}
/*@ assert offset < size - 8; */
{
- const unsigned int offset8=offset + 8;
- /*@ assert offset8 < size; */
+ const unsigned int offset_soft=offset + 8;
+ /*@ assert offset_soft < size; */
const unsigned int count=get32u(buffer, offset + 4);
unsigned int count2;
if(count == 0 || count > size/2)
@@ -870,27 +921,31 @@ static void OLE_parse_uni_software_entry(const unsigned char *buffer, const unsi
/*@ assert 0 < count <= size/2; */
count2=2*count;
/*@ assert 0 < count2 <= size; */
- if(count2 > size - offset8)
+ if(count2 > size - offset_soft)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
return ;
}
- /*@ assert count2 <= size - offset8; */
+ /*@ assert count2 <= size - offset_soft; */
+ /*@ assert offset_soft + count2 <= size; */
/*@ assert \valid_read(buffer + (0 .. size - 1)) && \initialized(buffer + (0 .. size - 1)); */
- /*@ assert \valid_read(buffer + (0 .. offset8 + count2 - 1)); */
+ /*@ assert \valid_read(buffer + (0 .. offset_soft + count2 - 1)); */
#ifdef DEBUG_OLE
- unsigned int j;
- log_info("Software ");
- for(j=0; j < 2 * count; j+=2)
{
- log_info("%c", buffer[offset + 8 + j]);
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j < count2; j+=2)
+ {
+ /*@ assert 0 <= j < count2; */
+ /*@ assert offset_soft + count2 <= size; */
+ const unsigned int tmp=offset_soft + j;
+ /*@ assert tmp < size; */
+ log_info("%c", buffer[tmp]);
+ }
+ log_info("\n");
}
- log_info("\n");
-#endif
-#ifndef __FRAMAC__
- /*@ assert \initialized(buffer + (0 .. offset8 + count2 - 1)); */
- *ext=software_uni2ext(&buffer[offset8], count);
#endif
+ *ext=software_uni2ext(&buffer[offset_soft], count);
}
/*@ assert *ext == \null || valid_read_string(*ext); */
}
@@ -898,66 +953,74 @@ static void OLE_parse_uni_software_entry(const unsigned char *buffer, const unsi
/*@
@ requires 8 <= size <= 1024*1024;
@ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \valid(title + (0 .. 1024-1));
+ @ requires valid_string(title);
@ requires \initialized(buffer+ (0 .. size-1));
- @ requires \valid(title);
- @ requires *title == \null || valid_read_string(*title);
- @ ensures *title == \null || valid_read_string(*title);
+ @ ensures valid_string(title);
+ @ assigns *(title + (0 .. 1023));
@*/
-static void OLE_parse_title_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, char **title)
+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 ;
+ 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;
+ const char *src=(const char *)buffer;
if(count <= 1 || count > size)
{
- /*@ assert *title == \null || valid_read_string(*title); */
- return ;
+ return;
}
/*@ assert 1 < count <= size; */
+ /*@ assert 1 < count <= 1024*1024; */
if(offset_tmp + count > size)
{
- /*@ assert *title == \null || valid_read_string(*title); */
- return ;
+ return;
}
/*@ assert offset_tmp + count <= size; */
-#ifndef MAIN_doc
- tmp=(char*)MALLOC(count+1);
- /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read(src + (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);
+ /*@ assert \valid_read(src + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read((src + offset_tmp) + (0 .. count - 1)); */
+ /*@ assert \valid_read((src + offset_tmp) + (1 .. count - 1)); */
+ /*@ assert \valid_read((char*)src + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read(((char*)(src+offset_tmp))+(0..count-1)); */
+ /*@ assert \valid_read(((char*)(src+offset_tmp))+(1..count-1)); */
+ /*@ assert \valid_read((char*)(src + offset_tmp)); */
+ /*@ assert \valid_read((char*)(src + offset_tmp)) && \valid_read(((char*)(src+offset_tmp))+(1..count-1)); */
+ /*@ assert valid_read_or_empty((void const *)(src + offset_tmp), count); */
+ /*@ assert valid_read_or_empty((void const *)(src + offset_tmp), count); */
+#ifndef __FRAMAC__
+ if(count < 1024)
+ {
+ memcpy(title, &src[offset_tmp], count);
+ title[count]='\0';
+ /*@ assert valid_string(title); */
+ }
+ else
+ {
+ memcpy(title, &src[offset_tmp], 1023);
+ title[1023]='\0';
+ /*@ assert valid_string(title); */
+ }
#endif
- *title=tmp;
- /*@ assert valid_read_string(*title); */
+#ifdef DEBUG_OLE
+ log_info("Title %s\n", title);
#endif
}
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
}
+
/*@
@ requires 8 <= size <= 1024*1024;
@ requires \valid_read(buffer+ (0 .. size-1));
@ requires \initialized(buffer+ (0 .. size-1));
@ requires \valid(file_time);
+ @ assigns *file_time;
@*/
static void OLE_parse_filetime_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, time_t *file_time)
{
@@ -981,14 +1044,94 @@ static void OLE_parse_filetime_entry(const unsigned char *buffer, const unsigned
@ requires \valid_read(buffer+ (0 .. size-1));
@ requires \initialized(buffer+ (0 .. size-1));
@ requires \valid(ext);
- @ requires \valid(title);
+ @ requires \valid(title + (0 .. 1024-1));
@ requires \valid(file_time);
- @ requires *title == \null || valid_read_string(*title);
+ @ requires \valid_read(entry);
@ requires *ext == \null || valid_read_string(*ext);
+ @ requires valid_string(title);
+ @ requires separation: \separated(buffer+(..), ext, title + ( 0 .. 1023), file_time);
@ ensures *ext == \null || valid_read_string(*ext);
- @ ensures *title == \null || valid_read_string(*title);
+ @ ensures valid_string(title);
+ @ assigns *ext, *(title + (0..1023)), *file_time;
@*/
-static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned int size, const char **ext, char **title, time_t *file_time)
+static void OLE_parse_PropertySet_entry(const unsigned char *buffer, const unsigned int size, const struct summary_entry *entry, const char **ext, char *title, time_t *file_time)
+{
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_read_string(title); */
+ const unsigned int tag=le32(entry->tag);
+ const unsigned int offset=le32(entry->offset);
+ unsigned int type;
+ if(offset >= size - 4)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
+ }
+ /*@ assert offset < size - 4; */
+ /*@ assert \valid_read(buffer + (0 .. offset + 4 - 1)); */
+ type=get32u(buffer, offset);
+#ifdef DEBUG_OLE
+ log_info("entry 0x%x, tag 0x%x, offset 0x%x, offset + 4 0x%x, type 0x%x\n",
+ entry_offset, tag, offset, offset + 4, type);
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ /* tag: Software, type: VT_LPSTR */
+ if(tag==0x12 && type==30)
+ {
+ /*@ assert valid_string(title); */
+ OLE_parse_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
+ }
+ /* tag: Software, type: VT_LPWSTR */
+ if(tag==0x12 && type==31)
+ {
+ /*@ assert valid_string(title); */
+ OLE_parse_uni_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
+ }
+ /* tag: title, type: VT_LPSTR */
+ if(tag==0x02 && type==30 && title[0]=='\0')
+ {
+ OLE_parse_title_entry(buffer, size, offset, title);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return ;
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ /* ModifyDate, type=VT_FILETIME */
+ if(tag==0x0d && type==64)
+ {
+ OLE_parse_filetime_entry(buffer, size, offset, file_time);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
+ return;
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \valid(ext);
+ @ requires \valid(title + (0 .. 1024-1));
+ @ requires \valid(file_time);
+ @ requires valid_string(title);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires separation: \separated(buffer+(..), ext, title + (0 .. 1023), file_time);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures valid_string(title);
+ @*/
+/*X TODO assigns *ext, *(title + (0..1023)), *file_time; */
+/*X TODO requires \initialized(buffer+ (0 .. size-1)); */
+static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned int size, const char **ext, char *title, time_t *file_time)
{
const struct summary_entry *entries=(const struct summary_entry *)&buffer[8];
const unsigned int numEntries=get32u(buffer, 4);
@@ -997,18 +1140,18 @@ static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned in
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); */
+ /*@ assert valid_string(title); */
if(numEntries == 0 || numEntries > 1024*1024)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_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); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert 8 + numEntries * 8 <= size; */
@@ -1017,76 +1160,42 @@ static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned in
if((const unsigned char *)&entries[numEntries] > &buffer[size])
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
/*@ assert \valid_read(buffer + (0 .. size - 1)); */
/*@ assert \valid_read((buffer+8) + (8 .. size - 8 - 1)); */
/*@
@ loop invariant *ext == \null || valid_read_string(*ext);
- @ loop invariant *title == \null || valid_read_string(*title);
+ @ loop invariant valid_string(title);
@ loop invariant 0 <= i <= numEntries;
@ loop variant numEntries-i;
@*/
+ /*X TODO loop assigns *ext, *(title + (0..1023)), *file_time; */
for(i=0; i<numEntries; i++)
{
+ const struct summary_entry *entry;
const unsigned int entry_offset=8+8*i;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
if(entry_offset + 8 > size)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_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(offset >= size - 4)
- {
- /*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
- return ;
- }
- /*@ assert offset < size - 4; */
- /*@ assert \valid_read(buffer + (0 .. offset + 4 - 1)); */
- type=get32u(buffer, offset);
-#ifdef DEBUG_OLE
- log_info("entry 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)
- {
- 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)
- {
- 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)
- {
- OLE_parse_title_entry(buffer, size, offset, title);
- /*@ assert *title == \null || valid_read_string(*title); */
- }
- /* ModifyDate, type=VT_FILETIME */
- if(tag==0x0d && type==64)
- {
- OLE_parse_filetime_entry(buffer, size, offset, file_time);
- }
- }
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
+ entry=(const struct summary_entry *)&buffer[entry_offset];
+ OLE_parse_PropertySet_entry(buffer, size, entry, ext, title, file_time);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
}
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
}
/*@
@@ -1094,19 +1203,21 @@ static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned in
@ requires \valid_read(dataPt + (0 .. dirLen-1));
@ requires \initialized(dataPt + (0 .. dirLen-1));
@ requires \valid(ext);
- @ requires \valid(title);
+ @ requires \valid(title + (0 .. 1024-1));
@ requires \valid(file_time);
- @ requires *title == \null || valid_read_string(*title);
+ @ requires valid_string(title);
@ requires *ext == \null || valid_read_string(*ext);
+ @ requires separation: \separated(dataPt+(..), ext, title + (0 .. 1023), file_time);
@ ensures *ext == \null || valid_read_string(*ext);
- @ ensures *title == \null || valid_read_string(*title);
+ @ ensures valid_string(title);
@*/
-static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char **title, time_t *file_time)
+/*X TODO assigns *ext, *(title + (0..1023)), *file_time; */
+static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char *title, time_t *file_time)
{
unsigned int pos;
assert(dirLen >= 48 && dirLen<=1024*1024);
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
#ifdef DEBUG_OLE
dump_log(dataPt, dirLen);
#endif
@@ -1116,7 +1227,7 @@ static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned in
if(pos > dirLen - 8)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert pos <= dirLen - 8; */
@@ -1126,7 +1237,7 @@ static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned in
if(size <= 8 || size > dirLen || pos + size > dirLen)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert 8 < size; */
@@ -1135,14 +1246,15 @@ static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned in
/*@ assert \valid_read(dataPt + (0 .. dirLen-1)); */
/*@ assert pos + size <= dirLen; */
/*@ assert \valid_read(dataPt + (0 .. pos+size-1)); */
+ /*@ assert \initialized(dataPt + (0 .. dirLen-1)); */
+ /*@ assert pos + size <= dirLen; */
+ /*X TODO assert \initialized(dataPt + (0 .. pos+size-1)); */
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
-#ifndef __FRAMAC__
+ /*@ assert valid_string(title); */
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); */
+ /*@ assert valid_string(title); */
}
/*@
@@ -1196,24 +1308,27 @@ static void *OLE_read_ministream(unsigned char *ministream,
@ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift);
@ requires 6 == le16(header->uMiniSectorShift);
@ requires \valid(ext);
- @ requires \valid(title);
+ @ requires \valid(title + (0 .. 1024-1));
@ requires \valid(file_time);
@ requires *ext == \null || valid_read_string(*ext);
- @ requires *title == \null || valid_read_string(*title);
+ @ requires valid_string(title);
+ @ requires separation: \separated(file,fat+(..), header, ext, title + (0 .. 1023), file_time);
@ ensures *ext == \null || valid_read_string(*ext);
- @ ensures *title == \null || valid_read_string(*title);
+ @ ensures valid_string(title);
@*/
static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries,
const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size,
- const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time,
+ const unsigned int block, const unsigned int len, const char **ext, char *title, time_t *file_time,
const uint64_t offset)
{
const unsigned int uSectorShift=le16(header->uSectorShift);
unsigned char *summary=NULL;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert valid_string(title); */
if(len < 48 || len>1024*1024)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert 48 <= len <= 1024*1024; */
@@ -1222,13 +1337,13 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
if(le32(header->csectMiniFat)==0 || ministream_size == 0)
{
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_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); */
+ /*@ assert valid_string(title); */
return ;
}
/*@ assert 0 < le32(header->csectMiniFat) <= 2048; */
@@ -1239,7 +1354,7 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
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); */
+ /*@ assert valid_string(title); */
return ;
}
ministream=(unsigned char *)OLE_read_stream(file,
@@ -1265,9 +1380,13 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
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); */
+#if 0
+ OLE_parse_summary_aux(summary, 4096, ext, title, file_time);
+ /*@ assert valid_string(title); */
+#else
OLE_parse_PropertySet(summary, 4096, ext, title, file_time);
+#endif
+ /*@ assert valid_string(title); */
free(summary);
}
#else
@@ -1278,17 +1397,18 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
}
#endif
/*@ assert *ext == \null || valid_read_string(*ext); */
- /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert valid_string(title); */
}
/*@
@ requires \valid(file_recovery);
@ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_doc;
@*/
static void file_rename_doc(file_recovery_t *file_recovery)
{
const char *ext=NULL;
- char *title=NULL;
+ char title[1024];
FILE *file;
unsigned char buffer_header[512];
uint32_t *fat;
@@ -1297,6 +1417,8 @@ static void file_rename_doc(file_recovery_t *file_recovery)
unsigned int fat_entries;
unsigned int uSectorShift;
unsigned int num_FAT_blocks;
+ title[0]='\0';
+ /*@ assert valid_string(&title[0]); */
if(strstr(file_recovery->filename, ".sdd")!=NULL)
ext=extension_sdd;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
@@ -1358,10 +1480,15 @@ static void file_rename_doc(file_recovery_t *file_recovery)
#ifdef DEBUG_OLE
log_info("file_rename_doc root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
+#ifndef __FRAMAC__
for(block=le32(header->root_start_block), i=0;
block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
block=le32(fat[block]), i++)
+#else
+ block=le32(header->root_start_block), i=0;
+#endif
{
+ /*@ assert valid_string(&title[0]); */
struct OLE_DIR *dir_entries;
#ifdef __FRAMAC__
dir_entries=(struct OLE_DIR *)MALLOC(1<<12);
@@ -1373,12 +1500,12 @@ static void file_rename_doc(file_recovery_t *file_recovery)
free(fat);
free(dir_entries);
fclose(file);
- free(title);
return ;
}
#ifdef DEBUG_OLE
log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
+ /*@ assert valid_string(&title[0]); */
{
unsigned int sid;
int is_db=0;
@@ -1388,10 +1515,12 @@ static void file_rename_doc(file_recovery_t *file_recovery)
ministream_block=le32(dir_entry->start_block);
ministream_size=le32(dir_entry->size);
}
+ /*@ assert valid_string(&title[0]); */
for(sid=0;
sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
sid++)
{
+ /*@ assert valid_string(&title[0]); */
const struct OLE_DIR *dir_entry=&dir_entries[sid];
if(dir_entry->type!=NO_ENTRY)
{
@@ -1403,9 +1532,10 @@ static void file_rename_doc(file_recovery_t *file_recovery)
'r', '\0', 'm', '\0', 'a', '\0', 't', '\0',
'i', '\0', 'o', '\0', 'n', '\0', '\0', '\0'
};
+ const unsigned int namsiz=le16(dir_entry->namsiz);
#ifdef DEBUG_OLE
unsigned int j;
- for(j=0;j<64 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
+ for(j=0;j<64 && j<namsiz && dir_entry->name[j]!='\0';j+=2)
{
log_info("%c",dir_entry->name[j]);
}
@@ -1422,13 +1552,15 @@ static void file_rename_doc(file_recovery_t *file_recovery)
ext=tmp;
/*@ assert ext == \null || valid_read_string(ext); */
}
- switch(le16(dir_entry->namsiz))
+ /*@ assert valid_string(&title[0]); */
+ switch(namsiz)
{
case 4:
if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0)
is_db=1;
else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "2\0\0\0", 4)==0)
is_db=2;
+ /*@ assert valid_string(&title[0]); */
break;
case 16:
if(sid==1 && memcmp(dir_entry->name, "d\0o\0c\0.\0d\0e\0t\0\0\0", 16)==0)
@@ -1438,6 +1570,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
ext=extension_snt;
else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0\0\0", 16)==0)
is_db=2;
+ /*@ assert valid_string(&title[0]); */
break;
case 18:
/* MS Excel
@@ -1445,36 +1578,50 @@ static void file_rename_doc(file_recovery_t *file_recovery)
if(ext==NULL &&
memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
ext=extension_xls;
+ /*@ assert valid_string(&title[0]); */
break;
case 36:
/* sda=StarDraw, sdd=StarImpress */
if(ext!=extension_sdd &&
memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
ext=extension_sda;
+ /*@ assert valid_string(&title[0]); */
break;
case 40:
if(memcmp(dir_entry->name, SummaryInformation, 40)==0)
{
+ /*@ assert ext == \null || valid_read_string(ext); */
+ /*@ assert valid_string(&title[0]); */
OLE_parse_summary(file, fat, fat_entries, header,
ministream_block, ministream_size,
le32(dir_entry->start_block), le32(dir_entry->size),
- &ext, &title, &file_time, 0);
+ &ext, &title[0], &file_time, 0);
+ /*@ assert valid_string(&title[0]); */
+ /*@ assert ext == \null || valid_read_string(ext); */
}
+ /*@ assert valid_string(&title[0]); */
+ break;
+ default:
+ /*@ assert valid_string(&title[0]); */
break;
}
- if(sid==1 && le16(dir_entry->namsiz) >=6 &&
+ /*@ assert valid_string(&title[0]); */
+ if(sid==1 && namsiz >=6 &&
memcmp(dir_entry->name, "D\0g\0n", 6)==0)
ext=extension_dgn;
#ifdef DEBUG_OLE
if(ext!=NULL)
- log_info("Found %s %u\n", ext, le16(dir_entry->namsiz));
+ log_info("Found %s %u\n", ext, namsiz);
#endif
+ /*@ assert valid_string(&title[0]); */
}
+ /*@ assert valid_string(&title[0]); */
}
if(ext==NULL && is_db==2)
ext=extension_db;
}
free(dir_entries);
+ /*@ assert valid_string(&title[0]); */
}
}
free(fat);
@@ -1483,8 +1630,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
set_date(file_recovery->filename, file_time, file_time);
if(title!=NULL)
{
- file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, ext, 1);
- free(title);
+ file_rename(file_recovery, &title, strlen((const char *)title), 0, ext, 1);
}
else
file_rename(file_recovery, NULL, 0, 0, ext, 1);
@@ -1501,12 +1647,16 @@ static void file_rename_doc(file_recovery_t *file_recovery)
@ ensures \result == 0 || \result == 1;
@ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
@ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
@ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
@ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_doc);
@ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_doc);
@ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
@ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
+ // TODO ensures *buffer == \old(*buffer);
+ // TODO ensures *file_recovery == \old(*file_recovery);
static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
/*@ assert file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename); */
@@ -1677,6 +1827,7 @@ int main()
memcpy(file_recovery_new.filename, fn, sizeof(fn));
/*@ assert valid_read_string((char *)&file_recovery_new.filename); */
/*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*X TODO assert valid_read_string(file_recovery_new.extension); */
file_recovery_new.file_stat=&file_stats;
if(file_recovery_new.file_stat!=NULL)
{
diff --git a/src/file_emf.c b/src/file_emf.c
index db02070..b4a10d0 100644
--- a/src/file_emf.c
+++ b/src/file_emf.c
@@ -30,10 +30,11 @@
#include "filegen.h"
#include "log.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_emf(file_stat_t *file_stat);
-static int header_check_emf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-static data_check_t data_check_emf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
const file_hint_t file_hint_emf= {
.extension="emf",
@@ -201,37 +202,30 @@ struct EMF_HDR
#define EMR_COLORMATCHTOTARGETW 121
#define EMR_CREATECOLORSPACEW 122
-static int header_check_emf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- static const unsigned char emf_header[4]= { 0x01, 0x00, 0x00, 0x00};
- const struct EMF_HDR *hdr=(const struct EMF_HDR *)buffer;
- const unsigned int atom_size=le32(hdr->emr.nSize);
- if(memcmp(buffer,emf_header,sizeof(emf_header))==0 &&
- le32(hdr->nBytes) >= 88 &&
- le16(hdr->sReserved)==0 &&
- atom_size>=0x34 && atom_size%4==0)
- {
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_emf.extension;
- if(file_recovery_new->blocksize >= 8)
- {
- file_recovery_new->data_check=&data_check_emf;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=atom_size;
- }
- return 1;
- }
- return 0;
-}
-
+/*@
+ @ requires buffer_size >= 2;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_emf;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP || \result == DC_ERROR;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 8);
+ @ ensures file_recovery->data_check==&data_check_emf;
+ @ assigns file_recovery->calculated_file_size;
+ @*/
static data_check_t data_check_emf(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
+ /*@
+ @ loop assigns file_recovery->calculated_file_size;
+ @*/
while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2)
{
- const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
- const unsigned int itype=buffer[i]+(buffer[i+1]<<8)+(buffer[i+2]<<16)+(buffer[i+3]<<24);
- const unsigned int atom_size=buffer[i+4]+(buffer[i+5]<<8)+(buffer[i+6]<<16)+(buffer[i+7]<<24);
+ const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert 0 <= i < buffer_size - 8 ; */
+ const U_EMR *hdr=(const U_EMR *)&buffer[i];
+ const unsigned int itype=le32(hdr->iType);
+ const unsigned int atom_size=le32(hdr->nSize);
#ifdef DEBUG_EMF
log_trace("0x%llx ", (long long unsigned)file_recovery->calculated_file_size);
switch(itype)
@@ -362,15 +356,158 @@ static data_check_t data_check_emf(const unsigned char *buffer, const unsigned i
#endif
if(atom_size<8 || atom_size%4!=0 || atom_size>1024*1024)
return DC_ERROR;
+ /*@ assert 8 <= atom_size <= 1024*1024; */
file_recovery->calculated_file_size+=(uint64_t)atom_size;
if(itype==EMR_EOF)
return DC_STOP;
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size + buffer_size/2 - 8 + 1024*1024; */
}
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 8; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 8; */
return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_emf.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 0x34);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_emf);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_emf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ static const unsigned char emf_header[4]= { 0x01, 0x00, 0x00, 0x00};
+ const struct EMF_HDR *hdr=(const struct EMF_HDR *)buffer;
+ const unsigned int atom_size=le32(hdr->emr.nSize);
+ if(buffer_size < sizeof(struct EMF_HDR))
+ return 0;
+ if(memcmp(buffer,emf_header,sizeof(emf_header))==0 &&
+ le32(hdr->nBytes) >= 88 &&
+ le16(hdr->sReserved)==0 &&
+ atom_size>=0x34 && atom_size%4==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_emf.extension;
+ if(file_recovery_new->blocksize >= 8)
+ {
+ file_recovery_new->data_check=&data_check_emf;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->calculated_file_size=atom_size;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_emf(file_stat_t *file_stat)
{
static const unsigned char emf_sign[4]= { ' ','E', 'M','F'};
register_header_check(0x28, emf_sign,sizeof(emf_sign), &header_check_emf, file_stat);
}
+
+#if defined(MAIN_emf)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.emf";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_emf;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_emf(&file_stats);
+ if(header_check_emf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.calculated_file_size > 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_emf; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_rename == \null; */
+ /*@ assert file_recovery_new.extension == file_hint_emf.extension; */
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert \separated(&file_recovery_new, file_recovery_new.extension); */
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*X TODO assert valid_read_string(file_recovery_new.extension); */
+ file_recovery_new.file_stat=&file_stats;
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_emf; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_emf(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_emf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ {
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_exe.c b/src/file_exe.c
index ade58b0..2050e21 100644
--- a/src/file_exe.c
+++ b/src/file_exe.c
@@ -58,11 +58,19 @@ static const unsigned char exe_header[2] = {'M','Z'};
@ requires buffer_size >= 2;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
@ requires \valid(file_recovery_new);
@ requires file_recovery_new->blocksize > 0;
- @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ requires separation: \separated(&file_hint_exe, buffer+(..), file_recovery, file_recovery_new);
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_exe.extension || file_recovery_new->extension == extension_dll);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null || file_recovery_new->data_check == &data_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == \null || file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null || file_recovery_new->file_rename == &file_rename_pe_exe);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
@@ -285,6 +293,7 @@ static char InternalName[24]={
@ requires needle_len > 0;
@ requires \valid_read(buffer+(0..end-1));
@ requires \valid_read(needle+(0..needle_len-1));
+ @ requires \separated(file_recovery, buffer+(..), needle+(..));
@*/
static int parse_String(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
@@ -300,12 +309,16 @@ static int parse_String(file_recovery_t *file_recovery, const char*buffer, const
len=le16(PE_index->len);
val_len=le16(PE_index->val_len);
type=le16(PE_index->type);
+#ifdef DEBUG_EXE
log_info("parse_String len=%u val_len=%u type=%u\n", len, val_len, type);
+#endif
if(len > end)
return -1;
if(6 + 2 * val_len > len)
return -1;
+#ifdef DEBUG_EXE
dump_log(buffer, len);
+#endif
// type=1 => text
if(6+needle_len < end && type==1 && memcmp(&buffer[6], needle, needle_len)==0)
{
@@ -322,11 +335,14 @@ static int parse_String(file_recovery_t *file_recovery, const char*buffer, const
@ requires needle_len > 0;
@ requires \valid_read(buffer+(0..end-1));
@ requires \valid_read(needle+(0..needle_len-1));
+ @ requires \separated(file_recovery, buffer+(..), needle+(..));
@*/
static int parse_StringArray(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
unsigned int pos=0;
+#ifdef DEBUG_EXE
log_info("parse_StringArray end=%u\n", end);
+#endif
/*@
@ loop variant end - pos;
@*/
@@ -350,6 +366,7 @@ static int parse_StringArray(file_recovery_t *file_recovery, const char*buffer,
@ requires needle_len > 0;
@ requires \valid_read(buffer+(0..end-1));
@ requires \valid_read(needle+(0..needle_len-1));
+ @ requires \separated(file_recovery, buffer+(..), needle+(..));
@*/
static int parse_StringTable(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
@@ -365,7 +382,9 @@ static int parse_StringTable(file_recovery_t *file_recovery, const char*buffer,
/*@ assert \valid_read(PE_index); */
len=le16(PE_index->len);
val_len=le16(PE_index->val_len);
+#ifdef DEBUG_EXE
log_info("parse_StringTable len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+#endif
if(len > end)
return -1;
/* szKey: language identifier + code page */
@@ -385,6 +404,7 @@ static int parse_StringTable(file_recovery_t *file_recovery, const char*buffer,
@ requires needle_len > 0;
@ requires \valid_read(buffer+(0..end-1));
@ requires \valid_read(needle+(0..needle_len-1));
+ @ requires \separated(file_recovery, buffer+(..), needle+(..));
@*/
static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
@@ -401,7 +421,9 @@ static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffe
/*@ assert \valid_read(PE_index); */
len=le16(PE_index->len);
val_len=le16(PE_index->val_len);
+#ifdef DEBUG_EXE
log_info("parse_StringFileInfo len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+#endif
if(len > end)
return -1;
if(6 + sizeof(StringFileInfo) > end)
@@ -427,6 +449,8 @@ static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffe
@ requires needle_len > 0;
@ requires \valid_read(buffer+(0..end-1));
@ requires \valid_read(needle+(0..needle_len-1));
+ @ requires \separated(vs_version_info+(..), file_recovery, buffer+(..), needle+(..));
+ @ behavior types: requires \separated(vs_version_info+(..), \union(file_recovery, buffer+(..), needle+(..)));
@*/
static int parse_VS_VERSIONINFO(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
@@ -444,7 +468,9 @@ static int parse_VS_VERSIONINFO(file_recovery_t *file_recovery, const char*buffe
/*@ assert \valid_read(PE_index); */
len=le16(PE_index->len);
val_len=le16(PE_index->val_len);
+#ifdef DEBUG_EXE
log_info("parse_VS_VERSIONINFO len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+#endif
if(len==0 && val_len==0)
{
return -1;
@@ -488,7 +514,9 @@ static int parse_VS_VERSIONINFO(file_recovery_t *file_recovery, const char*buffe
static void PEVersion(FILE *file, const unsigned int offset, const unsigned int length, file_recovery_t *file_recovery)
{
char buffer[1024*1024];
+#ifdef DEBUG_EXE
log_info("PEVersion(file, %u, %u, file_recovery)\n", offset, length);
+#endif
if(length==0 || length > 1024*1024)
return;
if(fseek(file, offset, SEEK_SET)<0)
@@ -586,7 +614,9 @@ static void pe_resource_language(FILE *file, const unsigned int base, const unsi
idEntries = buffer[14]+(buffer[15]<<8);
count = nameEntries + idEntries;
}
+#ifdef DEBUG_EXE
log_info("pe_resource_language count=%u\n", count);
+#endif
if(count==0 || count > 1024)
return ;
/*@ assert 0 < count <= 1024; */
@@ -765,6 +795,7 @@ static void pe_resource_type(FILE *file, const unsigned int base, const unsigned
/*@
@ requires \valid(file_recovery);
@ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_pe_exe;
@*/
static void file_rename_pe_exe(file_recovery_t *file_recovery)
{
@@ -954,17 +985,19 @@ int main()
}
if(file_recovery_new.file_check!=NULL)
{
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
file_recovery_new.handle=fopen(fn, "rb");
if(file_recovery_new.handle!=NULL)
{
- (file_recovery_new.file_check)(&file_recovery_new);
+ file_check_size(&file_recovery_new);
fclose(file_recovery_new.handle);
}
}
if(file_recovery_new.file_rename!=NULL)
{
/*@ assert valid_read_string((char *)&file_recovery_new.filename); */
- (file_recovery_new.file_rename)(&file_recovery_new);
+ /*@ assert file_recovery_new.file_rename == &file_rename_pe_exe; */
+ file_rename_pe_exe(&file_recovery_new);
}
return 0;
}
diff --git a/src/file_gpg.c b/src/file_gpg.c
index 84a5587..ec9635e 100644
--- a/src/file_gpg.c
+++ b/src/file_gpg.c
@@ -87,6 +87,7 @@ static const unsigned char pgp_header[5]= {0xa8, 0x03, 'P', 'G', 'P'};
/*@
@ ensures 0 <= \result <= 0x3f;
+ @ assigns \nothing;
@*/
static unsigned int openpgp_packet_tag(const unsigned char buf)
{
@@ -100,6 +101,7 @@ static unsigned int openpgp_packet_tag(const unsigned char buf)
@ requires \valid(length_type);
@ requires \valid(indeterminate_length);
@ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==3)|| (*length_type==5);
+ @ assigns *length_type, *indeterminate_length;
*/
static unsigned int old_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *indeterminate_length)
{
@@ -130,6 +132,7 @@ static unsigned int old_format_packet_length(const unsigned char *buf, unsigned
@ requires \valid(partial_body_length);
@ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==5);
@ ensures (*partial_body_length==0) || (*partial_body_length==1);
+ @ assigns *length_type, *partial_body_length;
*/
static unsigned int new_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *partial_body_length)
{
@@ -172,6 +175,7 @@ static unsigned int new_format_packet_length(const unsigned char *buf, unsigned
/*@
@ ensures \result == -1 || 0 <= \result <= 2048;
+ @ assigns \nothing;
@*/
static int is_valid_mpi(const uint16_t size)
{
@@ -183,6 +187,7 @@ static int is_valid_mpi(const uint16_t size)
/*@
@ ensures \result == 0 || \result == 1;
+ @ assigns \nothing;
@*/
static int is_valid_pubkey_algo(const int algo)
{
@@ -213,6 +218,7 @@ static int is_valid_pubkey_algo(const int algo)
/*@
@ ensures \result == 0 || \result == 1;
+ @ assigns \nothing;
@*/
static int is_valid_sym_algo(const int algo)
{
@@ -249,6 +255,7 @@ static int is_valid_sym_algo(const int algo)
/*@
@ ensures \result == 0 || \result == 1;
+ @ assigns \nothing;
@*/
static int is_valid_S2K(const unsigned int algo)
{
@@ -266,6 +273,7 @@ static int is_valid_S2K(const unsigned int algo)
/*@
@ requires \valid(file_recovery);
@ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_gpg;
@*/
static void file_check_gpg(file_recovery_t *file_recovery)
{
@@ -466,8 +474,18 @@ static void file_check_gpg(file_recovery_t *file_recovery)
@ 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->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_gpg.extension || file_recovery_new->extension == extension_pgp);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_gpg);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
static int header_check_gpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
@@ -737,7 +755,6 @@ 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;
diff --git a/src/file_gz.c b/src/file_gz.c
index 0ef52e0..ba5b112 100644
--- a/src/file_gz.c
+++ b/src/file_gz.c
@@ -157,18 +157,7 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
}
if(off >= 512 || off >= buffer_size)
return 0;
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_doc)
- {
- if(header_ignored_adv(file_recovery, file_recovery_new)==0)
- return 0;
- }
- if(file_recovery->file_check==&file_check_bgzf)
- {
- header_ignored(file_recovery_new);
- return 0;
- }
-#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
+#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ) && !defined(__FRAMAC__)
{
static const unsigned char schematic_header[12]={ 0x0a, 0x00, 0x09,
'S', 'c', 'h', 'e', 'm', 'a', 't', 'i', 'c'};
@@ -207,6 +196,17 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
/* Probably too small to be a file */
if(d_stream.total_out < 16)
return 0;
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_doc)
+ {
+ if(header_ignored_adv(file_recovery, file_recovery_new)==0)
+ return 0;
+ }
+ if(file_recovery->file_check==&file_check_bgzf)
+ {
+ header_ignored(file_recovery_new);
+ return 0;
+ }
buffer_uncompr[d_stream.total_out]='\0';
if(bgzf!=0)
{
@@ -297,6 +297,17 @@ static int header_check_gz(const unsigned char *buffer, const unsigned int buffe
}
}
#else
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_doc)
+ {
+ if(header_ignored_adv(file_recovery, file_recovery_new)==0)
+ return 0;
+ }
+ if(file_recovery->file_check==&file_check_bgzf)
+ {
+ header_ignored(file_recovery_new);
+ return 0;
+ }
reset_file_recovery(file_recovery_new);
file_recovery_new->min_filesize=22;
file_recovery_new->time=le32(gz->mtime);
diff --git a/src/file_jpg.c b/src/file_jpg.c
index 64abd7b..376f1b7 100644
--- a/src/file_jpg.c
+++ b/src/file_jpg.c
@@ -53,7 +53,7 @@
#include "__fc_builtin.h"
#endif
-#ifndef MAIN_jpg
+#if !defined(MAIN_jpg) && !defined(MAIN_fidentify)
extern const file_hint_t file_hint_doc;
extern const file_hint_t file_hint_indd;
extern const file_hint_t file_hint_mov;
@@ -64,7 +64,7 @@ extern data_check_t data_check_avi_stream(const unsigned char *buffer, const uns
static void register_header_check_jpg(file_stat_t *file_stat);
static void file_check_jpg(file_recovery_t *file_recovery);
-data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+static data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned i, const unsigned int size);
const file_hint_t file_hint_jpg= {
@@ -112,7 +112,7 @@ struct MP_IFD_Field
uint16_t tag;
uint16_t type;
uint32_t count;
- char value[0];
+ char value[4];
} __attribute__ ((gcc_struct, __packed__));
struct MP_Entry
@@ -126,7 +126,8 @@ struct MP_Entry
/*@
@ requires size >= 8;
- @ requires \valid(mpo + ( 0 .. size-1));
+ @ requires \valid_read(mpo + ( 0 .. size-1));
+ @ assigns \nothing;
@*/
static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size)
{
@@ -137,40 +138,55 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
unsigned int nbr;
unsigned int NumberOfImages=0;
unsigned int MPEntry_offset=0;
- const struct MP_Entry* MPEntry;
uint64_t max_offset=0;
#ifdef DEBUG_JPEG
log_info("check_mpo_be\n");
#endif
- if(offset+2 >= size)
+ if(offset >= size - 2)
return 0;
+ /*@ assert offset < size - 2; */
tmp16=(const uint16_t*)(&mpo[offset]);
nbr=be16(*tmp16);
offset+=2;
+ /* @offset: MP Index Fields*/
+ if(offset + nbr * 12 > size)
+ return 0;
+ /*@ assert offset + nbr * 12 <= size; */
+ /*@
+ @ loop invariant 0 <= i <= nbr;
+ @ loop assigns i, NumberOfImages, MPEntry_offset;
+ @ loop variant nbr-i;
+ @*/
for(i=0; i< nbr; i++)
{
- const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)(&mpo[offset]);
- if(offset+12 > size)
- return 0;
+ /*@ assert 0 <= i < nbr; */
+ const unsigned char *field_ptr=&mpo[offset + i * 12];
+ /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */
+ const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr;
+ const unsigned int count=be32(field->count);
+ const unsigned int type=be16(field->type);
switch(be16(field->tag))
{
case 0xb000:
/* MPFVersion, type must be undefined */
- if(be16(field->type)!=7 || be32(field->count)!=4)
+ if(type!=7 || count!=4)
return 0;
break;
case 0xb001:
/* NumberOfImages, type must be long */
- if(be16(field->type)!=4 || be32(field->count)!=1)
+ if(type!=4 || count!=1)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
NumberOfImages=be32(*tmp);
+ if(NumberOfImages >= 0x100000)
+ return 0;
+ /*@ assert NumberOfImages < 0x100000; */
}
break;
case 0xb002:
/* MPEntry, type must be undefined */
- if(be16(field->type)!=7 || be32(field->count)!=16*NumberOfImages)
+ if(type!=7 || count!=16*NumberOfImages)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
@@ -178,25 +194,34 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
}
break;
}
- offset+=12;
}
#ifdef DEBUG_JPEG
log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages);
#endif
+ /*@ assert NumberOfImages < 0x100000; */
+ if(MPEntry_offset > size)
+ return 0;
if(MPEntry_offset + 16*NumberOfImages > size)
return 0;
- for(i=0, MPEntry=(const struct MP_Entry*)(&mpo[MPEntry_offset]);
- i<NumberOfImages;
- i++, MPEntry++)
+ /*@
+ @ loop invariant 0 <= i <= NumberOfImages;
+ @ loop assigns i, max_offset;
+ @ loop variant NumberOfImages-i;
+ @*/
+ for(i=0; i<NumberOfImages; i++)
{
- uint64_t tmp=be32(MPEntry->offset)+be32(MPEntry->size);
+ /*@ assert 0 <= i < NumberOfImages; */
+ const unsigned char *MPEntry_ptr=&mpo[MPEntry_offset + i * sizeof(struct MP_Entry)];
+ /*@ assert \valid_read(MPEntry_ptr+ ( 0 .. sizeof(struct MP_Entry)-1)); */
+ const struct MP_Entry *MPEntry=(const struct MP_Entry*)MPEntry_ptr;
+ uint64_t tmp=be32(MPEntry->size);
#ifdef DEBUG_JPEG
log_info("offset=%lu, size=%lu\n",
(long unsigned)be32(MPEntry->offset),
(long unsigned)be32(MPEntry->size));
#endif
if(be32(MPEntry->offset)>0)
- tmp+=mpo_offset;
+ tmp+=be32(MPEntry->offset)+mpo_offset;
if(max_offset < tmp)
max_offset = tmp;
}
@@ -205,51 +230,69 @@ static uint64_t check_mpo_be(const unsigned char *mpo, const uint64_t mpo_offset
/*@
@ requires size >= 8;
- @ requires \valid(mpo + ( 0 .. size-1));
+ @ requires \valid_read(mpo + ( 0 .. size-1));
+ @ assigns \nothing;
@*/
static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset, const unsigned int size)
{
const uint16_t *tmp16;
+ /* Offset to first IFD */
const uint32_t *tmp32=(const uint32_t *)(&mpo[4]);
unsigned int offset=le32(*tmp32);
unsigned int i;
unsigned int nbr;
unsigned int NumberOfImages=0;
unsigned int MPEntry_offset=0;
- const struct MP_Entry* MPEntry;
uint64_t max_offset=0;
#ifdef DEBUG_JPEG
log_info("check_mpo_le\n");
#endif
- if(offset+2 >= size)
+ if(offset >= size - 2)
return 0;
+ /*@ assert offset < size - 2; */
tmp16=(const uint16_t*)(&mpo[offset]);
nbr=le16(*tmp16);
offset+=2;
+ /* @offset: MP Index Fields*/
+ if(offset + nbr * 12 > size)
+ return 0;
+ /*@ assert offset + nbr * 12 <= size; */
+ /*@
+ @ loop invariant 0 <= i <= nbr;
+ @ loop assigns i, NumberOfImages, MPEntry_offset;
+ @ loop variant nbr-i;
+ @*/
for(i=0; i< nbr; i++)
{
- const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)(&mpo[offset]);
- if(offset+12 > size)
- return 0;
+ /*@ assert 0 <= i < nbr; */
+ const unsigned char *field_ptr=&mpo[offset + i * 12];
+ /*@ assert \valid_read(field_ptr + ( 0 .. sizeof(struct MP_IFD_Field)-1)); */
+ const struct MP_IFD_Field *field=(const struct MP_IFD_Field *)field_ptr;
+ /*@ assert \valid_read(field); */
+ const unsigned int count=le32(field->count);
+ const unsigned int type=le16(field->type);
switch(le16(field->tag))
{
case 0xb000:
/* MPFVersion, type must be undefined */
- if(le16(field->type)!=7 || le32(field->count)!=4)
+ if(type!=7 || count!=4)
return 0;
break;
case 0xb001:
/* NumberOfImages, type must be long */
- if(le16(field->type)!=4 || le32(field->count)!=1)
+ if(type!=4 || count!=1)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
NumberOfImages=le32(*tmp);
+ if(NumberOfImages >= 0x100000)
+ return 0;
+ /*@ assert NumberOfImages < 0x100000; */
}
break;
case 0xb002:
/* MPEntry, type must be undefined */
- if(le16(field->type)!=7 || le32(field->count)!=16*NumberOfImages)
+ if(type!=7 || count!=16*NumberOfImages)
return 0;
{
const uint32_t *tmp=(const uint32_t *)&field->value[0];
@@ -257,25 +300,34 @@ static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset
}
break;
}
- offset+=12;
}
#ifdef DEBUG_JPEG
log_info("MPEntry_offset=%u, NumberOfImages=%u\n", MPEntry_offset, NumberOfImages);
#endif
+ /*@ assert NumberOfImages < 0x100000; */
+ if(MPEntry_offset > size)
+ return 0;
if(MPEntry_offset + 16*NumberOfImages > size)
return 0;
- for(i=0, MPEntry=(const struct MP_Entry*)(&mpo[MPEntry_offset]);
- i<NumberOfImages;
- i++, MPEntry++)
+ /*@
+ @ loop invariant 0 <= i <= NumberOfImages;
+ @ loop assigns i, max_offset;
+ @ loop variant NumberOfImages-i;
+ @*/
+ for(i=0; i<NumberOfImages; i++)
{
- uint64_t tmp=le32(MPEntry->offset)+le32(MPEntry->size);
+ /*@ assert 0 <= i < NumberOfImages; */
+ const unsigned char *MPEntry_ptr=&mpo[MPEntry_offset + i * sizeof(struct MP_Entry)];
+ /*@ assert \valid_read(MPEntry_ptr+ ( 0 .. sizeof(struct MP_Entry)-1)); */
+ const struct MP_Entry *MPEntry=(const struct MP_Entry*)MPEntry_ptr;
+ uint64_t tmp=le32(MPEntry->size);
#ifdef DEBUG_JPEG
log_info("offset=%lu, size=%lu\n",
(long unsigned)le32(MPEntry->offset),
(long unsigned)le32(MPEntry->size));
#endif
if(le32(MPEntry->offset)>0)
- tmp+=mpo_offset;
+ tmp+=(uint64_t)le32(MPEntry->offset) + mpo_offset;
if(max_offset < tmp)
max_offset = tmp;
}
@@ -284,10 +336,15 @@ static uint64_t check_mpo_le(const unsigned char *mpo, const uint64_t mpo_offset
/*@
@ requires size >= 8;
- @ requires \valid(mpo + ( 0 .. size-1));
+ @ requires \valid_read(mpo + ( 0 .. size-1));
+ @ assigns \nothing;
@*/
static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const unsigned int size)
{
+ /* MP header:
+ * - MP Endian (4Byte)
+ * - Offset to First IFD (4Byte)
+ */
if(mpo[0]=='I' && mpo[1]=='I' && mpo[2]=='*' && mpo[3]==0)
{
return check_mpo_le(mpo, offset, size);
@@ -304,6 +361,7 @@ static uint64_t check_mpo(const unsigned char *mpo, const uint64_t offset, const
@ requires \valid(fr->handle);
@ requires valid_read_string((char *)&fr->filename);
@ requires \initialized(&fr->time);
+ @ requires fr->file_check==&file_check_mpo;
@*/
static void file_check_mpo(file_recovery_t *fr)
{
@@ -322,6 +380,12 @@ static void file_check_mpo(file_recovery_t *fr)
do
{
offset+=(uint64_t)2+size;
+ if(offset >= 0x8000000000000000)
+ {
+ fr->file_size=0;
+ return ;
+ }
+ /*@ assert offset < 0x8000000000000000; */
if(my_fseek(fr->handle, offset, SEEK_SET) < 0)
{
fr->file_size=0;
@@ -354,7 +418,7 @@ static void file_check_mpo(file_recovery_t *fr)
fr->file_size=0;
return ;
}
- /*@ assert 16 <= size; */
+ /*@ assert 16 <= size <= 65535; */
{
const uint64_t max_offset=check_mpo(buffer+8, offset+8, size-8);
fr->file_size=(max_offset > fr->file_size ? 0 : max_offset);
@@ -428,25 +492,55 @@ static time_t jpg_get_date(const unsigned char *buffer, const unsigned int buffe
/*@
+ @ requires buffer_size >= 10;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid_read(file_recovery);
@ requires file_recovery->file_stat==\null || valid_read_string((char*)&file_recovery->filename);
@ requires \valid(file_recovery_new);
@ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_jpg, buffer+(..), file_recovery, file_recovery_new);
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
@ ensures \result == 1 ==> file_recovery_new->extension == file_hint_jpg.extension;
- @ ensures \result == 1 ==> valid_read_string(file_recovery_new->extension);
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
@ ensures \result == 1 ==> file_recovery_new->calculated_file_size == 0;
@ ensures \result == 1 ==> file_recovery_new->file_size == 0;
+ @ ensures \result == 1 ==> file_recovery_new->min_filesize > 0;
@ ensures \result == 1 ==> file_recovery_new->offset_ok == 0;
- @ ensures \result == 1 ==> 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;
+ @ ensures \result == 1 ==> file_recovery_new->file_check == file_check_jpg;
+ @ ensures \result == 1 ==> file_recovery_new->file_rename == \null;
+ @ ensures \result == 1 ==> valid_read_string(file_recovery_new->extension);
@*/
static int header_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
unsigned int i=2;
time_t jpg_time=0;
+ while(i+4<buffer_size && buffer[i]==0xff && is_marker_valid(buffer[i+1]))
+ {
+ const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
+ if(buffer[i+1]==0xff)
+ i++;
+ else
+ {
+ if(buffer[i+1]==0xe1)
+ { /* APP1 Exif information */
+ jpg_time=jpg_get_date(buffer, buffer_size, i, size);
+ }
+ else if(buffer[i+1]==0xc4)
+ {
+ /* DHT */
+ if(jpg_check_dht(buffer, buffer_size, i, 2+(buffer[i+2]<<8)+buffer[i+3])!=0)
+ return 0;
+ }
+ i+=2+size;
+ }
+ }
+ if(i+1 < file_recovery_new->blocksize && buffer[i+1]!=0xda)
+ return 0;
+ if(i+1 < 512 && buffer[i+1]!=0xda)
+ return 0;
if(file_recovery->file_stat!=NULL)
{
static const unsigned char jpg_header_app0_avi[0x0c]= {
@@ -459,7 +553,7 @@ 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 !defined(MAIN_jpg) && !defined(MAIN_fidentify)
if(file_recovery->file_stat->file_hint==&file_hint_indd)
{
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
@@ -505,7 +599,7 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
return 0;
}
}
-#ifndef MAIN_jpg
+#if !defined(MAIN_jpg) && !defined(MAIN_fidentify)
/* Don't extract jpg inside AVI */
if( file_recovery->file_stat->file_hint==&file_hint_riff &&
(memcmp(buffer, jpg_header_app0_avi, sizeof(jpg_header_app0_avi))==0 ||
@@ -555,30 +649,6 @@ static int header_check_jpg(const unsigned char *buffer, const unsigned int buff
return 0;
}
}
- while(i+4<buffer_size && buffer[i]==0xff && is_marker_valid(buffer[i+1]))
- {
- const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
- if(buffer[i+1]==0xff)
- i++;
- else
- {
- if(buffer[i+1]==0xe1)
- { /* APP1 Exif information */
- jpg_time=jpg_get_date(buffer, buffer_size, i, size);
- }
- else if(buffer[i+1]==0xc4)
- {
- /* DHT */
- if(jpg_check_dht(buffer, buffer_size, i, 2+(buffer[i+2]<<8)+buffer[i+3])!=0)
- return 0;
- }
- i+=2+size;
- }
- }
- if(i+1 < file_recovery_new->blocksize && buffer[i+1]!=0xda)
- return 0;
- if(i+1 < 512 && buffer[i+1]!=0xda)
- return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->min_filesize=i;
file_recovery_new->calculated_file_size=0;
@@ -1400,6 +1470,7 @@ static void jpg_check_picture(file_recovery_t *file_recovery)
/*@
@ requires i < buffer_size;
@ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
@*/
static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int i, const unsigned int size)
{
@@ -1408,6 +1479,7 @@ static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_
/* DHT should not be longer than 1088 bytes, 4*(1+16+255) */
if(size<18)
return 2;
+ /*@ loop assigns j; */
while(j < buffer_size && j < i+size)
{
const unsigned int tc=buffer[j]>>4;
@@ -1421,6 +1493,12 @@ static int jpg_check_dht(const unsigned char *buffer, const unsigned int buffer_
if(n > 3)
return 2;
j++;
+ /*@
+ @ loop invariant 0 <= l <= 16;
+ @ loop invariant sum <= l*255;
+ @ loop assigns l,sum;
+ @ loop variant 16-l;
+ @*/
for(l=0; l < 16; l++)
if(j+l < buffer_size)
sum+=buffer[j+l];
@@ -1449,6 +1527,7 @@ struct sof_header
/*@
@ requires \valid_read(buffer + (0..buffer_size-1));
+ @ assigns \nothing;
@*/
static int jpg_check_sof0(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int i)
{
@@ -1485,43 +1564,46 @@ 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;
+ const uint64_t offset_error=file_recovery->offset_error;
+ uint64_t offset_test=offset_error;
uint64_t offset;
- /*@ assert offset_test == file_recovery->offset_error; */
+ /*@ assert offset_test == offset_error; */
if(file_recovery->blocksize==0)
return ;
offset=offset_test / file_recovery->blocksize * file_recovery->blocksize;
if(my_fseek(infile, offset, SEEK_SET) < 0)
return ;
- /*@ assert offset_test == file_recovery->offset_error; */
+ /*@ assert offset_test == offset_error; */
/*@
- @ loop invariant offset_test >= file_recovery->offset_error;
+ @ loop invariant offset_test >= offset_error;
@*/
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 ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
#endif
+ /*@ assert offset_test >= offset_error; */
offset=offset_test / file_recovery->blocksize * file_recovery->blocksize;
i=offset_test % file_recovery->blocksize;
/*@ assert offset + i == offset_test; */
/*@ assert i == offset_test - offset; */
- /*@ assert offset_test >= file_recovery->offset_error; */
+ /*@ assert offset_test >= offset_error; */
/*@
@ loop invariant offset + i >= offset_test;
- @ loop invariant offset_test >= file_recovery->offset_error;
+ @ loop invariant offset_test >= offset_error;
@ loop invariant 0 <= i < nbytes + file_recovery->blocksize;
@ loop assigns i,file_recovery->extra;
@*/
while(i+1<nbytes)
{
const uint64_t tmp=offset + i;
+ /*@ assert tmp == offset + i; */
/*@ assert tmp >= offset_test; */
+ /*@ assert offset_test >= offset_error; */
if(buffer[i]==0xff &&
(buffer[i+1]==0xd8 || /* SOI */
buffer[i+1]==0xdb || /* DQT */
@@ -1532,7 +1614,7 @@ static void jpg_search_marker(file_recovery_t *file_recovery)
buffer[i+1]==0xfe) /* COM */
)
{
- file_recovery->extra=tmp - file_recovery->offset_error;
+ file_recovery->extra=tmp - offset_error;
#ifndef __FRAMAC__
if(file_recovery->extra % file_recovery->blocksize != 0)
{
@@ -1683,40 +1765,49 @@ static int jpg_check_app1(file_recovery_t *file_recovery, const unsigned int ext
j+=2U+(buffer[j+2]<<8)+buffer[j+3];
}
if(thumb_sos_found>0 && extract_thumb>0
- && offset < nbytes && buffer[offset]==0xff)
+ && offset < nbytes && buffer[offset]==0xff &&
+ *thumb_offset+thumb_size < nbytes)
{
- char *thumbname;
+ char thumbname[2048];
+ char *sep;
+ /*@ assert sizeof(thumbname) == sizeof(file_recovery->filename); */
/*@ assert valid_read_string((char *)&file_recovery->filename); */
+ memcpy(thumbname,file_recovery->filename, sizeof(thumbname));
+ thumbname[sizeof(thumbname)-1]='\0';
+ /*@ assert valid_read_string(&thumbname[0]); */
+ sep=strrchr(thumbname,'/');
+ if(sep!=NULL
#ifndef __FRAMAC__
- thumbname=strdup(file_recovery->filename);
- if(thumbname!=NULL)
+ && *(sep+1)=='f'
+#endif
+ )
{
- char *sep;
- /*@ assert thumbname!=\null; */
- /*@ assert valid_read_string(thumbname); */
- sep=strrchr(thumbname,'/');
- if(sep!=NULL && *(sep+1)=='f' && *thumb_offset+thumb_size < nbytes)
+ FILE *out;
+#ifndef __FRAMAC__
+ *(sep+1)='t';
+#endif
+ if((out=fopen(thumbname,"wb"))!=NULL)
{
- FILE *out;
- *(sep+1)='t';
- if((out=fopen(thumbname,"wb"))!=NULL)
- {
- if(fwrite(&buffer[*thumb_offset], 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
+ const char *buffer_char=(const char *)buffer;
+ /*@ assert \valid_read(buffer_char + (0 .. nbytes - 1)); */
+ /*@ assert *thumb_offset + thumb_size < nbytes; */
+ /*@ assert \valid_read(buffer_char + (0 .. *thumb_offset + thumb_size - 1)); */
+ /*@ assert \valid_read(buffer_char + *thumb_offset + (0 .. thumb_size - 1)); */
+ const char *thumb_char=&buffer_char[*thumb_offset];
+ /*@ assert \valid_read(thumb_char + (0 .. thumb_size - 1)); */
+ if(fwrite(thumb_char, thumb_size, 1, out) < 1)
{
- log_error("fopen %s failed\n", thumbname);
+ 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);
}
-#endif
}
}
return 1;
@@ -1831,6 +1922,7 @@ static uint64_t jpg_check_structure(file_recovery_t *file_recovery, const unsign
@ requires \valid(file_recovery->handle);
@ requires valid_read_string((char *)&file_recovery->filename);
@ requires \initialized(&file_recovery->time);
+ @ requires file_recovery->file_check == &file_check_mpo || file_recovery->file_check == &file_check_jpg;
@*/
static void file_check_jpg(file_recovery_t *file_recovery)
{
@@ -1854,8 +1946,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 __FRAMAC__
-#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H) && !defined(__FRAMAC__)
if(thumb_offset!=0 &&
(file_recovery->checkpoint_status==0 || thumb_error!=0) &&
(file_recovery->offset_error==0 || thumb_offset < file_recovery->offset_error))
@@ -1900,34 +1991,41 @@ static void file_check_jpg(file_recovery_t *file_recovery)
return ;
}
#endif
-#endif
}
/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
@ requires \valid(file_recovery);
+ @ requires file_recovery->calculated_file_size >= 2;
@ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @ requires file_recovery->data_check == &data_check_jpg2;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == \null;
+ @ ensures file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2;
+ @ ensures file_recovery->data_check == \null ==> file_recovery->calculated_file_size == 0;
+ @ assigns file_recovery->calculated_file_size;
+ @ assigns file_recovery->data_check;
+ @ assigns file_recovery->offset_error;
@*/
static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
-#if 0
- unsigned int old_marker=0;
-#endif
- if(file_recovery->calculated_file_size<2)
- {
- /* Reset to the correct file checker */
- file_recovery->data_check=&data_check_jpg;
- return data_check_jpg(buffer, buffer_size, file_recovery);
- }
+ /*@
+ @ loop assigns file_recovery->calculated_file_size;
+ @ loop assigns file_recovery->data_check;
+ @ loop assigns file_recovery->offset_error;
+ @*/
while(file_recovery->calculated_file_size + buffer_size/2 > file_recovery->file_size &&
file_recovery->calculated_file_size < file_recovery->file_size + buffer_size/2)
{
const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
if(buffer[i-1]==0xFF)
{
if(buffer[i]==0xd9)
{
/* JPEG_EOI */
file_recovery->calculated_file_size++;
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
return DC_STOP;
}
else if(buffer[i] >= 0xd0 && buffer[i] <= 0xd7)
@@ -1946,6 +2044,7 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
/* TODO: store old_marker in file_recovery */
old_marker=buffer[i];
#endif
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
}
else if(buffer[i] == 0xda || buffer[i] == 0xc4)
{
@@ -1961,9 +2060,11 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
(long long unsigned)file_recovery->calculated_file_size);
#endif
file_recovery->offset_error=file_recovery->calculated_file_size;
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
return DC_STOP;
}
}
+ /*@ assert file_recovery->data_check == &data_check_jpg2; */
file_recovery->calculated_file_size++;
}
return DC_CONTINUE;
@@ -1971,22 +2072,39 @@ static data_check_t data_check_jpg2(const unsigned char *buffer, const unsigned
/*@
@ requires buffer_size >= 8;
+ @ requires (buffer_size&1)==0;
@ requires \valid(file_recovery);
@ requires buffer_size >= 4;
@ requires \valid_read(buffer + ( 0 .. buffer_size-1));
+ @ requires file_recovery->data_check == &data_check_jpg;
@ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == &data_check_jpg || file_recovery->data_check == &data_check_size || file_recovery->data_check == \null;
+ @ ensures file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2;
+ @ assigns file_recovery->calculated_file_size;
+ @ assigns file_recovery->data_check;
+ @ assigns file_recovery->file_check;
+ @ assigns file_recovery->offset_error;
@*/
/* FIXME requires file_recovery->file_size == 0 || file_recovery->calculated_file_size >= file_recovery->file_size - 4; */
/* FIXME ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4); */
-data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+static data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
/* Skip the SOI */
- if(file_recovery->calculated_file_size==0)
- file_recovery->calculated_file_size+=2;
+ if(file_recovery->calculated_file_size<2)
+ file_recovery->calculated_file_size=2;
+ /*@ assert file_recovery->calculated_file_size >= 2; */
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
/* Search SOS */
+ /*@
+ @ loop assigns file_recovery->calculated_file_size;
+ @ loop assigns file_recovery->data_check;
+ @ loop assigns file_recovery->file_check;
+ @ loop assigns file_recovery->offset_error;
+ @*/
while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
file_recovery->calculated_file_size + 4 < file_recovery->file_size + buffer_size/2)
{
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
/*@ assert 0 <= i < buffer_size - 4 ; */
if(buffer[i]==0xFF && buffer[i+1]==0xFF)
@@ -1994,6 +2112,7 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
else if(buffer[i]==0xFF)
{
const unsigned int size=(buffer[i+2]<<8)+buffer[i+3];
+ const uint64_t old_calculated_file_size=file_recovery->calculated_file_size;
#ifdef DEBUG_JPEG
log_info("data_check_jpg %02x%02x at %llu, next expected at %llu\n", buffer[i], buffer[i+1],
(long long unsigned)file_recovery->calculated_file_size,
@@ -2003,48 +2122,68 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
if(buffer[i+1]==0xc0) /* SOF0 */
{
if(jpg_check_sof0(buffer, buffer_size, i)!=0)
+ {
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
return DC_STOP;
+ }
}
else if(buffer[i+1]==0xc4) /* DHT */
{
if(jpg_check_dht(buffer, buffer_size, i, 2+size)!=0)
+ {
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
return DC_STOP;
+ }
}
else if(buffer[i+1]==0xda) /* SOS: Start Of Scan */
{
+ data_check_t tmp;
file_recovery->data_check=&data_check_jpg2;
- return data_check_jpg2(buffer, buffer_size, file_recovery);
+ /*@ assert file_recovery->calculated_file_size >= 2; */
+ tmp=data_check_jpg2(buffer, buffer_size, file_recovery);
+ /*@ assert file_recovery->data_check == &data_check_jpg2 || file_recovery->data_check == \null; */
+ /*@ assert file_recovery->data_check == &data_check_jpg2 ==> file_recovery->calculated_file_size >= 2; */
+ return tmp;
}
else if(buffer[i+1]==0xe2) /* APP2 Exif information */
{
if(i+8 < buffer_size &&
buffer[i+4]=='M' && buffer[i+5]=='P' && buffer[i+6]=='F' && buffer[i+7]==0)
{
- const uint64_t offset=file_recovery->calculated_file_size-(2+size)+8;
+ const uint64_t offset=old_calculated_file_size+8;
if(i>=buffer_size/2)
{
/* Restore previous value */
- file_recovery->calculated_file_size-=2+size;
+ file_recovery->calculated_file_size=old_calculated_file_size;
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
return DC_CONTINUE;
}
/*@ assert 0 <= i < buffer_size / 2 ; */
if( i + size <= buffer_size)
{
/*@ assert i + size <= buffer_size; */
+ /*@ assert size <= buffer_size - i; */
if(size >= 16)
{
- /*@ assert 16 <= size; */
-#ifndef __FRAMAC__
- const uint64_t calculated_file_size=check_mpo(buffer+i+8, offset, size-8);
+ /*@ assert 16 <= size <= 65535; */
+ /*@ assert \valid_read(buffer + (0 .. buffer_size-1)); */
+ /*@ assert \valid_read(buffer + (0 .. i+size-1)); */
+ /*@ assert \valid_read((buffer + i ) + (0 .. size-1)); */
+ /*@ assert \valid_read((buffer + i + 8) + (0 .. size-8-1)); */
+ const unsigned char *mpo=buffer + i + 8;
+ const unsigned int size_mpo=size-8;
+ /*@ assert \valid_read(mpo + (0 .. size-8-1)); */
+ /*@ assert \valid_read(mpo + (0 .. size_mpo-1)); */
+ const uint64_t calculated_file_size=check_mpo(mpo, offset, size_mpo);
if(calculated_file_size > 0)
{
/* Multi-picture format */
file_recovery->calculated_file_size=calculated_file_size;
file_recovery->data_check=&data_check_size;
file_recovery->file_check=&file_check_mpo;
+ /*@ assert file_recovery->data_check == &data_check_size; */
return DC_CONTINUE;
}
-#endif
}
}
else
@@ -2061,6 +2200,7 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
file_recovery->calculated_file_size=calculated_file_size;
file_recovery->data_check=&data_check_size;
file_recovery->file_check=&file_check_mpo;
+ /*@ assert file_recovery->data_check == &data_check_size; */
return DC_CONTINUE;
}
}
@@ -2074,11 +2214,13 @@ data_check_t data_check_jpg(const unsigned char *buffer, const unsigned int buff
log_info("data_check_jpg %02x at %llu\n", buffer[i],
(long long unsigned)file_recovery->calculated_file_size);
#endif
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
return DC_STOP;
}
}
+ /*@ assert file_recovery->data_check == &data_check_jpg; */
/*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */
- /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */
+ /*X TODO assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 4; */
return DC_CONTINUE;
}
@@ -2168,6 +2310,7 @@ int main()
/*@ assert file_recovery_new.data_check == &data_check_jpg; */
/*@ assert file_recovery_new.file_size == 0; */;
res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ /*@ assert file_recovery_new.data_check == &data_check_jpg2 ==> file_recovery_new.calculated_file_size >= 2; */
file_recovery_new.file_size+=BLOCKSIZE;
if(res_data_check == DC_CONTINUE)
{
@@ -2175,7 +2318,29 @@ int main()
#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.data_check == &data_check_jpg || file_recovery_new.data_check == &data_check_jpg2 || file_recovery_new.data_check == &data_check_size || file_recovery_new.data_check == NULL; */
+ if(file_recovery_new.data_check == &data_check_jpg)
+ res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ else if(file_recovery_new.data_check == &data_check_jpg2)
+ res_data_check=data_check_jpg2(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ else if(file_recovery_new.data_check == &data_check_size)
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ /*@ assert file_recovery_new.data_check == &data_check_jpg || file_recovery_new.data_check == &data_check_jpg2 || file_recovery_new.data_check == &data_check_size || file_recovery_new.data_check == NULL; */
+ if(file_recovery_new.data_check == &data_check_jpg)
+ res_data_check=data_check_jpg(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ else if(file_recovery_new.data_check == &data_check_jpg2)
+ res_data_check=data_check_jpg2(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ else if(file_recovery_new.data_check == &data_check_size)
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ }
}
}
/*@ assert file_recovery_new.offset_ok == 0; */
@@ -2190,7 +2355,8 @@ int main()
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; */
+ /*@ assert file_recovery_new.file_check == file_check_jpg || file_recovery_new.file_check == file_check_mpo; */
+ if(file_recovery_new.file_check == file_check_jpg)
{
file_recovery_new.handle=fopen(fn, "rb");
if(file_recovery_new.handle!=NULL)
@@ -2199,7 +2365,9 @@ int main()
fclose(file_recovery_new.handle);
}
}
+ else
{
+ /*@ assert file_recovery_new.file_check == file_check_mpo; */
file_recovery_new.handle=fopen(fn, "rb");
if(file_recovery_new.handle!=NULL)
{
diff --git a/src/file_list.c b/src/file_list.c
index f706680..0c6b183 100644
--- a/src/file_list.c
+++ b/src/file_list.c
@@ -288,6 +288,7 @@ extern const file_hint_t file_hint_rpm;
extern const file_hint_t file_hint_rw2;
extern const file_hint_t file_hint_rx2;
extern const file_hint_t file_hint_save;
+extern const file_hint_t file_hint_sdsk;
extern const file_hint_t file_hint_ses;
extern const file_hint_t file_hint_sgcta;
extern const file_hint_t file_hint_shn;
@@ -365,6 +366,7 @@ extern const file_hint_t file_hint_zpr;
file_enable_t list_file_enable[]=
{
+#ifndef MAIN_fidentify
{ .enable=0, .file_hint=&file_hint_sig },
{ .enable=0, .file_hint=&file_hint_1cd },
{ .enable=0, .file_hint=&file_hint_3dm },
@@ -404,7 +406,9 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_binvox },
{ .enable=0, .file_hint=&file_hint_bkf },
{ .enable=0, .file_hint=&file_hint_blend },
+#endif
{ .enable=0, .file_hint=&file_hint_bmp },
+#ifndef MAIN_fidentify
{ .enable=0, .file_hint=&file_hint_bpg },
{ .enable=0, .file_hint=&file_hint_bvr },
{ .enable=0, .file_hint=&file_hint_bz2 },
@@ -626,6 +630,7 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_rw2 },
{ .enable=0, .file_hint=&file_hint_rx2 },
{ .enable=0, .file_hint=&file_hint_save },
+ { .enable=0, .file_hint=&file_hint_sdsk },
{ .enable=0, .file_hint=&file_hint_ses },
{ .enable=0, .file_hint=&file_hint_sgcta },
{ .enable=0, .file_hint=&file_hint_shn },
@@ -700,6 +705,7 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_zcode },
{ .enable=0, .file_hint=&file_hint_zip },
{ .enable=0, .file_hint=&file_hint_zpr },
+#endif
{ .enable=0, .file_hint=NULL }
};
diff --git a/src/file_mov.c b/src/file_mov.c
index 6e71676..a403eb9 100644
--- a/src/file_mov.c
+++ b/src/file_mov.c
@@ -103,6 +103,7 @@ static void file_rename_mov(file_recovery_t *file_recovery)
/*@
@ requires buffer_size >= 16;
+ @ requires (buffer_size&1)==0;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid(file_recovery);
@ requires file_recovery->data_check==&data_check_mov;
@@ -136,8 +137,9 @@ static data_check_t data_check_mov(const unsigned char *buffer, const unsigned i
}
else if(atom_size<8)
return DC_STOP;
- if(atom_size >= 0x80000000)
+ if(atom_size >= 0x800000000000)
return DC_STOP;
+ /*@ assert 8 <= atom_size < 0x800000000000; */
#ifdef DEBUG_MOV
log_trace("file_mov.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n",
file_recovery->filename,
@@ -199,10 +201,13 @@ static data_check_t data_check_mov(const unsigned char *buffer, const unsigned i
@ requires buffer_size >= 16;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
@ requires \valid(file_recovery_new);
@ requires file_recovery_new->blocksize > 0;
@ requires separation: \separated(file_recovery, file_recovery_new);
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mov.extension ||
file_recovery_new->extension == extension_3g2 ||
file_recovery_new->extension == extension_3gp ||
@@ -211,12 +216,14 @@ static data_check_t data_check_mov(const unsigned char *buffer, const unsigned i
file_recovery_new->extension == extension_jp2 ||
file_recovery_new->extension == extension_m4p ||
file_recovery_new->extension == extension_mp4);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
@ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
@ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_mov || file_recovery_new->file_rename == \null);
@ ensures (\result == 1 && file_recovery_new->extension == file_hint_mov.extension) ==> (file_recovery_new->file_rename == file_rename_mov);
@ ensures (\result == 1 && file_recovery_new->extension != file_hint_mov.extension) ==> (file_recovery_new->file_rename == \null);
@ ensures (\result == 1 && (file_recovery_new->extension == extension_jp2 || file_recovery_new->blocksize < 16)) ==> (file_recovery_new->data_check == \null && file_recovery_new->file_check == \null && file_recovery_new->file_rename == \null && file_recovery_new->min_filesize > 0);
@ ensures (\result == 1 && file_recovery_new->extension != extension_jp2 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->calculated_file_size > 0 && file_recovery_new->file_check == &file_check_size && file_recovery_new->data_check == &data_check_mov);
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
static int header_check_mov_aux(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
@@ -238,9 +245,9 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
else if(atom_size<8)
return 0;
/*@ assert 8 <= atom_size; */
- if(atom_size >= 0x80000000)
+ if(atom_size >= 0x800000000000)
return 0;
- /*@ assert 8 <= atom_size < 0x80000000; */
+ /*@ assert 8 <= atom_size < 0x800000000000; */
calculated_file_size=atom_size+i;
/* check for commun atom type */
if(buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t')
diff --git a/src/file_mp3.c b/src/file_mp3.c
index 25d688a..11431da 100644
--- a/src/file_mp3.c
+++ b/src/file_mp3.c
@@ -35,16 +35,12 @@
#include "__fc_builtin.h"
#endif
-#if !defined(MAIN_mp3) && !defined(MAIN_id3)
+#if !defined(MAIN_mp3)
extern const file_hint_t file_hint_mkv;
extern const file_hint_t file_hint_tiff;
#endif
static void register_header_check_mp3(file_stat_t *file_stat);
-static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
-static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
-static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size);
-static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size);
const file_hint_t file_hint_mp3= {
.extension="mp3",
@@ -55,7 +51,6 @@ const file_hint_t file_hint_mp3= {
.register_header_check=&register_header_check_mp3
};
-
#define MPEG_V25 0
#define MPEG_V2 0x2
#define MPEG_V1 0x3
@@ -117,232 +112,167 @@ 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);
+ @ 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 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)
+static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
{
- if(buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3' && (buffer[3]==2 || buffer[3]==3 || buffer[3]==4) && buffer[4]==0)
- {
- unsigned int potential_frame_offset=0;
- /*
- * TODO Handle ID3 tag
- * http://www.id3.org/id3v2-00
- * http://www.id3.org/id3v2.3.0
- */
- if(buffer[3]==4 && (buffer[5]&0x10)==0x10) /* a footer is present http://www.id3.org/id3v2.4.0-structure chap. 3.1 */
- potential_frame_offset = 10;
-
- potential_frame_offset+=((buffer[6]&0x7f)<<21) + ((buffer[7]&0x7f)<<14)
- + ((buffer[8]&0x7f)<<7) + (buffer[9]&0x7f)+ 10;
-
- /*
- log_info("ID3v2.%u found \n potential_frame_offset at 0x%x\n",buffer[3], potential_frame_offset);
- */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->calculated_file_size=potential_frame_offset;
- /*@ assert file_recovery_new->calculated_file_size > 0; */
- file_recovery_new->min_filesize=287;
- file_recovery_new->data_check=&data_check_id3;
- file_recovery_new->extension=file_hint_mp3.extension;
- file_recovery_new->file_check=&file_check_size;
- return 1;
- }
+ 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;
}
-#endif
-#ifndef MAIN_id3
/*@
- @ requires buffer_size >= 6;
+ @ requires 0 < buffer_size <= 10*1024*1024;
+ @ requires i <= buffer_size;
@ 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);
+ @ ensures \result <= buffer_size + 0x80;
+ @ assigns \nothing;
@*/
-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)
+static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size)
{
- unsigned int potential_frame_offset=0;
- unsigned int nbr=0;
/*
- A Frame sync 11 (length in bits)
- B MPEG audio version (MPEG-1, 2, etc.) 2
- C MPEG layer (Layer I, II, III, etc.) 2
- D Protection (if on, then checksum follows header) 1
- AAAA AAAA AAAB BCCD
- 1111 1111 1111 1010 = FA = MPEG-1 layer 3
- 1111 1111 1111 0010 = F2 = MPEG-2 layer 3
- 1111 1111 1110 0010 = E2 = MPEG-2.5 layer 3
-
- http://www.dv.co.yu/mpgscript/mpeghdr.htm
- */
- if(!(buffer[0]==0xFF &&
- ((buffer[1]&0xFE)==0xFA ||
- (buffer[1]&0xFE)==0xF2 ||
- (buffer[1]&0xFE)==0xE2)))
+ Check for MusicMatch Tag
+ http://freenet-homepage.de/StefanRypalla/stuff/musicmatch.txt
+ min size = 8192bytes
+ header is optional
+ structure :
+ header 256 bytes optional
+ image extension 4 bytes
+ image binary >= 4 bytes
+ unused 4 bytes
+ version info 256 bytes
+ audio meta-data >= 7868 bytes
+ In all versions of the MusicMatch format up to and including 3.00,
+ this section (audio meta-data) is always 7868 bytes in length.
+ All subsequent versions allowed three possible lengths for this section: 7936, 8004, and 8132 bytes.
+ data offsets 20 bytes
+ Footer 48 bytes (optional?!)
+ */
+ const unsigned char mm_header[10]= {'1','8','2','7','3','6','4','5',0x00, 0x00};
+ const unsigned char mm_pad_version_info[14] = {0x00,0x00,0x00,0x00,'1','8','2','7','3','6','4','5',0x00,0x00};
+ const char mm_footer[]="Brava Software Inc.";
+ const char mm_footer_tag[]="TAG";
+ unsigned int size=0;
+ if(i+sizeof(mm_header)>buffer_size)
return 0;
- if(file_recovery->file_stat!=NULL)
+ /*@ assert i + sizeof(mm_header) <= buffer_size; */
+ if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header
{
- if(file_recovery->file_stat->file_hint==&file_hint_mp3
-#if !defined(MAIN_mp3) && !defined(MAIN_id3)
- || file_recovery->file_stat->file_hint==&file_hint_mkv
-#endif
- )
- {
- header_ignored(file_recovery_new);
+ size=256;
+ /* Don't check image extension */
+ /* log_info("search_MMT: mm_header present\n"); */
+ }
+ else
+ {
+ /* Check image extension */
+ if( memcmp(&buffer[i]," ",4)!=0 &&
+ memcmp(&buffer[i],"bmp ",4)!=0 &&
+ memcmp(&buffer[i],"jpg ",4)!=0)
return 0;
- }
-#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])
- {
- if(header_ignored_adv(file_recovery, file_recovery_new)==0)
- return 0;
- }
-#endif
+ /* log_info("search_MMT: image extension present\n"); */
}
- /*@ assert nbr == 0; */
- /*@
- @ loop invariant 0 <= nbr <= potential_frame_offset <= 2048 + 8065;
- @*/
- while(potential_frame_offset+1 < buffer_size &&
- potential_frame_offset+1 < 2048)
{
- if(buffer[potential_frame_offset+0]!=0xFF)
+ const unsigned int tmp=i+size;
+ const uint32_t *image_size_ptr;
+ uint32_t image_size;
+ if(tmp+8>buffer_size)
return 0;
- {
- const unsigned int mpeg_version =(buffer[potential_frame_offset+1]>>3)&0x03;
- const unsigned int mpeg_layer =(buffer[potential_frame_offset+1]>>1)&0x03;
- const unsigned int bit_rate_key =(buffer[potential_frame_offset+2]>>4)&0x0F;
- const unsigned int sampling_rate_key=(buffer[potential_frame_offset+2]>>2)&0x03;
- const unsigned int padding =(buffer[potential_frame_offset+2]>>1)&0x01;
- const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key];
- const unsigned int sample_rate =sample_rate_table[mpeg_version][sampling_rate_key];
- unsigned int frameLengthInBytes=0;
- if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
- return 0;
- /*@ assert 8 <= bit_rate <= 448; */
- /*@ assert 8000 <= sample_rate <= 48000; */
- if(mpeg_layer==MPEG_L3)
- {
- if(mpeg_version==MPEG_V1)
- frameLengthInBytes = 144000 * bit_rate / sample_rate + padding;
- else
- frameLengthInBytes = 72000 * bit_rate / sample_rate + padding;
- }
- else if(mpeg_layer==MPEG_L2)
- frameLengthInBytes = 144000 * bit_rate / sample_rate + padding;
- else
- frameLengthInBytes = (12000 * bit_rate / sample_rate + padding)*4;
-#ifdef DEBUG_MP3
- log_info("framesize: %u, layer: %u, bitrate: %u, padding: %u\n",
- frameLengthInBytes, 4-mpeg_layer, bit_rate, padding);
-#endif
- if(frameLengthInBytes==0)
- return 0;
- /*@ assert 0 < frameLengthInBytes <= 8065; */
- potential_frame_offset+=frameLengthInBytes;
- /*@ assert potential_frame_offset > 0; */
- nbr++;
- }
+ /*@ assert tmp + 8 <= buffer_size; */
+ image_size_ptr = (const uint32_t *)&buffer[tmp+4];
+ image_size = le32(*image_size_ptr);
+ /* Check if the image size */
+ if(image_size > buffer_size)
+ return 0;
+ /*@ assert image_size <= buffer_size; */
+ /* Image binary */
+ size+=8+image_size;
}
- if(nbr>1)
{
- /*@ 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)
+ const unsigned int tmp=i+size;
+ /* check null padding + version_info */
+ if(tmp+sizeof(mm_pad_version_info)>buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch Tag 1\n"); */
+ return 0;
+ }
+ /*@ assert tmp + sizeof(mm_pad_version_info) <= buffer_size; */
+ if(memcmp(&buffer[tmp], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
{
- file_recovery_new->data_check=&data_check_mp3;
- file_recovery_new->file_check=&file_check_size;
+ /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
+ return 0;
}
- return 1;
}
- return 0;
-}
-#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)
+ size+=4+256; /* padding + version_info */
+ size+=20; /* data offset */
{
- 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++;
+ const unsigned int tmp=i+size;
+ /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */
+ if(tmp+8132+sizeof(mm_footer) > buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch 2\n"); */
+ return 0;
}
+ /*@ assert tmp + 8132 + sizeof(mm_footer) <= buffer_size; */
+ if( memcmp(&buffer[tmp+7868], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7868], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7868;
+ else if(memcmp(&buffer[tmp+7936], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7936], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7936;
+ else if(memcmp(&buffer[tmp+8004], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8004], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=8004;
+ else if(memcmp(&buffer[tmp+8132], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8132], mm_footer_tag, sizeof(mm_footer_tag)-1)==0)
+ size+=8132;
else
- { /* no more padding or no padding */
- file_recovery->data_check=&data_check_mp3;
- file_recovery->file_check=&file_check_size;
- 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;
+ {
+ /* log_trace("search_MMT: no mm_footer present\n"); */
+ return 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 - 1; */
- /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
- return DC_CONTINUE;
+ {
+ const unsigned int tmp=i+size;
+ if(tmp + sizeof(mm_footer) > buffer_size)
+ return 0;
+ /*@ assert tmp + sizeof(mm_footer) <= buffer_size; */
+ if(memcmp(&buffer[tmp],mm_footer, sizeof(mm_footer)-1)==0)
+ size+=48; /* footer */
+ else
+ size+=0x80; /* TAG footer */
+ }
+ /* log_trace("search_MMT: MMT found size=%u (0x%x)\n", size, size); */
+ return size;
}
-#endif
/*@
@ requires buffer_size >= 32;
+ @ requires (buffer_size&1)==0;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid(file_recovery);
@ requires file_recovery->data_check==&data_check_mp3;
@ requires file_recovery->file_size == 0 || file_recovery->calculated_file_size >= file_recovery->file_size - 16;
@ ensures \result == DC_CONTINUE || \result == DC_STOP;
@ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @ ensures file_recovery->data_check==&data_check_mp3;
+ @ assigns file_recovery->calculated_file_size;
@*/
- /* 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
@@ -350,6 +280,9 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
(long long unsigned)file_recovery->file_size,
(long long unsigned)file_recovery->calculated_file_size);
#endif
+ /*@
+ @ loop assigns file_recovery->calculated_file_size;
+ @*/
while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2)
{
@@ -368,19 +301,15 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
const unsigned int bit_rate_key =(buffer[i+2]>>4)&0x0F;
const unsigned int sampling_rate_key=(buffer[i+2]>>2)&0x03;
const unsigned int padding =(buffer[i+2]>>1)&0x01;
- const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key];
+ /*@ split mpeg_version; */
const unsigned int sample_rate =sample_rate_table[mpeg_version][sampling_rate_key];
+ /*@ assert sample_rate == 0 || 8000 <= sample_rate <= 48000; */
+ const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key];
unsigned int frameLengthInBytes=0;
- /*
- log_info("frame_offset=%u\n",i);
- log_info("bit_rate=%u\n",bit_rate);
- log_info("sample_rate=%u\n",sample_rate);
- log_info("frameLengthInBytes=%u\n",frameLengthInBytes);
- */
if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
return DC_STOP;
- /*@ assert 8 <= bit_rate <= 448; */
/*@ assert 8000 <= sample_rate <= 48000; */
+ /*@ assert 0 < bit_rate <= 448; */
if(mpeg_layer==MPEG_L3)
{
if(mpeg_version==MPEG_V1)
@@ -394,7 +323,7 @@ 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; */
+ /*@ assert 3 <= frameLengthInBytes <= 8065; */
file_recovery->calculated_file_size+=frameLengthInBytes;
/*@ assert file_recovery->calculated_file_size > 0; */
}
@@ -416,13 +345,13 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
/*@ assert i + 5100 <= buffer_size; */
if((pos_lyrics=pos_in_mem(&buffer[i], 4096, (const unsigned char*)"LYRICS200", 9)) != 0)
{
- /*@ assert pos_lyrics > 0; */
+ /*@ assert 0 < pos_lyrics <= 4096; */
file_recovery->calculated_file_size+=pos_lyrics;
/*@ assert file_recovery->calculated_file_size > 0; */
}
else if((pos_lyrics=pos_in_mem(&buffer[i], 5100, (const unsigned char*)"LYRICSEND", 9)) != 0)
{
- /*@ assert pos_lyrics > 0; */
+ /*@ assert 0 < pos_lyrics <= 5100; */
file_recovery->calculated_file_size+=pos_lyrics;
/*@ assert file_recovery->calculated_file_size > 0; */
}
@@ -450,7 +379,7 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
const unsigned int MMT_size=search_MMT(buffer,i,buffer_size);
if(MMT_size==0)
return DC_STOP;
- /*@ assert MMT_size > 0; */
+ /*@ assert 0 < MMT_size <= buffer_size + 0x80; */
/*
log_info("MusicMatch Tag found at offset 0x%x with size 0x%x \n", file_recovery->calculated_file_size, MMT_size);
*/
@@ -464,152 +393,236 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
}
/*@
- @ 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;
+ @ requires buffer_size >= 32;
+ @ requires (buffer_size&1)==0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_id3;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE && file_recovery->data_check==&data_check_id3 ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1);
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @ ensures file_recovery->data_check==&data_check_id3 || file_recovery->data_check==&data_check_mp3;
@*/
-static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
+ /*TODO assigns file_recovery->data_check,file_recovery->calculated_file_size; */
+static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- unsigned int i;
- if(haystack_size < needle_size)
- return 0;
- /*@ assert haystack_size >= needle_size; */
/*@
- @ loop assigns i;
- @ loop invariant 0 <= i <= haystack_size - needle_size + 1;
- @ loop variant haystack_size - needle_size - i;
+ @ loop assigns file_recovery->data_check,file_recovery->calculated_file_size;
@*/
- for(i=0; i <= haystack_size - needle_size; i++)
- if(memcmp(&haystack[i],needle,needle_size)==0)
- return (i+needle_size);
+ while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
+ file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2)
+ {
+ const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert 0 <= i < buffer_size - 1 ; */
+ if(buffer[i]==0)
+ { /* Padding is present */
+ file_recovery->calculated_file_size++;
+ }
+ else
+ { /* no more padding or no padding */
+ file_recovery->data_check=&data_check_mp3;
+ file_recovery->file_check=&file_check_size;
+ /*@ assert file_recovery->data_check==&data_check_mp3; */
+ if(data_check_mp3(buffer, buffer_size, file_recovery)!=DC_CONTINUE)
+ return DC_STOP;
+ /*@ assert file_recovery->data_check==&data_check_mp3; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
+ return DC_CONTINUE;
+ }
+ }
+ /*@ assert file_recovery->data_check==&data_check_id3; */
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
+ return DC_CONTINUE;
+}
+
+/*@
+ @ requires buffer_size >= 10;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_id3);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_id3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3' && (buffer[3]==2 || buffer[3]==3 || buffer[3]==4) && buffer[4]==0)
+ {
+ unsigned int potential_frame_offset=0;
+ /*
+ * TODO Handle ID3 tag
+ * http://www.id3.org/id3v2-00
+ * http://www.id3.org/id3v2.3.0
+ */
+ if(buffer[3]==4 && (buffer[5]&0x10)==0x10) /* a footer is present http://www.id3.org/id3v2.4.0-structure chap. 3.1 */
+ potential_frame_offset = 10;
+
+ potential_frame_offset+=((buffer[6]&0x7f)<<21) + ((buffer[7]&0x7f)<<14)
+ + ((buffer[8]&0x7f)<<7) + (buffer[9]&0x7f)+ 10;
+
+ /*
+ log_info("ID3v2.%u found \n potential_frame_offset at 0x%x\n",buffer[3], potential_frame_offset);
+ */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->calculated_file_size=potential_frame_offset;
+ /*@ assert file_recovery_new->calculated_file_size > 0; */
+ file_recovery_new->min_filesize=287;
+ file_recovery_new->data_check=&data_check_id3;
+ file_recovery_new->extension=file_hint_mp3.extension;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
return 0;
}
/*@
- @ requires buffer_size > 0;
- @ requires i <= buffer_size;
+ @ requires buffer_size >= 6;
@ requires \valid_read(buffer+(0..buffer_size-1));
- @ assigns \nothing;
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_mp3, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287);
+ @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->data_check == &data_check_mp3);
+ @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->data_check == \null);
+ @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->file_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
-static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size)
+static int header_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
+ unsigned int potential_frame_offset=0;
+ unsigned int nbr=0;
/*
- Check for MusicMatch Tag
- http://freenet-homepage.de/StefanRypalla/stuff/musicmatch.txt
- min size = 8192bytes
- header is optional
- structure :
- header 256 bytes optional
- image extension 4 bytes
- image binary >= 4 bytes
- unused 4 bytes
- version info 256 bytes
- audio meta-data >= 7868 bytes
- In all versions of the MusicMatch format up to and including 3.00,
- this section (audio meta-data) is always 7868 bytes in length.
- All subsequent versions allowed three possible lengths for this section: 7936, 8004, and 8132 bytes.
- data offsets 20 bytes
- Footer 48 bytes (optional?!)
- */
- const unsigned char mm_header[10]= {'1','8','2','7','3','6','4','5',0x00, 0x00};
- const unsigned char mm_pad_version_info[14] = {0x00,0x00,0x00,0x00,'1','8','2','7','3','6','4','5',0x00,0x00};
- const char mm_footer[]="Brava Software Inc.";
- const char mm_footer_tag[]="TAG";
- unsigned int size=0;
- if(i+sizeof(mm_header)>buffer_size)
+ A Frame sync 11 (length in bits)
+ B MPEG audio version (MPEG-1, 2, etc.) 2
+ C MPEG layer (Layer I, II, III, etc.) 2
+ D Protection (if on, then checksum follows header) 1
+ AAAA AAAA AAAB BCCD
+ 1111 1111 1111 1010 = FA = MPEG-1 layer 3
+ 1111 1111 1111 0010 = F2 = MPEG-2 layer 3
+ 1111 1111 1110 0010 = E2 = MPEG-2.5 layer 3
+
+ http://www.dv.co.yu/mpgscript/mpeghdr.htm
+ */
+ if(!(buffer[0]==0xFF &&
+ ((buffer[1]&0xFE)==0xFA ||
+ (buffer[1]&0xFE)==0xF2 ||
+ (buffer[1]&0xFE)==0xE2)))
return 0;
- /*@ assert i + sizeof(mm_header) <= buffer_size; */
- if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header
- {
- size=256;
- /* Don't check image extension */
- /* log_info("search_MMT: mm_header present\n"); */
- }
- else
- {
- /* Check image extension */
- if( memcmp(&buffer[i]," ",4)!=0 &&
- memcmp(&buffer[i],"bmp ",4)!=0 &&
- memcmp(&buffer[i],"jpg ",4)!=0)
- return 0;
- /* log_info("search_MMT: image extension present\n"); */
- }
- {
- const unsigned int tmp=i+size;
- const uint32_t *image_size_ptr;
- uint32_t image_size;
- if(tmp+8>buffer_size)
- return 0;
- /*@ assert tmp + 8 <= buffer_size; */
- image_size_ptr = (const uint32_t *)&buffer[tmp+4];
- image_size = le32(*image_size_ptr);
- /* Check if the image size */
- if(image_size > 10 * 1024 * 1024)
- return 0;
- /*@ assert image_size <= 10 * 1024 * 1024; */
- /* Image binary */
- size+=8+image_size;
- }
+ /*@ assert nbr == 0; */
+ /*@
+ @ loop invariant 0 <= nbr <= potential_frame_offset <= 2048 + 8065;
+ @ loop assigns potential_frame_offset,nbr;
+ @ loop variant 2048 - potential_frame_offset;
+ @*/
+ while(potential_frame_offset+1 < buffer_size &&
+ potential_frame_offset+1 < 2048)
{
- 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"); */
+ if(buffer[potential_frame_offset+0]!=0xFF)
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;
+ const unsigned int mpeg_version =(buffer[potential_frame_offset+1]>>3)&0x03;
+ const unsigned int mpeg_layer =(buffer[potential_frame_offset+1]>>1)&0x03;
+ const unsigned int bit_rate_key =(buffer[potential_frame_offset+2]>>4)&0x0F;
+ const unsigned int sampling_rate_key=(buffer[potential_frame_offset+2]>>2)&0x03;
+ const unsigned int padding =(buffer[potential_frame_offset+2]>>1)&0x01;
+ /*@ split mpeg_version; */
+ const unsigned int bit_rate =bit_rate_table[mpeg_version][mpeg_layer][bit_rate_key];
+ const unsigned int sample_rate =sample_rate_table[mpeg_version][sampling_rate_key];
+ unsigned int frameLengthInBytes=0;
+ if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
+ return 0;
+ /*@ assert 8000 <= sample_rate <= 48000; */
+ /*@ assert 0 < bit_rate <= 448; */
+ if(mpeg_layer==MPEG_L3)
+ {
+ if(mpeg_version==MPEG_V1)
+ frameLengthInBytes = 144000 * bit_rate / sample_rate + padding;
+ else
+ frameLengthInBytes = 72000 * bit_rate / sample_rate + padding;
+ }
+ else if(mpeg_layer==MPEG_L2)
+ frameLengthInBytes = 144000 * bit_rate / sample_rate + padding;
+ else
+ frameLengthInBytes = (12000 * bit_rate / sample_rate + padding)*4;
+#ifdef DEBUG_MP3
+ log_info("framesize: %u, layer: %u, bitrate: %u, padding: %u\n",
+ frameLengthInBytes, 4-mpeg_layer, bit_rate, padding);
+#endif
+ if(frameLengthInBytes<3)
+ return 0;
+ /*@ assert 3 <= frameLengthInBytes <= 8065; */
+ potential_frame_offset+=frameLengthInBytes;
+ /*@ assert potential_frame_offset > 0; */
+ nbr++;
}
}
- size+=4+256; /* padding + version_info */
- size+=20; /* data offset */
+ if(nbr<=1)
+ return 0;
+ if(file_recovery->file_stat!=NULL)
{
- 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"); */
+ if(file_recovery->file_stat->file_hint==&file_hint_mp3
+#if !defined(MAIN_mp3)
+ || file_recovery->file_stat->file_hint==&file_hint_mkv
+#endif
+ )
+ {
+ header_ignored(file_recovery_new);
return 0;
}
- /*@ 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
+#if !defined(MAIN_mp3)
+ /* RGV values from TIFF may be similar to the beginning of an mp3 */
+ if(file_recovery->file_stat->file_hint==&file_hint_tiff &&
+ buffer[0]==buffer[3] && buffer[1]==buffer[4] && buffer[2]==buffer[5])
{
- /* log_trace("search_MMT: no mm_footer present\n"); */
- return 0;
+ if(header_ignored_adv(file_recovery, file_recovery_new)==0)
+ return 0;
}
+#endif
}
+ /*@ assert nbr > 1; */
+ /*@ assert potential_frame_offset > 0; */
+#ifdef DEBUG_MP3
+ log_info("header_check_mp3 mp3 found\n");
+#endif
+ reset_file_recovery(file_recovery_new);
+ /*@ assert file_recovery_new->file_check == \null; */
+ /*@ assert file_recovery_new->data_check == \null; */
+ file_recovery_new->calculated_file_size=potential_frame_offset;
+ /*@ assert file_recovery_new->calculated_file_size > 0; */
+ file_recovery_new->min_filesize=287;
+ file_recovery_new->extension=file_hint_mp3.extension;
+ if(file_recovery_new->blocksize >= 16)
{
- 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 */
+ file_recovery_new->data_check=&data_check_mp3;
+ file_recovery_new->file_check=&file_check_size;
}
- /* log_trace("search_MMT: MMT found size=%u (0x%x)\n", size, size); */
- return(size);
+ return 1;
}
/*@
@@ -623,22 +636,18 @@ 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
+#if defined(MAIN_mp3)
#define BLOCKSIZE 65536u
-int main()
+static int main_id3()
{
const char fn[] = "recup_dir.1/f0000000.mp3";
unsigned char buffer[BLOCKSIZE];
@@ -677,6 +686,7 @@ int main()
/*@ assert file_recovery_new.file_size == 0; */
/*@ assert file_recovery_new.min_filesize == 287; */
/*@ assert file_recovery_new.data_check == &data_check_id3; */
+ /*@ assert file_recovery_new.file_rename == \null; */
{
unsigned char big_buffer[2*BLOCKSIZE];
data_check_t res_data_check=DC_CONTINUE;
@@ -719,16 +729,10 @@ int main()
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()
+
+static int main_mp3()
{
const char fn[] = "recup_dir.1/f0000000.mp3";
unsigned char buffer[BLOCKSIZE];
@@ -755,7 +759,7 @@ int main()
file_stats.file_hint=&file_hint_mp3;
file_stats.not_recovered=0;
file_stats.recovered=0;
- file_hint_mp3.register_header_check(&file_stats);
+ register_header_check_mp3(&file_stats);
if(header_check_mp3(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
return 0;
/*@ assert valid_read_string((char *)&fn); */
@@ -764,6 +768,7 @@ int main()
/*@ assert file_recovery_new.min_filesize == 287; */
/*@ assert file_recovery_new.extension == file_hint_mp3.extension; */
/*@ assert file_recovery_new.calculated_file_size > 0; */
+ /*@ assert file_recovery_new.file_rename == \null; */
file_recovery_new.file_stat=&file_stats;
if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL &&
file_recovery_new.data_check!=NULL)
@@ -809,11 +814,13 @@ int main()
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;
+}
+
+int main()
+{
+ main_mp3();
+ main_id3();
return 0;
}
#endif
diff --git a/src/file_pdf.c b/src/file_pdf.c
index c62b9bf..1311539 100644
--- a/src/file_pdf.c
+++ b/src/file_pdf.c
@@ -85,7 +85,7 @@ static void file_rename_pdf(file_recovery_t *file_recovery)
#else
offset=ftell(handle);
#endif
- if(offset < 0)
+ if(offset <= 0)
{
fclose(handle);
return;
@@ -250,11 +250,11 @@ static void file_date_pdf(file_recovery_t *file_recovery)
{
if(buffer[0]=='=' && (buffer[1]=='\'' || buffer[1]=='"'))
{
- file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS((const char *)&buffer[2]);
+ file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[2]);
}
else if(buffer[0]=='>')
{
- file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS((const char *)&buffer[1]);
+ file_recovery->time=get_time_from_YYYY_MM_DD_HH_MM_SS(&buffer[1]);
}
}
free(buffer);
diff --git a/src/file_pf.c b/src/file_pf.c
index 787a8a6..d01b99d 100644
--- a/src/file_pf.c
+++ b/src/file_pf.c
@@ -60,20 +60,28 @@ struct pf_header
/*@
@ requires \valid(file_recovery);
@ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_pf;
+ @ ensures valid_read_string((char*)&file_recovery->filename);
@*/
static void file_rename_pf(file_recovery_t *file_recovery)
{
FILE *file;
struct pf_header hdr;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
return;
+ }
if(fread(&hdr, sizeof(hdr), 1, file) <= 0)
{
fclose(file);
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
return ;
}
fclose(file);
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
file_rename_unicode(file_recovery, &hdr.name, sizeof(hdr.name), 0, "pf", 0);
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
}
/*@
@@ -82,13 +90,20 @@ static void file_rename_pf(file_recovery_t *file_recovery)
@ 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);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_pf, buffer+(..), file_recovery, file_recovery_new);
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_pf.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
@ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= sizeof(struct pf_header));
- @ ensures (\result == 1) ==> (file_recovery_new->file_rename==&file_rename_pf);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
@ ensures (\result == 1) ==> (file_recovery_new->data_check==&data_check_size);
@ ensures (\result == 1) ==> (file_recovery_new->file_check==&file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename==&file_rename_pf);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
static int header_check_pf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
diff --git a/src/file_sdsk.c b/src/file_sdsk.c
new file mode 100644
index 0000000..0d0ec6a
--- /dev/null
+++ b/src/file_sdsk.c
@@ -0,0 +1,66 @@
+/*
+
+ File: file_sdsk.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_sdsk(file_stat_t *file_stat);
+
+const file_hint_t file_hint_sdsk= {
+ .extension="sdsk",
+ .description="SafeHouse virtual disk",
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .enable_by_default=1,
+ .register_header_check=&register_header_check_sdsk
+};
+
+static int header_check_sdsk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_sdsk.extension;
+ file_recovery_new->min_filesize=0x1000;
+ return 1;
+}
+
+static void register_header_check_sdsk(file_stat_t *file_stat)
+{
+ static const unsigned char sdsk_header[0x48]= {
+ 'W' , 'A' , 'R' , 'N' , 'I' , 'N' , 'G' , 0x3a,
+ ' ' , 'T' , 'h' , 'i' , 's' , ' ' , 'f' , 'i' ,
+ 'l' , 'e' , ' ' , 'i' , 's' , ' ' , 'a' , ' ' ,
+ 'S' , 'a' , 'f' , 'e' , 'H' , 'o' , 'u' , 's' ,
+ 'e' , ' ' , 'v' , 'i' , 'r' , 't' , 'u' , 'a' ,
+ 'l' , ' ' , 'd' , 'i' , 's' , 'k' , ' ' , 'v' ,
+ 'o' , 'l' , 'u' , 'm' , 'e' , '.' , 0x0d, 0x0a,
+ 'h' , 'e' , 'a' , 'd' , 'e' , 'r' , ' ' , 'v' ,
+ 'e' , 'r' , 's' , 'i' , 'o' , 'n' , 0x3a, ' ' ,
+ };
+ register_header_check(0, sdsk_header, sizeof(sdsk_header), &header_check_sdsk, file_stat);
+}
diff --git a/src/file_spe.c b/src/file_spe.c
index 9130cf1..0e79aab 100644
--- a/src/file_spe.c
+++ b/src/file_spe.c
@@ -31,9 +31,11 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_spe(file_stat_t *file_stat);
-static int header_check_spe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_spe= {
.extension="spe",
@@ -237,30 +239,171 @@ struct header_spe
int16_t lastvalue; /* 4098 Always the LAST value in the header */
} __attribute__ ((gcc_struct, __packed__));
-static const unsigned char spe_header[4]= {0x67, 0x45, 0x23, 0x01};
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(&file_hint_spe, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_spe.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 4100);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 4100);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @ assigns file_recovery_new->filename[0];
+ @ assigns file_recovery_new->time;
+ @ assigns file_recovery_new->file_stat;
+ @ assigns file_recovery_new->handle;
+ @ assigns file_recovery_new->file_size;
+ @ assigns file_recovery_new->location.list.prev;
+ @ assigns file_recovery_new->location.list.next;
+ @ assigns file_recovery_new->location.end;
+ @ assigns file_recovery_new->location.data;
+ @ assigns file_recovery_new->extension;
+ @ assigns file_recovery_new->min_filesize;
+ @ assigns file_recovery_new->calculated_file_size;
+ @ assigns file_recovery_new->data_check;
+ @ assigns file_recovery_new->file_check;
+ @ assigns file_recovery_new->file_rename;
+ @ assigns file_recovery_new->offset_error;
+ @ assigns file_recovery_new->offset_ok;
+ @ assigns file_recovery_new->checkpoint_status;
+ @ assigns file_recovery_new->checkpoint_offset;
+ @ assigns file_recovery_new->flags;
+ @ assigns file_recovery_new->extra;
+ @*/
+static int header_check_spe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ uint64_t tmp;
+ const struct header_spe *spe;
+ if(buffer_size < 4100)
+ return 0;
+ /*@ assert buffer_size >= 4100; */
+ spe=(const struct header_spe*)buffer;
+ /*@ assert \valid_read(spe); */
+ if(le32(spe->WinView_id)!=0x01234567L || le16(spe->lastvalue)!=0x5555 || le32(spe->NumFrames)<0)
+ return 0;
+ tmp=(uint64_t)le16(spe->xdim)*le16(spe->ydim)*le32(spe->NumFrames);
+ if((tmp&0xc000000000000000)!=0)
+ return 0;
+ tmp*=(le16(spe->datatype)<=1?4:2);
+ if((tmp&0x8000000000000000)!=0)
+ return 0;
+ tmp+=4100;
+
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_spe.extension;
+ file_recovery_new->min_filesize=4100;
+ file_recovery_new->calculated_file_size=tmp;
+#ifndef __FRAMAC__
+ log_debug("spe xdim=%u ydim=%u NumFrames=%u datatype=%u size=%llu\n",
+ le16(spe->xdim), le16(spe->ydim), (unsigned int)le32(spe->NumFrames), le16(spe->datatype),
+ (long long unsigned) file_recovery_new->calculated_file_size);
+#endif
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+}
static void register_header_check_spe(file_stat_t *file_stat)
{
+ static const unsigned char spe_header[4]= {0x67, 0x45, 0x23, 0x01};
register_header_check(0xbb4, spe_header,sizeof(spe_header), &header_check_spe, file_stat);
}
-static int header_check_spe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+#if defined(MAIN_spe)
+#define BLOCKSIZE 65536u
+int main()
{
- const struct header_spe *spe=(const struct header_spe*)buffer;
- if(le32(spe->WinView_id)==0x01234567L && le16(spe->lastvalue)==0x5555)
+ const char fn[] = "recup_dir.1/f0000000.spe";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_spe;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_spe(&file_stats);
+ if(header_check_spe(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.extension == file_hint_spe.extension; */
+ /*@ assert file_recovery_new.calculated_file_size >= 4100; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.min_filesize == 4100; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */
{
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_spe.extension;
- file_recovery_new->min_filesize=4100;
- file_recovery_new->calculated_file_size=(uint64_t)le16(spe->xdim)*le16(spe->ydim)*le32(spe->NumFrames);
- file_recovery_new->calculated_file_size*=(le16(spe->datatype)<=1?4:2);
- file_recovery_new->calculated_file_size+=4100;
- log_debug("spe xdim=%u ydim=%u NumFrames=%u datatype=%u size=%llu\n",
- le16(spe->xdim), le16(spe->ydim), (unsigned int)le32(spe->NumFrames), le16(spe->datatype),
- (long long unsigned) file_recovery_new->calculated_file_size);
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- return 1;
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ {
+ file_recovery_t file_recovery_new2;
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_spe(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
}
return 0;
}
+#endif
diff --git a/src/file_tiff.h b/src/file_tiff.h
index 0fb5f6c..fa9af03 100644
--- a/src/file_tiff.h
+++ b/src/file_tiff.h
@@ -77,7 +77,7 @@ time_t get_date_from_tiff_header(const unsigned char*buffer, const unsigned int
/*@
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \separated(potential_error, buffer);
- @ ensures \valid_read(buffer+(0..buffer_size-1));
+ @ assigns *potential_error;
@*/
unsigned int find_tag_from_tiff_header(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int tag, const unsigned char **potential_error);
@@ -88,7 +88,7 @@ unsigned int find_tag_from_tiff_header(const unsigned char *buffer, const unsign
@ 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));
+ @ assigns *potential_error;
@*/
unsigned int find_tag_from_tiff_header_le(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error);
#endif
@@ -99,6 +99,7 @@ unsigned int find_tag_from_tiff_header_le(const unsigned char *buffer, const uns
@ requires \valid(fr->handle);
@ requires \valid_read(&fr->extension);
@ requires valid_read_string(fr->extension);
+ @ requires fr->file_check==&file_check_tiff_le;
@ ensures \valid(fr->handle);
@ ensures valid_read_string(fr->extension);
@*/
@@ -108,12 +109,21 @@ void file_check_tiff_le(file_recovery_t *fr);
@ requires buffer_size >= 15;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
@ requires \valid(file_recovery_new);
@ requires file_recovery_new->blocksize > 0;
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
@ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_le);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
@ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
#endif
@@ -125,7 +135,7 @@ int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_
@ 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));
+ @ assigns *potential_error;
@*/
unsigned int find_tag_from_tiff_header_be(const unsigned char*buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error);
#endif
@@ -135,11 +145,20 @@ unsigned int find_tag_from_tiff_header_be(const unsigned char*buffer, const unsi
@ requires buffer_size >= 15;
@ requires \valid_read(buffer+(0..buffer_size-1));
@ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
@ requires \valid(file_recovery_new);
@ requires file_recovery_new->blocksize > 0;
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures \result == 1 ==> \initialized(&file_recovery_new->time);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename== \null);
@ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
@ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
int header_check_tiff_be(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
#endif
diff --git a/src/file_tiff_be.c b/src/file_tiff_be.c
index 92ac870..84b33af 100644
--- a/src/file_tiff_be.c
+++ b/src/file_tiff_be.c
@@ -54,8 +54,31 @@ static const char *extension_pef="pef";
#ifndef MAIN_tiff_le
/*@
@ requires \valid_read(buffer+(0..tiff_size-1));
+ @ ensures \result <= 0xffff;
+ @ assigns \nothing;
+ @ */
+static unsigned int get_nbr_fields_be(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int offset_hdr)
+{
+ const unsigned char *ptr_hdr;
+ const struct ifd_header *hdr;
+ if(sizeof(struct ifd_header) > tiff_size)
+ return 0;
+ /*@ assert tiff_size >= sizeof(struct ifd_header); */
+ if(offset_hdr > tiff_size - sizeof(struct ifd_header))
+ return 0;
+ /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */
+ ptr_hdr=&buffer[offset_hdr];
+ /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */
+ hdr=(const struct ifd_header *)ptr_hdr;
+ /*@ assert \valid_read(hdr); */
+ return be16(hdr->nbr_fields);
+}
+
+/*@
+ @ requires \valid_read(buffer+(0..tiff_size-1));
@ requires \valid(potential_error);
@ requires \separated(potential_error, buffer+(..));
+ @ assigns *potential_error;
@
*/
static unsigned int find_tag_from_tiff_header_be_aux(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error, const unsigned int offset_hdr)
@@ -143,6 +166,25 @@ unsigned int find_tag_from_tiff_header_be(const unsigned char *buffer, const uns
if(tmp)
return tmp;
}
+ {
+ const unsigned int nbr_fields=get_nbr_fields_be(buffer, tiff_size, offset_ifd0);
+ unsigned int offset_tiff_next_diroff;
+ offset_tiff_next_diroff=offset_ifd0 + 2 + nbr_fields * sizeof(TIFFDirEntry);
+ /*@ assert tiff_size >= 4; */
+ if(offset_tiff_next_diroff < tiff_size - 4)
+ {
+ const unsigned char *ptr_hdr;
+ /*@ assert offset_tiff_next_diroff + 4 <= tiff_size; */
+ ptr_hdr=&buffer[offset_tiff_next_diroff];
+ /*@ assert \valid_read(ptr_hdr + (0 .. 4-1)); */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)ptr_hdr;
+ /*@ assert \valid_read(tiff_next_diroff); */
+ /* IFD1 */
+ const unsigned int offset_ifd1=be32(*tiff_next_diroff);
+ if(offset_ifd1 > 0)
+ return find_tag_from_tiff_header_be_aux(buffer, tiff_size, tag, potential_error, offset_ifd1);
+ }
+ }
/*@ assert \valid_read(buffer+(0..tiff_size-1)); */
return 0;
}
@@ -659,6 +701,7 @@ static uint64_t file_check_tiff_be_aux(file_recovery_t *fr, const uint32_t tiff_
@ requires \valid(fr->handle);
@ requires \valid_read(&fr->extension);
@ requires valid_read_string(fr->extension);
+ @ requires fr->file_check==&file_check_tiff_be;
@*/
static void file_check_tiff_be(file_recovery_t *fr)
{
diff --git a/src/file_tiff_le.c b/src/file_tiff_le.c
index 590e7bf..d12f146 100644
--- a/src/file_tiff_le.c
+++ b/src/file_tiff_le.c
@@ -58,8 +58,31 @@ static const char *extension_sr2="sr2";
#ifndef MAIN_tiff_be
/*@
@ requires \valid_read(buffer+(0..tiff_size-1));
+ @ ensures \result <= 0xffff;
+ @ assigns \nothing;
+ @ */
+static unsigned int get_nbr_fields_le(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int offset_hdr)
+{
+ const unsigned char *ptr_hdr;
+ const struct ifd_header *hdr;
+ if(sizeof(struct ifd_header) > tiff_size)
+ return 0;
+ /*@ assert tiff_size >= sizeof(struct ifd_header); */
+ if(offset_hdr > tiff_size - sizeof(struct ifd_header))
+ return 0;
+ /*@ assert offset_hdr + sizeof(struct ifd_header) <= tiff_size; */
+ ptr_hdr=&buffer[offset_hdr];
+ /*@ assert \valid_read(ptr_hdr + (0 .. sizeof(struct ifd_header)-1)); */
+ hdr=(const struct ifd_header *)ptr_hdr;
+ /*@ assert \valid_read(hdr); */
+ return le16(hdr->nbr_fields);
+}
+
+/*@
+ @ requires \valid_read(buffer+(0..tiff_size-1));
@ requires \valid(potential_error);
@ requires \separated(potential_error, buffer+(..));
+ @ assigns *potential_error;
@
*/
static unsigned int find_tag_from_tiff_header_le_aux(const unsigned char *buffer, const unsigned int tiff_size, const unsigned int tag, const unsigned char**potential_error, const unsigned int offset_hdr)
@@ -146,6 +169,24 @@ unsigned int find_tag_from_tiff_header_le(const unsigned char *buffer, const uns
if(tmp)
return tmp;
}
+ {
+ const unsigned int nbr_fields=get_nbr_fields_le(buffer, tiff_size, offset_ifd0);
+ unsigned int offset_tiff_next_diroff;
+ offset_tiff_next_diroff=offset_ifd0 + 2 + nbr_fields * sizeof(TIFFDirEntry);
+ if(offset_tiff_next_diroff < tiff_size - 4)
+ {
+ const unsigned char *ptr_hdr;
+ /*@ assert offset_tiff_next_diroff + 4 <= tiff_size; */
+ ptr_hdr=&buffer[offset_tiff_next_diroff];
+ /*@ assert \valid_read(ptr_hdr + (0 .. 4-1)); */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)ptr_hdr;
+ /*@ assert \valid_read(tiff_next_diroff); */
+ /* IFD1 */
+ const unsigned int offset_ifd1=le32(*tiff_next_diroff);
+ if(offset_ifd1 > 0)
+ return find_tag_from_tiff_header_le_aux(buffer, tiff_size, tag, potential_error, offset_ifd1);
+ }
+ }
/*@ assert \valid_read(buffer+(0..tiff_size-1)); */
return 0;
}
diff --git a/src/file_txt.c b/src/file_txt.c
index 19ea286..aec7b7f 100644
--- a/src/file_txt.c
+++ b/src/file_txt.c
@@ -41,41 +41,109 @@
#include "log.h"
#include "memmem.h"
#include "file_txt.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_txt)
extern const file_hint_t file_hint_doc;
extern const file_hint_t file_hint_jpg;
extern const file_hint_t file_hint_pdf;
extern const file_hint_t file_hint_sld;
extern const file_hint_t file_hint_tiff;
extern const file_hint_t file_hint_zip;
+#endif
-static inline int filtre(unsigned int car);
+typedef struct
+{
+ const char *string;
+ const unsigned int len;
+ const char *extension;
+} txt_header_t;
-static void register_header_check_txt(file_stat_t *file_stat);
-static int header_check_txt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
static void register_header_check_fasttxt(file_stat_t *file_stat);
static void register_header_check_snz(file_stat_t *file_stat);
-static int header_check_fasttxt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void register_header_check_txt(file_stat_t *file_stat);
+
+static const char *extension_asp="asp";
+static const char *extension_bat="bat";
+static const char *extension_c="c";
+static const char *extension_csv="csv";
+static const char *extension_dc="dc";
+static const char *extension_emlx="emlx";
+static const char *extension_ers="ers";
+static const char *extension_f="f";
+static const char *extension_fb2="fb2";
+static const char *extension_fods="fods";
+static const char *extension_fst="fst";
+static const char *extension_gcs="gcs";
+static const char *extension_ghx="ghx";
+static const char *extension_go="go";
+static const char *extension_gpx="gpx";
+static const char *extension_groovy="groovy";
+static const char *extension_gsb="gsb";
+static const char *extension_h="h";
+#ifdef DJGPP
+static const char *extension_html="htm";
+#else
+static const char *extension_html="html";
+#endif
+static const char *extension_ics="ics";
+static const char *extension_inf="inf";
+static const char *extension_ini="ini";
+#ifdef DJGPP
+static const char *extension_java="jav";
+#else
+static const char *extension_java="java";
+#endif
+static const char *extension_json="json";
+static const char *extension_jsp="jsp";
+static const char *extension_ldif="ldif";
+static const char *extension_ly="ly";
+static const char *extension_mbox="mbox";
+static const char *extension_php="php";
+static const char *extension_pl="pl";
+#ifdef DJGPP
+static const char *extension_plist="pli";
+#else
+static const char *extension_plist="plist";
+#endif
+static const char *extension_pm="pm";
+static const char *extension_prproj="prproj";
+static const char *extension_py="py";
+static const char *extension_rb="rb";
+static const char *extension_rtf="rtf";
+static const char *extension_sla="sla";
+static const char *extension_smil="smil";
+static const char *extension_stl="stl";
+static const char *extension_svg="svg";
+static const char *extension_ttd="ttd";
+static const char *extension_tex="tex";
#ifdef UTF16
-static int header_check_le16_txt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static const char *extension_utf16="utf16";
#endif
+static const char *extension_vb="vb";
+static const char *extension_vbm="vbm";
+static const char *extension_vcf="vcf";
+static const char *extension_xml="xml";
+static const char *extension_xmp="xmp";
-const file_hint_t file_hint_snz= {
- .extension="snz",
- .description="Olfaction SeeNez odorama",
+const file_hint_t file_hint_fasttxt= {
+ .extension="tx?",
+ .description="Text files with header: rtf,xml,xhtml,mbox/imm,pm,ram,reg,sh,slk,stp,jad,url",
.max_filesize=PHOTOREC_MAX_FILE_SIZE,
.recover=1,
.enable_by_default=1,
- .register_header_check=&register_header_check_snz
+ .register_header_check=&register_header_check_fasttxt
};
-const file_hint_t file_hint_fasttxt= {
- .extension="tx?",
- .description="Text files with header: rtf,xml,xhtml,mbox/imm,pm,ram,reg,sh,slk,stp,jad,url",
+const file_hint_t file_hint_snz= {
+ .extension="snz",
+ .description="Olfaction SeeNez odorama",
.max_filesize=PHOTOREC_MAX_FILE_SIZE,
.recover=1,
.enable_by_default=1,
- .register_header_check=&register_header_check_fasttxt
+ .register_header_check=&register_header_check_snz
};
const file_hint_t file_hint_txt= {
@@ -89,28 +157,6 @@ const file_hint_t file_hint_txt= {
static unsigned char ascii_char[256];
-static void register_header_check_txt(file_stat_t *file_stat)
-{
- unsigned int i;
- for(i=0; i<256; i++)
- ascii_char[i]=i;
- for(i=0; i<256; i++)
- {
- if(filtre(i) || i==0xE2 || i==0xC2 || i==0xC3 || i==0xC5 || i==0xC6 || i==0xCB)
- register_header_check(0, &ascii_char[i], 1, &header_check_txt, file_stat);
- }
-#ifdef UTF16
- register_header_check(1, &ascii_char[0], 1, &header_check_le16_txt, file_stat);
-#endif
-}
-
-typedef struct
-{
- const char *string;
- const unsigned int len;
- const char *extension;
-} txt_header_t;
-
static const txt_header_t fasttxt_headers[] = {
/* Unix shell */
{ "#!/bin/bash", 11, "sh"},
@@ -227,6 +273,9 @@ static const txt_header_t fasttxt_headers[] = {
// #define DEBUG_FILETXT
/* return 1 if char can be found in text file */
+/*@
+ @ assigns \nothing;
+ @*/
static int filtre(unsigned int car)
{
switch(car)
@@ -287,16 +336,192 @@ static int filtre(unsigned int car)
return 0;
}
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
+static int has_newline(const char *buffer, const unsigned int buffer_size)
+{
+ unsigned int i;
+ /*@
+ @ loop invariant 0 <= i <= 512;
+ @ loop assigns i;
+ @ loop variant 512-i;
+ @*/
+ for(i=0; i<512 && i < buffer_size && buffer[i]!='\0'; i++)
+ {
+ if(buffer[i]=='\n')
+ return 1;
+ }
+ /* A text file must contains several lines */
+ return 0;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
+static unsigned int is_csv(const char *buffer, const unsigned int buffer_size)
+{
+ unsigned int csv_per_line_current=0;
+ unsigned int csv_per_line=0;
+ unsigned int line_nbr=0;
+ unsigned int i;
+ /*@
+ @ loop invariant 0 <= i <= buffer_size;
+ @ loop invariant csv_per_line_current <= i+1;
+ @ loop invariant line_nbr <= i+1;
+ @ loop assigns i, csv_per_line_current, csv_per_line, line_nbr;
+ @ loop variant buffer_size-i;
+ @*/
+ for(i=0; i<buffer_size; i++)
+ {
+ if(buffer[i]==';')
+ {
+ csv_per_line_current++;
+ }
+ else if(buffer[i]=='\n')
+ {
+ if(line_nbr==0)
+ {
+ if(csv_per_line_current==0)
+ return 0;
+ csv_per_line=csv_per_line_current;
+ }
+ if(csv_per_line_current!=csv_per_line)
+ return 0;
+ line_nbr++;
+ csv_per_line_current=0;
+ }
+ }
+ if(line_nbr<10)
+ return 0;
+ return 1;
+}
+
+/*@
+ @ requires valid_read_string(buffer);
+ @ assigns \nothing;
+ @*/
+static unsigned int is_fortran(const char *buffer)
+{
+ const char *str=buffer;
+ unsigned int i=0;
+ /* Detect Fortran */
+ /*@ assert valid_read_string(str); */
+ /*@
+ @ loop invariant 0 <= i <= 10;
+ @ loop assigns str,i;
+ @ loop variant 10 - i;
+ @*/
+ for(i=0; i<10; i++)
+ {
+ str=strstr(str, "\n ");
+ if(str==NULL)
+ return 0;
+ /*@ assert valid_read_string(str); */
+#ifdef __FRAMAC__
+ if(*str=='\0')
+ return 0;
+#endif
+ str++;
+ /*@ assert valid_read_string(str); */
+ }
+ if(i < 10)
+ return 0;
+ if(strstr(buffer, "integer")==NULL)
+ return 0;
+ return 1;
+}
+
+/*@
+ @ requires valid_read_string((char *)buffer);
+ @ assigns \nothing;
+ @*/
+static int is_ini(const unsigned char *buffer)
+{
+ const unsigned char *src=buffer;
+ if(*src!='[')
+ return 0;
+ src++;
+ /*@
+ @ loop assigns src;
+ @*/
+ while(*src!='\0')
+ {
+ if(*src==']')
+ {
+ if(src > buffer + 3)
+ return 1;
+ return 0;
+ }
+ if(!isalnum(*src) && *src!=' ')
+ return 0;
+ src++;
+ }
+ return 0;
+}
+
+/*@
+ @ requires buffer_size >= 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @*/
+static double is_random(const unsigned char *buffer, const unsigned int buffer_size)
+{
+ unsigned int stats[256];
+ unsigned int i;
+ double ind;
+ if(buffer_size < 2)
+ return 1;
+ memset(&stats, 0, sizeof(stats));
+ /*@ assert \forall int j; (0 <= j <= 255) ==> (stats[j] == 0); */
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= i <= buffer_size;
+ @ loop invariant \forall integer j; (0 <= j <= 255) ==> (stats[j] <= i+1);
+ @ loop assigns i, stats[0..255];
+ @ loop variant buffer_size-i;
+ @*/
+ for(i=0; i<buffer_size; i++)
+ stats[buffer[i]]++;
+ ind=0;
+ /*@
+ @ loop invariant 0 <= i <= 256;
+ @ loop assigns ind;
+ @ loop variant 256-i;
+ @*/
+ for(i=0; i<256; i++)
+ if(stats[i]>0)
+ ind+=stats[i]*(stats[i]-1);
+#else
+ ind=Frama_C_interval(0, buffer_size*(buffer_size-1));
+#endif
+return ind/buffer_size/(buffer_size-1);
+}
+
/* destination should have an extra byte available for null terminator
- return read size */
-int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int buf_len)
+ return written size */
+/*@
+ @ requires buf_len > 0;
+ @ requires \valid(buffer_lower + (0..buf_len-1));
+ @ requires \valid_read(buffer + (0..buf_len-1));
+ @ ensures \result <= buf_len;
+ @*/
+static int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int buf_len)
{
const unsigned char *p; /* pointers to actual position in source buffer */
unsigned char *q; /* pointers to actual position in destination buffer */
- int i; /* counter of remaining bytes available in destination buffer */
- for (i = buf_len, p = buffer, q = buffer_lower; p-buffer<buf_len && i > 0 && *p!='\0';)
+ unsigned int offset_dst;
+ /* destination will be null terminated */
+ /*@
+ @ loop invariant offset_dst < buf_len;
+ @ loop invariant q == buffer_lower + offset_dst;
+ @ loop variant buf_len - 1 - offset_dst;
+ @*/
+ for (offset_dst = 0, p = buffer, q = buffer_lower;
+ p+2-buffer<buf_len && offset_dst < buf_len-1 && *p!='\0';)
{
- const unsigned char *p_org=p;
if((*p & 0xf0)==0xe0 && (*(p+1) & 0xc0)==0x80 && (*(p+2) & 0xc0)==0x80)
{ /* UTF8 l=3 */
#ifdef DEBUG_TXT
@@ -390,12 +615,17 @@ int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int
}
p+=2;
}
+ else if( 'A' <= *p && *p <='Z')
+ {
+ *q = *p-'A'+'a';
+ p++;
+ }
else
{ /* Ascii UCS */
#ifdef DEBUG_TXT
log_info("UTF8 Ascii UCS 0x%02x\n", *p);
#endif
- *q = tolower(*p);
+ *q = *p;
p++;
}
if (*q=='\0' || filtre(*q)==0)
@@ -404,19 +634,25 @@ int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int
log_warning("UTF2Lat reject 0x%x\n",*q);
#endif
*q = '\0';
- return(p_org-buffer);
+ return offset_dst;
}
q++;
- i--;
+ offset_dst++;
}
*q = '\0';
- return(p-buffer);
+ return offset_dst;
}
-static int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
+int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
{
const unsigned char *p=buffer; /* pointers to actual position in source buffer */
unsigned int i=0;
+ /*@
+ @ loop invariant 0 <= i < buf_len + 3;
+ @ loop invariant p == buffer + i;
+ @ loop assigns i, p;
+ @ loop variant buf_len - 1 - i;
+ @*/
while(i<buf_len && *p!='\0')
{
/* Reject some invalid UTF-8 sequences */
@@ -481,47 +717,68 @@ static int UTFsize(const unsigned char *buffer, const unsigned int buf_len)
return (i<buf_len?i:buf_len);
}
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_html;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
static data_check_t data_check_html(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
const char sign_html_end[] = "</html>";
- const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
- unsigned int j;
- for(j=(buffer_size/2>sizeof(sign_html_end)?buffer_size/2-sizeof(sign_html_end):0);
- j+sizeof(sign_html_end)-1 < buffer_size;
- j++)
+ if(buffer_size/2 > (sizeof(sign_html_end)-1))
{
- if(buffer[j]=='<' && strncasecmp((const char *)&buffer[j], sign_html_end, sizeof(sign_html_end)-1)==0)
+ unsigned int j;
+ /*@
+ @ loop assigns j, file_recovery->calculated_file_size;
+ @*/
+ for(j=buffer_size/2-(sizeof(sign_html_end)-1);
+ j+sizeof(sign_html_end)-1 < buffer_size;
+ j++)
{
- file_recovery->calculated_file_size+=j-buffer_size/2+sizeof(sign_html_end)-1;
- return DC_STOP;
+ if(buffer[j]=='<' && strncasecmp((const char *)&buffer[j], sign_html_end, sizeof(sign_html_end)-1)==0)
+ {
+ j+=sizeof(sign_html_end)-1;
+ /*@ assert j >= buffer_size/2; */
+ /*@ loop assigns j; */
+ while(j < buffer_size && (buffer[j]=='\n' || buffer[j]=='\r'))
+ j++;
+ file_recovery->calculated_file_size+=j-buffer_size/2;
+ return DC_STOP;
+ }
}
}
- if(i<buffer_size/2)
- {
- if(i>=10)
- file_recovery->calculated_file_size=file_recovery->file_size+i;
- return DC_STOP;
- }
- file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
- return DC_CONTINUE;
-}
-
-static data_check_t data_check_txt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
-{
- const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
- if(i<buffer_size/2)
{
- if(i>=10)
- file_recovery->calculated_file_size=file_recovery->file_size+i;
- return DC_STOP;
+ const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
+ if(i<buffer_size/2)
+ {
+ if(i>=10)
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
+ }
}
file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_ttd;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
static data_check_t data_check_ttd(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
unsigned int i;
+ /*@
+ @ loop invariant buffer_size/2 <= i <= buffer_size;
+ @ loop assigns i, file_recovery->calculated_file_size;
+ @ loop variant buffer_size - i;
+ @*/
for(i=buffer_size/2; i<buffer_size; i++)
{
const unsigned char car=buffer[i];
@@ -534,159 +791,139 @@ static data_check_t data_check_ttd(const unsigned char *buffer, const unsigned i
return DC_CONTINUE;
}
-static int header_check_ttd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- if(buffer[56]<'0' || buffer[56]>'9')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_ttd;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="ttd";
- return 1;
-}
-
-static void file_check_ers(file_recovery_t *file_recovery)
-{
- file_search_footer(file_recovery, "DatasetHeader End", 17, 0);
- file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
-}
-
-static int header_check_ers(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- /* ER Mapper Rasters (ERS) */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_ers;
- file_recovery_new->extension="ers";
- return 1;
-}
-
-static int header_check_ics(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size >= 2 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_txt;
+ @ assigns file_recovery->calculated_file_size;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
+static data_check_t data_check_txt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- const char *date_asc;
- char *buffer2;
- if(buffer[15]=='\0')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- /* vcalendar */
- file_recovery_new->extension="ics";
- /* DTSTART:19970714T133000 ;Local time
- * DTSTART:19970714T173000Z ;UTC time
- * DTSTART;TZID=US-Eastern:19970714T133000 ;Local time and time
- */
- buffer2=(char *)MALLOC(buffer_size+1);
- buffer2[buffer_size]='\0';
- memcpy(buffer2, buffer, buffer_size);
- date_asc=strstr(buffer2, "DTSTART");
- if(date_asc!=NULL)
- date_asc=strchr(date_asc, ':');
- if(date_asc!=NULL && date_asc+1+14 < buffer2+buffer_size)
+ const unsigned int i=UTFsize(&buffer[buffer_size/2], buffer_size/2);
+ if(i<buffer_size/2)
{
- file_recovery_new->time=get_time_from_YYYYMMDD_HHMMSS(date_asc+1);
+ if(i>=10)
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
}
- free(buffer2);
- return 1;
+ file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
+ return DC_CONTINUE;
}
-static int header_check_perlm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size >= 10 && (buffer_size&1)==0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check == &data_check_xml_utf8;
+ @ assigns file_recovery->calculated_file_size,file_recovery->data_check;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->data_check==&data_check_txt);
+ @*/
+static data_check_t data_check_xml_utf8(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
unsigned int i;
- const unsigned int buffer_size_test=(buffer_size < 2048 ? buffer_size : 2048);
- for(i=0; i<128 && buffer[i]!=';' && buffer[i]!='\n'; i++);
- if(buffer[i]!=';')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- if( td_memmem(buffer, buffer_size_test, "class", 5)!=NULL ||
- td_memmem(buffer, buffer_size_test, "private static", 14)!=NULL ||
- td_memmem(buffer, buffer_size_test, "public interface", 16)!=NULL)
- {
- /* source code in java */
-#ifdef DJGPP
- file_recovery_new->extension="jav";
-#else
- file_recovery_new->extension="java";
-#endif
- }
- else
+ if(buffer_size<=8)
+ return DC_CONTINUE;
+ i=UTFsize(&buffer[buffer_size/2+4], buffer_size/2-4)+4;
+ if(i<buffer_size/2)
{
- /* perl module */
- file_recovery_new->extension="pm";
- }
- return 1;
-}
-
-static int header_check_dc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- if(buffer[0]=='0' && buffer[1]=='0')
- { /*
- TSCe Survey Controller DC v10.0
- */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="dc";
- return 1;
+ file_recovery->calculated_file_size=file_recovery->file_size+i;
+ return DC_STOP;
}
- return 0;
+ file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
+ file_recovery->data_check=&data_check_txt;
+ return DC_CONTINUE;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_fods;
+ @ ensures valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_fods(file_recovery_t *file_recovery)
{
+ const char *meta_title="<office:meta><dc:title>";
FILE *file;
char buffer[4096];
- char *tmp;
+ char *tmp=NULL;
size_t lu;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
+ }
if((lu=fread(&buffer, 1, sizeof(buffer)-1, file)) <= 0)
{
fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
+ fclose(file);
buffer[lu]='\0';
- tmp=strchr(buffer,'<');
- while(tmp!=NULL)
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant tmp==\null || valid_read_string(tmp);
+ @ loop assigns tmp;
+ @*/
+ for(tmp=strchr(buffer,'<');
+ tmp!=NULL && strncasecmp(tmp, meta_title, 23)!=0;
+ tmp=strchr(tmp,'<'))
{
- if(strncasecmp(tmp, "<office:meta><dc:title>", 23)==0)
- {
- const char *title=tmp+23;
- tmp=strchr(title,'<');
- if(tmp!=NULL)
- *tmp='\0';
- file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
- fclose(file);
- return ;
- }
+ /* TODO assert tmp[0]=='<'; */
+ /*@ assert valid_read_string(tmp); */
tmp++;
- tmp=strchr(tmp,'<');
+ /*@ assert valid_read_string(tmp); */
}
- fclose(file);
+ if(tmp!=NULL)
+ {
+ const char *title=tmp+23;
+ /*@ assert valid_read_string(title); */
+ tmp=strchr(title,'<');
+ if(tmp!=NULL)
+ *tmp='\0';
+ file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
+ }
+#endif
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_html;
+ @ ensures valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_html(file_recovery_t *file_recovery)
{
FILE *file;
char buffer[4096];
char *tmp;
size_t lu;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
if((file=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
+ }
if((lu=fread(&buffer, 1, sizeof(buffer)-1, file)) <= 0)
{
fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
+ fclose(file);
buffer[lu]='\0';
+#ifndef __FRAMAC__
tmp=strchr(buffer,'<');
while(tmp!=NULL)
{
if(strncasecmp(tmp, "</head", 5)==0)
{
- fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
if(strncasecmp(tmp, "<title>", 7)==0)
@@ -696,294 +933,381 @@ static void file_rename_html(file_recovery_t *file_recovery)
if(tmp!=NULL)
*tmp='\0';
file_rename(file_recovery, (const unsigned char*)title, strlen(title), 0, NULL, 1);
- fclose(file);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
tmp++;
tmp=strchr(tmp,'<');
}
- fclose(file);
-}
-
-static int header_check_html(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
- strcmp(file_recovery->extension,"mbox")==0)
- return 0;
- if(buffer[14]==0)
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_html;
- file_recovery_new->file_check=&file_check_size;
- /* Hypertext Markup Language (HTML) */
-#ifdef DJGPP
- file_recovery_new->extension="htm";
-#else
- file_recovery_new->extension="html";
#endif
- file_recovery_new->file_rename=&file_rename_html;
- return 1;
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
}
-static void file_check_vbm(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_emlx;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_emlx(file_recovery_t *file_recovery)
{
- file_search_footer(file_recovery, "</BackupMeta>", 13, 0);
- file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
+ if(file_recovery->file_size < file_recovery->calculated_file_size)
+ file_recovery->file_size=0;
+ else
+ {
+ if(file_recovery->file_size > file_recovery->calculated_file_size+2048)
+ file_recovery->file_size=file_recovery->calculated_file_size+2048;
+ file_search_footer(file_recovery, "</plist>\n", 9, 0);
+ }
}
-static int header_check_vbm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_ers;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_ers(file_recovery_t *file_recovery)
{
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->extension="vbm";
- file_recovery_new->file_check=&file_check_vbm;
- return 1;
+ file_search_footer(file_recovery, "DatasetHeader End", 17, 0);
+ file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_gpx;
+ @ ensures \valid(file_recovery->handle);
+ @*/
static void file_check_gpx(file_recovery_t *file_recovery)
{
file_search_footer(file_recovery, "</gpx>", 6, 0);
file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static void file_check_xml(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_svg;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_svg(file_recovery_t *file_recovery)
{
- file_search_footer(file_recovery, ">", 1, 0);
+ file_search_footer(file_recovery, "</svg>", 6, 0);
file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static void file_check_svg(file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_smil;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_smil(file_recovery_t *file_recovery)
{
- file_search_footer(file_recovery, "</svg>", 6, 0);
+ file_search_footer(file_recovery, "</smil>", 7, 0);
file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static data_check_t data_check_xml_utf8(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_vbm;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_vbm(file_recovery_t *file_recovery)
{
- unsigned int i;
- if(buffer_size<=8)
- return DC_CONTINUE;
- i=UTFsize(&buffer[buffer_size/2+4], buffer_size/2-4)+4;
- if(i<buffer_size/2)
- {
- file_recovery->calculated_file_size=file_recovery->file_size+i;
- return DC_STOP;
- }
- file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
- file_recovery->data_check=&data_check_txt;
- return DC_CONTINUE;
+ file_search_footer(file_recovery, "</BackupMeta>", 13, 0);
+ file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-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)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ requires file_recovery->file_check == &file_check_xml;
+ @ ensures \valid(file_recovery->handle);
+ @*/
+static void file_check_xml(file_recovery_t *file_recovery)
{
- 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=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;
+ file_search_footer(file_recovery, ">", 1, 0);
+ file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
}
-static int header_check_xml_utf16(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, 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->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_dc);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> (\separated(file_recovery_new, file_recovery_new->extension));
+ @*/
+static int header_check_dc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- /* Avoid false positive with .sldprt */
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_doc)
+ if(buffer_size < 2)
+ return 0;
+ if(buffer[0]!='0' || buffer[1]!='0')
return 0;
+ /*
+ TSCe Survey Controller DC v10.0
+ */
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="xml";
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=extension_dc;
return 1;
}
-static int header_check_xml(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 1;
+ @ ensures file_recovery_new->file_stat == \null;
+ @ ensures file_recovery_new->handle == \null;
+ @ ensures file_recovery_new->calculated_file_size == 0;
+ @ ensures file_recovery_new->extension == extension_ers;
+ @ ensures file_recovery_new->file_size == 0;
+ @ ensures file_recovery_new->min_filesize == 0;
+ @ ensures file_recovery_new->data_check == &data_check_txt;
+ @ ensures file_recovery_new->file_check == &file_check_ers;
+ @ ensures file_recovery_new->file_rename == \null;
+ @ ensures valid_read_string(file_recovery_new->extension);
+ @ ensures \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_ers(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- 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';
+ /* ER Mapper Rasters (ERS) */
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->extension=NULL;
- tmp=strchr(buf,'<');
- while(tmp!=NULL && file_recovery_new->extension==NULL)
+ file_recovery_new->file_check=&file_check_ers;
+ file_recovery_new->extension=extension_ers;
+ return 1;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, 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->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize > 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_fasttxt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const txt_header_t *header=&fasttxt_headers[0];
+ /*@ loop unroll 200; */
+ while(header->len > 0)
{
- if(strncasecmp(tmp, "<Grisbi>", 8)==0)
- {
- /* Grisbi - Personal Finance Manager XML data */
- file_recovery_new->extension="gsb";
- }
- else if(strncasecmp(tmp, "<collection type=\"GC", 20)==0)
- {
- /* GCstart, personal collections manager, http://www.gcstar.org/ */
- file_recovery_new->extension="gcs";
- }
- else if(strncasecmp(tmp, "<html", 5)==0)
- {
- file_recovery_new->data_check=&data_check_html;
-#ifdef DJGPP
- file_recovery_new->extension="htm";
-#else
- file_recovery_new->extension="html";
-#endif
- file_recovery_new->file_rename=&file_rename_html;
- }
- else if(strncasecmp(tmp, "<Version>QBFSD", 14)==0)
- {
- /* QuickBook */
- file_recovery_new->extension="fst";
- }
- else if(strncasecmp(tmp, "<svg", 4)==0)
- {
- /* Scalable Vector Graphics */
- file_recovery_new->extension="svg";
- file_recovery_new->file_check=&file_check_svg;
- free(buf);
- return 1;
- }
- else if(strncasecmp(tmp, "<!DOCTYPE plist ", 16)==0)
- {
- /* Mac OS X property list */
-#ifdef DJGPP
- file_recovery_new->extension="pli";
-#else
- file_recovery_new->extension="plist";
-#endif
- }
- else if(strncasecmp(tmp, "<gpx ", 5)==0)
+ if(memcmp(buffer, header->string, header->len)==0)
{
- /* GPS eXchange Format */
- file_recovery_new->extension="gpx";
- file_recovery_new->file_check=&file_check_gpx;
- free(buf);
+ if(buffer[header->len]=='\0')
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /*@ assert valid_read_string(header->extension); */
+ file_recovery_new->extension=header->extension;
+ /*@ assert file_recovery_new->extension != \null; */
+ file_recovery_new->min_filesize=header->len+1;
+ /*@ assert file_recovery_new->file_stat == \null; */
+ /*@ assert file_recovery_new->handle == \null; */
+ /*@ assert file_recovery_new->min_filesize > 0; */
+ /*@ assert file_recovery_new->calculated_file_size == 0; */
+ /*@ assert file_recovery_new->file_size == 0; */
+ /*@ assert file_recovery_new->data_check == &data_check_txt; */
+ /*@ assert file_recovery_new->file_check == &file_check_size; */
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ /*@ assert \separated(file_recovery_new, file_recovery_new->extension); */
return 1;
}
- else if(strncasecmp(tmp, "<PremiereData Version=", 22)==0)
- {
- /* Adobe Premiere project */
- file_recovery_new->data_check=NULL;
- file_recovery_new->extension="prproj";
- }
- else if(strncasecmp(tmp, "<SCRIBUS", 8)==0)
- {
- /* Scribus XML file */
- file_recovery_new->extension="sla";
- }
- else if(strncasecmp(tmp, "<FictionBook", 12)==0)
- {
- /* FictionBook, see http://www.fictionbook.org */
- file_recovery_new->extension="fb2";
- }
- else if(strncasecmp(tmp, "<office:document", 16)==0)
- {
- /* OpenDocument Flat XML Spreadsheet */
- file_recovery_new->extension="fods";
- file_recovery_new->data_check=NULL;
- file_recovery_new->file_rename=&file_rename_fods;
- }
- tmp++;
- tmp=strchr(tmp,'<');
- }
- if(file_recovery_new->extension==NULL)
- {
- /* XML Extensible Markup Language */
- file_recovery_new->extension="xml";
+ header++;
}
- file_recovery_new->file_check=&file_check_xml;
- free(buf);
- return 1;
+ return 0;
}
-static int header_check_rtf(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_html);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_html);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_html);
+ @ 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_html(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- unsigned int i;
- for(i=0; i<16; i++)
- if(buffer[i]=='\0')
- return 0;
- /* Avoid a false positive with .snt */
+ if(buffer_size < 15)
+ return 0;
if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_doc)
+ file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
+ file_recovery->extension==extension_mbox)
+ return 0;
+ if(buffer[14]==0)
return 0;
reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->data_check=&data_check_html;
file_recovery_new->file_check=&file_check_size;
- /* Rich Text Format */
- file_recovery_new->extension="rtf";
+ /* Hypertext Markup Language (HTML) */
+ file_recovery_new->extension=extension_html;
+ file_recovery_new->file_rename=&file_rename_html;
return 1;
}
-static int header_check_xmp(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_ics);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_ics(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- if(buffer[35]=='\0')
+ const char *date_asc;
+ char *buffer2;
+ if(buffer_size < 22)
return 0;
- if(file_recovery->file_stat!=NULL &&
- (file_recovery->file_stat->file_hint==&file_hint_jpg ||
- file_recovery->file_stat->file_hint==&file_hint_pdf ||
- file_recovery->file_stat->file_hint==&file_hint_tiff))
+ if(buffer[15]=='\0')
return 0;
- /* Adobe's Extensible Metadata Platform */
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="xmp";
- return 1;
-}
-
-static void file_check_thunderbird(file_recovery_t *file_recovery)
-{
- if(file_recovery->file_size<file_recovery->calculated_file_size)
+ /* vcalendar */
+ file_recovery_new->extension=extension_ics;
+ /* DTSTART:19970714T133000 ;Local time
+ * DTSTART:19970714T173000Z ;UTC time
+ * DTSTART;TZID=US-Eastern:19970714T133000 ;Local time and time
+ */
+ buffer2=(char *)MALLOC(buffer_size+1);
+ buffer2[buffer_size]='\0';
+ memcpy(buffer2, buffer, buffer_size);
+ date_asc=strstr(buffer2, "DTSTART");
+ if(date_asc!=NULL)
+ date_asc=strchr(date_asc, ':');
+ if(date_asc!=NULL && date_asc+1+14 < buffer2+buffer_size)
{
- file_recovery->file_size=0;
- return;
+ file_recovery_new->time=get_time_from_YYYYMMDD_HHMMSS(date_asc+1);
}
- file_recovery->file_size=file_recovery->calculated_file_size;
+ free(buffer2);
+ return 1;
}
-static int header_check_thunderbird(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+#ifdef UTF16
+static int header_check_le16_txt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
unsigned int i;
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
- strcmp(file_recovery->extension,"mbox")==0)
- return 0;
- for(i=0; i<64; i++)
- if(buffer[i]==0)
- return 0;
+ for(i=0; i+1 < buffer_size; i+=2)
+ {
+ if(!( buffer[i+1]=='\0' && (isprint(buffer[i]) || buffer[i]=='\n' || buffer[i]=='\r' || buffer[i]==0xbb)))
+ {
+ if(i<40)
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->calculated_file_size=i;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=extension_utf16;
+ return 1;
+ }
+ }
reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_thunderbird;
- file_recovery_new->extension="mbox";
+ file_recovery_new->calculated_file_size=i;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=extension_utf16;
return 1;
}
+#endif
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_mbox);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_mbox(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
unsigned int i;
+ if(buffer_size < 200)
+ return 0;
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
- strcmp(file_recovery->extension,"mbox")==0)
+ file_recovery->extension==extension_mbox)
return 0;
+ /*@ loop assigns i; */
for(i=0; i<64; i++)
if(buffer[i]==0)
return 0;
@@ -991,6 +1315,7 @@ static int header_check_mbox(const unsigned char *buffer, const unsigned int buf
memcmp(buffer, "From MAILER-DAEMON ", 19)!=0)
{
/* From someone@somewhere */
+ /*@ loop assigns i; */
for(i=5; i<200 && buffer[i]!=' ' && buffer[i]!='@'; i++);
if(buffer[i]!='@')
return 0;
@@ -999,114 +1324,365 @@ static int header_check_mbox(const unsigned char *buffer, const unsigned int buf
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Incredimail has .imm extension but this extension isn't frequent */
- file_recovery_new->extension="mbox";
+ file_recovery_new->extension=extension_mbox;
return 1;
}
-static int header_check_fasttxt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_java || file_recovery_new->extension == extension_pm);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_perlm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- const txt_header_t *header=&fasttxt_headers[0];
- while(header->len > 0)
+ unsigned int i;
+ const unsigned int buffer_size_test=(buffer_size < 2048 ? buffer_size : 2048);
+ if(buffer_size < 128)
+ return 0;
+ for(i=0; i<128 && buffer[i]!=';' && buffer[i]!='\n'; i++);
+ if(buffer[i]!=';')
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ if( td_memmem(buffer, buffer_size_test, "class", 5)!=NULL ||
+ td_memmem(buffer, buffer_size_test, "private static", 14)!=NULL ||
+ td_memmem(buffer, buffer_size_test, "public interface", 16)!=NULL)
{
- if(memcmp(buffer, header->string, header->len)==0)
- {
- if(buffer[header->len]=='\0')
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->data_check=&data_check_txt;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension=header->extension;
- file_recovery_new->min_filesize=header->len+1;
- return 1;
- }
- header++;
+ /* source code in java */
+ file_recovery_new->extension=extension_java;
}
- return 0;
+ else
+ {
+ /* perl module */
+ file_recovery_new->extension=extension_pm;
+ }
+ return 1;
}
-static int is_ini(const char *buffer)
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_rtf);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_rtf(const unsigned char *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 *src=buffer;
- if(*src!='[')
+ unsigned int i;
+ if(buffer_size < 16)
return 0;
- src++;
- while(1)
- {
- if(*src==']')
- {
- if(src > buffer + 3)
- return 1;
- return 0;
- }
- if(!isalnum(*src) && *src!=' ')
+ for(i=0; i<16; i++)
+ if(buffer[i]=='\0')
return 0;
- src++;
- }
+ /* Avoid a false positive with .snt */
+ if(file_recovery->file_stat!=NULL
+#if !defined(MAIN_txt)
+ && file_recovery->file_stat->file_hint==&file_hint_doc
+#endif
+ )
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /* Rich Text Format */
+ file_recovery_new->extension=extension_rtf;
+ return 1;
}
-#ifdef UTF16
-static int header_check_le16_txt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_smil);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_smil);
+ @ 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_smil(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /* Synchronized Multimedia Integration Language
+ * http://en.wikipedia.org/wiki/Synchronized_Multimedia_Integration_Language */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_smil;
+ file_recovery_new->extension=extension_smil;
+ return 1;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_snz, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_snz.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->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_snz(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const unsigned int buffer_size_test=(buffer_size < 512? buffer_size : 512);
+ const unsigned char *pos=(const unsigned char *)td_memmem(buffer, buffer_size_test, ".snz", 4);
+ if(pos==NULL)
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=file_hint_snz.extension;
+ file_recovery_new->min_filesize=pos-buffer;
+ return 1;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_stl);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_stl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const unsigned int buffer_size_test=(buffer_size < 512? buffer_size : 512);
+ if(td_memmem(buffer, buffer_size_test, "facet normal", 12)==NULL)
+ return 0;
+ /* StereoLithography - STL Ascii format
+ * http://www.ennex.com/~fabbers/StL.asp */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=extension_stl;
+ return 1;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_svg);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_svg);
+ @ 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_svg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /* Scalable Vector Graphics */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=extension_svg;
+ file_recovery_new->file_check=&file_check_svg;
+ return 1;
+}
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_mbox);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_thunderbird(const unsigned char *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;
- for(i=0; i+1 < buffer_size; i+=2)
- {
- if(!( buffer[i+1]=='\0' && (isprint(buffer[i]) || buffer[i]=='\n' || buffer[i]=='\r' || buffer[i]==0xbb)))
- {
- if(i<40)
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->calculated_file_size=i;
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="utf16";
- return 1;
- }
- }
+ if(buffer_size < 64)
+ return 0;
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
+ file_recovery->extension == extension_mbox)
+ return 0;
+ /*@ loop assigns i; */
+ for(i=0; i<64; i++)
+ if(buffer[i]==0)
+ return 0;
reset_file_recovery(file_recovery_new);
- file_recovery_new->calculated_file_size=i;
- file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="utf16";
+ file_recovery_new->extension=extension_mbox;
return 1;
}
-#endif
-static void file_check_emlx(file_recovery_t *file_recovery)
+/*@
+ @ 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->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_ttd);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_ttd);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_ttd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- if(file_recovery->file_size < file_recovery->calculated_file_size)
- file_recovery->file_size=0;
- else
- {
- if(file_recovery->file_size > file_recovery->calculated_file_size+2048)
- file_recovery->file_size=file_recovery->calculated_file_size+2048;
- file_search_footer(file_recovery, "</plist>\n", 9, 0);
- }
+ if(buffer[56]<'0' || buffer[56]>'9')
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_ttd;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=extension_ttd;
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ /*@ assert \separated(file_recovery_new, file_recovery_new->extension); */
+ return 1;
}
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null || file_recovery_new->data_check == &data_check_html || file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_emlx || file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == \null || file_recovery_new->file_rename == &file_rename_html);
+ @ 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_txt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
static char *buffer_lower=NULL;
static unsigned int buffer_lower_size=0;
unsigned int l;
const unsigned int buffer_size_test=(buffer_size < 2048 ? buffer_size : 2048);
+ if(buffer_size < 512)
+ return 0;
{
unsigned int i;
- unsigned int tmp=0;
+ uint64_t tmp=0;
+ /*@
+ @ loop unroll 10;
+ @ loop invariant 0 <= i <= 10;
+ @ loop assigns i, tmp;
+ @ loop variant 10-i;
+ @*/
for(i=0;i<10 && isdigit(buffer[i]);i++)
- tmp=tmp*10+buffer[i]-'0';
+ {
+ /*@ assert '0' <= buffer[i] <= '9'; */
+ unsigned int v=buffer[i]-'0';
+ /*@ assert 0 <= v <= 9; */
+ tmp=tmp*10+v;
+ }
if(buffer[i]==0x0a &&
(memcmp(buffer+i+1, "Return-Path: ", 13)==0 ||
memcmp(buffer+i+1, "Received: from", 14)==0) &&
!(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_fasttxt &&
- strcmp(file_recovery->extension,"mbox")==0))
+ file_recovery->extension==extension_mbox))
{
reset_file_recovery(file_recovery_new);
file_recovery_new->calculated_file_size=tmp+i+1;
file_recovery_new->data_check=NULL;
file_recovery_new->file_check=&file_check_emlx;
/* Mac OSX mail */
- file_recovery_new->extension="emlx";
+ file_recovery_new->extension=extension_emlx;
return 1;
}
}
@@ -1118,7 +1694,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Dos/Windows batch */
- file_recovery_new->extension="bat";
+ file_recovery_new->extension=extension_bat;
return 1;
}
if(strncasecmp((const char *)buffer, "<%@ language=\"vbscript", 22)==0)
@@ -1129,7 +1705,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Microsoft Active Server Pages */
- file_recovery_new->extension="asp";
+ file_recovery_new->extension=extension_asp;
return 1;
}
if(strncasecmp((const char *)buffer, "version 4.00\r\nbegin", 19)==0)
@@ -1140,7 +1716,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Microsoft Visual Basic */
- file_recovery_new->extension="vb";
+ file_recovery_new->extension=extension_vb;
return 1;
}
if(strncasecmp((const char *)buffer, "begin:vcard", 11)==0)
@@ -1151,7 +1727,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* vcard, electronic business cards */
- file_recovery_new->extension="vcf";
+ file_recovery_new->extension=extension_vcf;
return 1;
}
if(buffer[0]=='#' && buffer[1]=='!')
@@ -1168,7 +1744,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Groovy script */
- file_recovery_new->extension="groovy";
+ file_recovery_new->extension=extension_groovy;
return 1;
}
if(td_memmem(haystack, ll, "perl", 4) != NULL)
@@ -1177,7 +1753,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Perl script */
- file_recovery_new->extension="pl";
+ file_recovery_new->extension=extension_pl;
return 1;
}
if(td_memmem(haystack, ll, "php", 3) != NULL)
@@ -1186,7 +1762,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* PHP script */
- file_recovery_new->extension="php";
+ file_recovery_new->extension=extension_php;
return 1;
}
if(td_memmem(haystack, ll, "python", 6) != NULL)
@@ -1195,7 +1771,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Python script */
- file_recovery_new->extension="py";
+ file_recovery_new->extension=extension_py;
return 1;
}
if(td_memmem(haystack, ll, "ruby", 4) != NULL)
@@ -1204,7 +1780,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Ruby script */
- file_recovery_new->extension="rb";
+ file_recovery_new->extension=extension_rb;
return 1;
}
}
@@ -1237,25 +1813,15 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
l=UTF2Lat((unsigned char*)buffer_lower, buffer, buffer_size_test);
if(l<10)
return 0;
- {
- unsigned int line_nbr=0;
- unsigned int i;
- for(i=0; i<512 && i<l; i++)
- {
- if(buffer[i]=='\n')
- line_nbr++;
- }
- /* A text file must contains several lines */
- if(line_nbr==0)
- return 0;
- }
+ if(has_newline(buffer_lower, l)==0)
+ return 0;
if(strncasecmp((const char *)buffer, "rem ", 4)==0)
{
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
/* Dos/Windows batch */
- file_recovery_new->extension="bat";
+ file_recovery_new->extension=extension_bat;
return 1;
}
if(strncasecmp((const char *)buffer, "dn: ", 4)==0)
@@ -1263,152 +1829,115 @@ 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;
- file_recovery_new->extension="ldif";
+ file_recovery_new->extension=extension_ldif;
return 1;
}
{
const char *ext=NULL;
- /* ind=~0: random
- * ind=~1: constant */
- double ind;
- unsigned int nbrf=0;
- unsigned int is_csv=1;
- char *str;
- /* Detect Fortran */
- {
- str=buffer_lower;
- while((str=strstr(str, "\n "))!=NULL)
- {
- nbrf++;
- str++;
- }
- }
- /* Detect csv */
- {
- unsigned int csv_per_line_current=0;
- unsigned int csv_per_line=0;
- unsigned int line_nbr=0;
- unsigned int i;
- for(i=0;i<l && is_csv>0;i++)
- {
- if(buffer_lower[i]==';')
- {
- csv_per_line_current++;
- }
- else if(buffer_lower[i]=='\n')
- {
- if(line_nbr==0)
- csv_per_line=csv_per_line_current;
- if(csv_per_line_current!=csv_per_line)
- is_csv=0;
- line_nbr++;
- csv_per_line_current=0;
- }
- }
- if(csv_per_line<1 || line_nbr<10)
- is_csv=0;
- }
- /* if(l>1) */
- {
- unsigned int stats[256];
- unsigned int i;
- memset(&stats, 0, sizeof(stats));
- for(i=0;i<l;i++)
- stats[(unsigned char)buffer_lower[i]]++;
- ind=0;
- for(i=0;i<256;i++)
- if(stats[i]>0)
- ind+=stats[i]*(stats[i]-1);
- ind=ind/l/(l-1);
- }
+ /* ind_random=~0: random
+ * ind_random=~1: constant */
+ double ind_random;
+ const char *str;
+ ind_random=is_random((const unsigned char *)buffer_lower, l);
/* Windows Autorun */
if(strstr(buffer_lower, "[autorun]")!=NULL)
- ext="inf";
+ {
+ ext=extension_inf;
+ log_info("ext=%s\n", ext);
+ }
/* Detect .ini */
- else if(buffer[0]=='[' && l>50 && is_ini(buffer_lower))
- ext="ini";
+ else if(buffer[0]=='[' && l>50 && is_ini((const unsigned char *)buffer_lower))
+ ext=extension_ini;
/* php (Hypertext Preprocessor) script */
else if(strstr(buffer_lower, "<?php")!=NULL)
- ext="php";
+ ext=extension_php;
/* Comma separated values */
- else if(is_csv>0)
- ext="csv";
+ else if(is_csv(buffer_lower, l)!=0)
+ ext=extension_csv;
/* Detect LaTeX, C, PHP, JSP, ASP, HTML, C header */
else if(strstr(buffer_lower, "\\begin{")!=NULL)
- ext="tex";
+ ext=extension_tex;
else if(strstr(buffer_lower, "#include")!=NULL)
- ext="c";
+ ext=extension_c;
else if(l>20 && strstr(buffer_lower, "<%@")!=NULL)
- ext="jsp";
+ ext=extension_jsp;
else if(l>20 && strstr(buffer_lower, "<%=")!=NULL)
- ext="jsp";
+ ext=extension_jsp;
else if(l>20 && strstr(buffer_lower, "<% ")!=NULL)
- ext="asp";
+ ext=extension_asp;
else if(strstr(buffer_lower, "<html")!=NULL)
- ext="html";
+ ext=extension_html;
else if(strstr(buffer_lower, "private static")!=NULL ||
strstr(buffer_lower, "public interface")!=NULL)
{
-#ifdef DJGPP
- ext="jav";
-#else
- ext="java";
-#endif
+ ext=extension_java;
}
else if(strstr(buffer_lower, "\nimport (")!=NULL)
{
- ext="go";
+ ext=extension_go;
}
else if((str=strstr(buffer_lower, "\nimport "))!=NULL)
{
+ /*@ assert valid_read_string(str); */
+#ifndef __FRAMAC__
str+=8;
+#endif
+ /*@ assert valid_read_string(str); */
+ /*@
+ @ loop assigns str;
+ @*/
while(*str!='\0' && *str!='\n' && *str!=';')
str++;
if(*str==';')
- ext="java";
+ ext=extension_java;
else
- ext="py";
+ ext=extension_py;
}
else if(strstr(buffer_lower, "class ")!=NULL &&
(l>=100 || file_recovery->file_stat==NULL))
{
-#ifdef DJGPP
- ext="jav";
-#else
- ext="java";
-#endif
+ ext=extension_java;
}
/* Fortran */
- else if(nbrf>10 && ind<0.9 && strstr(buffer_lower, "integer")!=NULL)
- ext="f";
+ else if(ind_random<0.9 && is_fortran(buffer_lower)!=0)
+ ext=extension_f;
/* LilyPond http://lilypond.org*/
else if(strstr(buffer_lower, "\\score {")!=NULL)
- ext="ly";
+ ext=extension_ly;
/* C header file */
else if(strstr(buffer_lower, "/*")!=NULL && l>50)
- ext="h";
- else if(l<100 || ind<0.03 || ind>0.90)
+ ext=extension_h;
+ else if(l<100 || ind_random<0.03 || ind_random>0.90)
ext=NULL;
/* JavaScript Object Notation */
else if(memcmp(buffer_lower, "{\"", 2)==0)
- ext="json";
+ ext=extension_json;
+ else if(strstr(buffer_lower,"<br>")!=NULL || strstr(buffer_lower,"<p>")!=NULL)
+ ext=extension_html;
else
ext=file_hint_txt.extension;
if(ext==NULL)
return 0;
- if(strcmp(ext,"txt")==0 &&
- (strstr(buffer_lower,"<br>")!=NULL || strstr(buffer_lower,"<p>")!=NULL))
- {
- ext="html";
- }
if(file_recovery->file_stat!=NULL)
{
- if(file_recovery->file_stat->file_hint == &file_hint_doc)
+ if(file_recovery->file_stat->file_hint == &file_hint_fasttxt ||
+ file_recovery->file_stat->file_hint == &file_hint_txt)
+ {
+ /* file_recovery->filename is a .html */
+ buffer_lower[511]='\0';
+ if(strstr(buffer_lower, "<html")==NULL)
+ return 0;
+ /* Special case: two consecutive HTML files */
+ }
+ else
+#if !defined(MAIN_txt)
+ if(file_recovery->file_stat->file_hint == &file_hint_doc)
+#endif
{
unsigned int i;
unsigned int txt_nl=0;
/* file_recovery->filename is .doc */
- if(ind>0.20)
+ if(ind_random>0.20)
return 0;
/* Unix: \n (0xA)
* Dos: \r\n (0xD 0xA)
@@ -1424,18 +1953,9 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
if(txt_nl<=1)
return 0;
}
- else if(file_recovery->file_stat->file_hint == &file_hint_fasttxt ||
- file_recovery->file_stat->file_hint == &file_hint_txt)
- {
- /* file_recovery->filename is a .html */
- buffer_lower[511]='\0';
- if(strstr(buffer_lower, "<html")==NULL)
- return 0;
- /* Special case: two consecutive HTML files */
- }
}
reset_file_recovery(file_recovery_new);
- if(strcmp(ext, "html")==0)
+ if(ext==extension_html)
{
file_recovery_new->file_rename=&file_rename_html;
file_recovery_new->data_check=&data_check_html;
@@ -1448,66 +1968,305 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
}
}
-static void file_check_smil(file_recovery_t *file_recovery)
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_vbm);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_vbm);
+ @ 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_vbm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- file_search_footer(file_recovery, "</smil>", 7, 0);
- file_allow_nl(file_recovery, NL_BARENL|NL_CRLF|NL_BARECR);
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->extension=extension_vbm;
+ file_recovery_new->file_check=&file_check_vbm;
+ return 1;
}
-static int header_check_smil(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 1;
+ @ ensures file_recovery_new->file_stat == \null;
+ @ ensures file_recovery_new->handle == \null;
+ @ ensures file_recovery_new->calculated_file_size == 0;
+ @ ensures file_recovery_new->file_size == 0;
+ @ ensures file_recovery_new->min_filesize == 0;
+ @ ensures file_recovery_new->data_check == \null ||
+ file_recovery_new->data_check == data_check_html ||
+ file_recovery_new->data_check == data_check_txt;
+ @ ensures file_recovery_new->file_check == \null ||
+ file_recovery_new->file_check == &file_check_gpx ||
+ file_recovery_new->file_check == &file_check_svg ||
+ file_recovery_new->file_check == &file_check_xml;
+ @ ensures file_recovery_new->file_rename == \null ||
+ file_recovery_new->file_rename == &file_rename_fods ||
+ file_recovery_new->file_rename == &file_rename_html;
+ @ ensures valid_read_string(file_recovery_new->extension);
+ @ ensures \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_xml(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- /* Synchronized Multimedia Integration Language
- * http://en.wikipedia.org/wiki/Synchronized_Multimedia_Integration_Language */
+ 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_txt;
- file_recovery_new->file_check=&file_check_smil;
- file_recovery_new->extension="smil";
+ file_recovery_new->file_check=&file_check_xml;
+ file_recovery_new->extension=NULL;
+ tmp=strchr(buf,'<');
+ while(tmp!=NULL)
+ {
+ if(strncasecmp(tmp, "<Grisbi>", 8)==0)
+ {
+ /* Grisbi - Personal Finance Manager XML data */
+ file_recovery_new->extension=extension_gsb;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<collection type=\"GC", 20)==0)
+ {
+ /* GCstart, personal collections manager, http://www.gcstar.org/ */
+ file_recovery_new->extension=extension_gcs;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<html", 5)==0)
+ {
+ file_recovery_new->data_check=&data_check_html;
+ file_recovery_new->extension=extension_html;
+ file_recovery_new->file_rename=&file_rename_html;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<Version>QBFSD", 14)==0)
+ {
+ /* QuickBook */
+ file_recovery_new->extension=extension_fst;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<svg", 4)==0)
+ {
+ /* Scalable Vector Graphics */
+ file_recovery_new->extension=extension_svg;
+ file_recovery_new->file_check=&file_check_svg;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<!DOCTYPE plist ", 16)==0)
+ {
+ /* Mac OS X property list */
+ file_recovery_new->extension=extension_plist;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<gpx ", 5)==0)
+ {
+ /* GPS eXchange Format */
+ file_recovery_new->extension=extension_gpx;
+ file_recovery_new->file_check=&file_check_gpx;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<PremiereData Version=", 22)==0)
+ {
+ /* Adobe Premiere project */
+ file_recovery_new->data_check=NULL;
+ file_recovery_new->extension=extension_prproj;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<SCRIBUS", 8)==0)
+ {
+ /* Scribus XML file */
+ file_recovery_new->extension=extension_sla;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<FictionBook", 12)==0)
+ {
+ /* FictionBook, see http://www.fictionbook.org */
+ file_recovery_new->extension=extension_fb2;
+ free(buf);
+ return 1;
+ }
+ else if(strncasecmp(tmp, "<office:document", 16)==0)
+ {
+ /* OpenDocument Flat XML Spreadsheet */
+ file_recovery_new->extension=extension_fods;
+ file_recovery_new->data_check=NULL;
+ file_recovery_new->file_rename=&file_rename_fods;
+ free(buf);
+ return 1;
+ }
+ tmp++;
+ tmp=strchr(tmp,'<');
+ }
+ /* XML Extensible Markup Language */
+ file_recovery_new->extension=extension_xml;
+ free(buf);
return 1;
}
-static int header_check_stl(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 1;
+ @ ensures file_recovery_new->file_stat == \null;
+ @ ensures file_recovery_new->handle == \null;
+ @ ensures file_recovery_new->extension == extension_ghx || file_recovery_new->extension == extension_xml;
+ @ ensures file_recovery_new->calculated_file_size == 0;
+ @ ensures file_recovery_new->file_size == 0;
+ @ ensures file_recovery_new->min_filesize == 0;
+ @ ensures (buffer_size >= 10) ==> (file_recovery_new->data_check == &data_check_xml_utf8);
+ @ ensures (buffer_size < 10) ==> file_recovery_new->data_check == \null;
+ @ ensures file_recovery_new->file_check == &file_check_xml;
+ @ ensures valid_read_string(file_recovery_new->extension);
+ @ ensures \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+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 unsigned int buffer_size_test=(buffer_size < 512? buffer_size : 512);
- if(td_memmem(buffer, buffer_size_test, "facet normal", 12)==NULL)
- return 0;
- /* StereoLithography - STL Ascii format
- * http://www.ennex.com/~fabbers/StL.asp */
+ 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_txt;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="stl";
+ if(buffer_size >= 10)
+ file_recovery_new->data_check=&data_check_xml_utf8;
+ file_recovery_new->extension=NULL;
+ tmp=strchr(buf,'<');
+ /*@
+ @ loop assigns tmp,file_recovery_new->extension;
+ @*/
+ while(tmp!=NULL && file_recovery_new->extension==NULL)
+ {
+ if(strncasecmp(tmp, "<Archive name=\"Root\">", 8)==0)
+ {
+ /* Grasshopper archive */
+ file_recovery_new->extension=extension_ghx;
+ }
+ tmp++;
+ tmp=strchr(tmp,'<');
+ }
+ if(file_recovery_new->extension==NULL)
+ {
+ file_recovery_new->extension=extension_xml;
+ }
+ file_recovery_new->file_check=&file_check_xml;
+ free(buf);
return 1;
}
-static int header_check_svg(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_xml);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
+ @*/
+static int header_check_xml_utf16(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- /* Scalable Vector Graphics */
+ /* Avoid false positive with .sldprt */
+ if(file_recovery->file_stat!=NULL
+#if !defined(MAIN_txt)
+ && file_recovery->file_stat->file_hint==&file_hint_doc
+#endif
+ )
+ return 0;
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="svg";
- file_recovery_new->file_check=&file_check_svg;
+ file_recovery_new->extension=extension_xml;
return 1;
}
-static int header_check_snz(const unsigned char *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 > 0;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->extension);
+ @ 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_fasttxt, buffer+(..), file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == extension_xmp);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_txt);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ 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_xmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- const unsigned int buffer_size_test=(buffer_size < 512? buffer_size : 512);
- const unsigned char *pos=(const unsigned char *)td_memmem(buffer, buffer_size_test, ".snz", 4);
- if(pos==NULL)
+ if(buffer[35]=='\0')
return 0;
+ if(file_recovery->file_stat!=NULL
+#if !defined(MAIN_txt)
+ && (file_recovery->file_stat->file_hint==&file_hint_jpg ||
+ file_recovery->file_stat->file_hint==&file_hint_pdf ||
+ file_recovery->file_stat->file_hint==&file_hint_tiff)
+#endif
+ )
+ return 0;
+ /* Adobe's Extensible Metadata Platform */
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->extension="snz";
- file_recovery_new->min_filesize=pos-buffer;
+ file_recovery_new->extension=extension_xmp;
return 1;
}
-static void register_header_check_snz(file_stat_t *file_stat)
-{
- register_header_check(0, "DEFAULT\n", 8, &header_check_snz, file_stat);
- register_header_check(0, "DEFAULT\r\n", 9, &header_check_snz, file_stat);
-}
-
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_fasttxt(file_stat_t *file_stat)
{
static const unsigned char header_xml_utf8[17] = {0xef, 0xbb, 0xbf, '<', '?', 'x', 'm', 'l', ' ', 'v', 'e', 'r', 's', 'i', 'o', 'n', '='};
@@ -1549,3 +2308,1815 @@ static void register_header_check_fasttxt(file_stat_t *file_stat)
register_header_check(0, "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"", 35, &header_check_xmp, file_stat);
register_header_check(0, "<svg xmlns=\"http://www.w3.org/2000/svg\"", 39, &header_check_svg, file_stat);
}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_snz(file_stat_t *file_stat)
+{
+ register_header_check(0, "DEFAULT\n", 8, &header_check_snz, file_stat);
+ register_header_check(0, "DEFAULT\r\n", 9, &header_check_snz, file_stat);
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_txt(file_stat_t *file_stat)
+{
+ unsigned int i;
+ for(i=0; i<256; i++)
+ ascii_char[i]=i;
+ for(i=0; i<256; i++)
+ {
+ if(filtre(i) || i==0xE2 || i==0xC2 || i==0xC3 || i==0xC5 || i==0xC6 || i==0xCB)
+ register_header_check(0, &ascii_char[i], 1, &header_check_txt, file_stat);
+ }
+#ifdef UTF16
+ register_header_check(1, &ascii_char[0], 1, &header_check_le16_txt, file_stat);
+#endif
+}
+
+#if defined(MAIN_txt)
+#define BLOCKSIZE 65536u
+static int main_dc()
+{
+ const char fn[] = "recup_dir.1/f0000000.dc";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_dc(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 file_recovery_new.extension == extension_dc; */
+ /*@ assert valid_read_string(extension_dc); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_rename == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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 file_recovery_new.extension == extension_dc; */
+ /*@ assert valid_read_string(extension_dc); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_dc(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;
+}
+
+static int main_ers()
+{
+ const char fn[] = "recup_dir.1/f0000000.ers";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_ers(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 file_recovery_new.extension == extension_ers; */
+ /*@ assert valid_read_string(extension_ers); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_ers; */
+ /*@ assert file_recovery_new.file_rename == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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 file_recovery_new.extension == extension_ers; */
+ /*@ assert valid_read_string(extension_ers); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_ers(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_ers; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_ers(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+
+static int main_fasttxt()
+{
+ const char fn[] = "recup_dir.1/f0000000.txt";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_fasttxt(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ /*@ assert file_recovery_new.extension != \null; */
+ 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 valid_read_string((char *)file_recovery_new.extension); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_rename == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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.extension); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_fasttxt(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;
+}
+
+static int main_html()
+{
+ const char fn[] = "recup_dir.1/f0000000.html";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_html(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 file_recovery_new.extension == extension_html; */
+ /*@ assert valid_read_string(extension_html); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_html; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_rename == &file_rename_html; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_html; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_html(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_html; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_html(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 file_recovery_new.extension == extension_html; */
+ /*@ assert valid_read_string(extension_html); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_html(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);
+ }
+ file_rename_html(&file_recovery_new);
+ return 0;
+}
+
+static int main_ics()
+{
+ const char fn[] = "recup_dir.1/f0000000.ics";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_ics(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 file_recovery_new.extension == extension_ics; */
+ /*@ assert valid_read_string(extension_ics); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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 file_recovery_new.extension == extension_ics; */
+ /*@ assert valid_read_string(extension_ics); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_ics(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;
+}
+
+static int main_mbox()
+{
+ const char fn[] = "recup_dir.1/f0000000.mbox";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_mbox(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 file_recovery_new.extension == extension_mbox; */
+ /*@ assert valid_read_string(extension_mbox); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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 file_recovery_new.extension == extension_mbox; */
+ /*@ assert valid_read_string(extension_mbox); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_mbox(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;
+}
+
+static int main_perlm()
+{
+ const char fn[] = "recup_dir.1/f0000000.pm";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_perlm(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 == extension_pm || file_recovery_new.extension == extension_java; */
+ /*@ assert valid_read_string((char *)file_recovery_new.extension); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_perlm(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;
+}
+
+static int main_rtf()
+{
+ const char fn[] = "recup_dir.1/f0000000.rtf";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_rtf(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 == extension_rtf; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_rtf(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;
+}
+
+static int main_smail()
+{
+ const char fn[] = "recup_dir.1/f0000000.smil";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_smil(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 == extension_smil; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_smil; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_smil(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_smil; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_smil(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+
+static int main_snz()
+{
+ const char fn[] = "recup_dir.1/f0000000.snz";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_snz;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_snz(&file_stats);
+#endif
+ if(header_check_snz(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_snz.extension; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_snz; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_snz(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;
+}
+
+static int main_stl()
+{
+ const char fn[] = "recup_dir.1/f0000000.stl";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_stl(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 == extension_stl; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_stl(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;
+}
+
+static int main_svg()
+{
+ const char fn[] = "recup_dir.1/f0000000.svg";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_svg(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 == extension_svg; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_svg; */
+ /*@ assert file_recovery_new.data_check == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_svg(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_svg; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_svg(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+
+static int main_thunderbird()
+{
+ const char fn[] = "recup_dir.1/f0000000.mbox";
+ 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);
+ reset_file_recovery(&file_recovery_new);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_thunderbird(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(extension_mbox); */
+ /*@ assert file_recovery_new.extension == extension_mbox; */
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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(extension_mbox); */
+ /*@ assert file_recovery_new.extension == extension_mbox; */
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_thunderbird(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;
+}
+
+static int main_ttd()
+{
+ const char fn[] = "recup_dir.1/f0000000.ttd";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+// register_header_check_fasttxt(&file_stats);
+ if(header_check_ttd(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 == extension_ttd; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_ttd; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_ttd; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_ttd(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_ttd(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_ttd(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;
+}
+
+static int main_txt()
+{
+ const char fn[] = "recup_dir.1/f0000000.txt";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.extension == \null; */
+ /*@ assert file_recovery.file_stat == \null; */
+ 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_txt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_txt(&file_stats);
+#endif
+ /*@ assert file_recovery.extension == \null; */
+ if(header_check_txt(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ /*@ assert file_recovery_new.extension != \null; */
+ 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 valid_read_string((char *)file_recovery_new.extension); */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.data_check == \null || file_recovery_new.data_check == &data_check_html || file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_check == &file_check_emlx || file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.file_rename == \null || file_recovery_new.file_rename == &file_rename_html; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_txt; */
+ if(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_html || file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=file_recovery_new.data_check(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
+ file_recovery_new.data_check(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.extension); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_txt(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_emlx || file_recovery_new.file_check == &file_check_size; */
+ 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 file_recovery_new.file_rename == &file_rename_html; */
+ file_rename_html(&file_recovery_new);
+ }
+ return 0;
+}
+
+static int main_vbm()
+{
+ const char fn[] = "recup_dir.1/f0000000.vbm";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_vbm(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 == extension_vbm; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_vbm; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_vbm(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_vbm; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_vbm(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+
+static int main_xml()
+{
+ const char fn[] = "recup_dir.1/f0000000.xml";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_xml(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.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_gpx ||
+ file_recovery_new.file_check == &file_check_svg ||
+ file_recovery_new.file_check == &file_check_xml; */
+ /*@ assert file_recovery_new.data_check == \null ||
+ file_recovery_new.data_check == &data_check_html ||
+ file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_rename == \null ||
+ file_recovery_new.file_rename == &file_rename_fods ||
+ file_recovery_new.file_rename == &file_rename_html;
+ */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ if(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.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=file_recovery_new.data_check(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
+ file_recovery_new.data_check(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_xml(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)
+ {
+ file_recovery_new.file_rename(&file_recovery_new);
+ }
+ return 0;
+}
+
+static int main_xml_utf8()
+{
+ const char fn[] = "recup_dir.1/f0000000.xml";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_xml_utf8(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 == extension_ghx || file_recovery_new.extension == extension_xml; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_xml; */
+ /*@ assert file_recovery_new.data_check == &data_check_xml_utf8; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_xml_utf8; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_xml_utf8(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_xml_utf8(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert file_recovery_new.file_check == &file_check_xml; */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_xml(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+
+static int main_xml_utf16()
+{
+ const char fn[] = "recup_dir.1/f0000000.xml";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_xml_utf16(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 == extension_xml; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == \null; */
+ /*@ assert file_recovery_new.data_check == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_xml_utf16(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert file_recovery_new.file_check == \null; */
+ return 0;
+}
+
+static int main_xmp()
+{
+ const char fn[] = "recup_dir.1/f0000000.xmp";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.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_fasttxt;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+#if 0
+ register_header_check_fasttxt(&file_stats);
+#endif
+ if(header_check_xmp(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 == extension_xmp; */
+ /*@ assert file_recovery_new.calculated_file_size == 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ /*@ assert file_recovery_new.file_stat->file_hint==&file_hint_fasttxt; */
+ {
+ 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_txt; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_txt(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_txt; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_txt(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_xmp(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;
+}
+
+int main()
+{
+ main_dc();
+ main_ers();
+ main_fasttxt();
+ main_html();
+ main_ics();
+ main_mbox();
+ main_perlm();
+ main_rtf();
+ main_smail();
+ main_snz();
+ main_stl();
+ main_svg();
+ main_thunderbird();
+ main_ttd();
+ main_txt();
+ main_vbm();
+ main_xml();
+ main_xml_utf8();
+ main_xml_utf16();
+ main_xmp();
+ return 0;
+}
+#endif
diff --git a/src/file_txt.h b/src/file_txt.h
index 127f96f..b1a6641 100644
--- a/src/file_txt.h
+++ b/src/file_txt.h
@@ -19,5 +19,10 @@
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-int UTF2Lat(unsigned char *buffer_lower, const unsigned char *buffer, const int buf_len);
-
+/*@
+ @ requires buf_len> 0;
+ @ requires \valid_read(buffer+(0..buf_len-1));
+ @ ensures 0 <= \result <= buf_len;
+ @ assigns \nothing;
+ @*/
+int UTFsize(const unsigned char *buffer, const unsigned int buf_len);
diff --git a/src/file_win.c b/src/file_win.c
index 4db35b6..9e8b726 100644
--- a/src/file_win.c
+++ b/src/file_win.c
@@ -49,19 +49,16 @@ const file_hint_t file_hint_win= {
static data_check_t data_check_win(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
unsigned int i;
- char *buffer_lower=(char *)MALLOC(buffer_size+16);
unsigned int offset=0;
if(file_recovery->calculated_file_size==0)
offset=3;
- i=UTF2Lat((unsigned char*)buffer_lower, &buffer[buffer_size/2+offset], buffer_size/2-offset);
+ i=UTFsize(&buffer[buffer_size/2+offset], buffer_size/2-offset);
if(i<buffer_size/2-offset)
{
if(i>=10)
file_recovery->calculated_file_size=file_recovery->file_size+offset+i;
- free(buffer_lower);
return DC_STOP;
}
- free(buffer_lower);
file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
return DC_CONTINUE;
}
diff --git a/src/file_zip.c b/src/file_zip.c
index 417bd3d..f80d461 100644
--- a/src/file_zip.c
+++ b/src/file_zip.c
@@ -46,10 +46,7 @@
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);
static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size);
-static void file_rename_zip(file_recovery_t *file_recovery);
static char first_filename[256];
const file_hint_t file_hint_zip= {
@@ -242,7 +239,7 @@ static int zip_parse_file_entry_fn(file_recovery_t *fr, const char **ext, const
return -1;
}
#if defined(__FRAMAC__)
- Frama_C_make_unknown(buffer, 128);
+ Frama_C_make_unknown((char *)buffer, 128);
#endif
if (my_fseek(fr->handle, -to_read, SEEK_CUR) < 0)
{
@@ -336,6 +333,7 @@ static int zip_parse_file_entry_fn(file_recovery_t *fr, const char **ext, const
@ requires \valid(fr->handle);
@ requires \valid(ext);
@ requires fr->file_size < 0x8000000000000000 + 4;
+ @ requires \separated(fr, ext);
@*/
static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const unsigned int file_nbr)
{
@@ -755,6 +753,7 @@ static int zip64_parse_end_central_dir_locator(file_recovery_t *fr)
/*@
@ requires \valid(fr);
@ requires \valid(fr->handle);
+ @ requires fr->file_check==&file_check_zip;
@*/
static void file_check_zip(file_recovery_t *fr)
{
@@ -851,23 +850,31 @@ static void file_check_zip(file_recovery_t *fr)
/*@
@ requires \valid(file_recovery);
@ requires valid_read_string((char*)file_recovery->filename);
+ @ requires file_recovery->file_rename==&file_rename_zip;
@*/
+/* TODO ensures valid_read_string((char*)file_recovery->filename); */
static void file_rename_zip(file_recovery_t *file_recovery)
{
const char *ext=NULL;
unsigned int file_nbr=0;
file_recovery_t fr;
reset_file_recovery(&fr);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
if((fr.handle=fopen(file_recovery->filename, "rb"))==NULL)
+ {
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
+ }
fr.file_size = 0;
fr.offset_error=0;
first_filename[0]='\0';
if(my_fseek(fr.handle, 0, SEEK_SET) < 0)
{
fclose(fr.handle);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return ;
}
+ /*@ loop invariant valid_read_string((char*)file_recovery->filename); */
while (1)
{
uint32_t header;
@@ -875,6 +882,7 @@ static void file_rename_zip(file_recovery_t *file_recovery)
if(file_nbr>=0xffffffff || fr.file_size >= 0x8000000000000000 - 4)
{
fclose(fr.handle);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
}
/*@ assert fr.file_size < 0x8000000000000000 - 4; */
@@ -885,6 +893,7 @@ static void file_rename_zip(file_recovery_t *file_recovery)
log_trace("Failed to read block header\n");
#endif
fclose(fr.handle);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
}
#if defined(__FRAMAC__)
@@ -921,7 +930,9 @@ static void file_rename_zip(file_recovery_t *file_recovery)
if(ext!=NULL)
{
fclose(fr.handle);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
file_rename(file_recovery, NULL, 0, 0, ext, 1);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
}
break;
@@ -943,6 +954,7 @@ static void file_rename_zip(file_recovery_t *file_recovery)
if (status<0)
{
fclose(fr.handle);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
}
/* Only end of central dir is end of archive, 64b version of it is before */
@@ -956,7 +968,9 @@ static void file_rename_zip(file_recovery_t *file_recovery)
first_filename[len]!='/' &&
first_filename[len]!='\\';
len++);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
file_rename(file_recovery, first_filename, len, 0, "zip", 0);
+ /*@ assert valid_read_string((char*)file_recovery->filename); */
return;
}
}
@@ -966,14 +980,23 @@ 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->extension);
@ 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);
+ @ requires separation: \separated(&file_hint_zip, file_recovery, file_recovery_new);
@ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_stat == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->handle == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->time == 0);
@ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 21);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == \null);
@ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_zip || file_recovery_new->file_check == \null);
@ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_zip || file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> \separated(file_recovery_new, file_recovery_new->extension);
@*/
static int header_check_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)
{
@@ -1072,7 +1095,7 @@ static int header_check_zip(const unsigned char *buffer, const unsigned int buff
@ 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);
+ @ requires separation: \separated(&file_hint_zip, 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;
@@ -1140,6 +1163,7 @@ int main()
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;
diff --git a/src/filegen.c b/src/filegen.c
index c197b5e..70b6913 100644
--- a/src/filegen.c
+++ b/src/filegen.c
@@ -39,6 +39,9 @@
#include "common.h"
#include "filegen.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static file_check_t file_check_plist={
.list = TD_LIST_HEAD_INIT(file_check_plist.list)
@@ -50,11 +53,18 @@ file_check_list_t file_check_list={
static unsigned int index_header_check(void);
+/*@
+ @ requires \valid_read(a);
+ @ requires \valid_read(b);
+ @*/
static int file_check_cmp(const struct td_list_head *a, const struct td_list_head *b)
{
const file_check_t *fc_a=td_list_entry_const(a, const file_check_t, list);
const file_check_t *fc_b=td_list_entry_const(b, const file_check_t, list);
int res;
+ unsigned int min_length;
+ /*@ assert \valid_read(fc_a); */
+ /*@ assert \valid_read(fc_b); */
if(fc_a->length==0 && fc_b->length!=0)
return -1;
if(fc_a->length!=0 && fc_b->length==0)
@@ -62,23 +72,44 @@ static int file_check_cmp(const struct td_list_head *a, const struct td_list_hea
res=fc_a->offset-fc_b->offset;
if(res!=0)
return res;
- res=memcmp(fc_a->value,fc_b->value, (fc_a->length<=fc_b->length?fc_a->length:fc_b->length));
+ /*@ assert \valid_read((char *)fc_a->value + (0 .. fc_a->length - 1)); */
+ /*@ assert \initialized((char *)fc_a->value + (0 .. fc_a->length - 1)); */
+#if 0
+ /*@ assert \valid_read((char *)fc_b->value + (0 .. fc_b->length - 1)); */
+ /*@ assert \initialized((char *)fc_b->value + (0 .. fc_b->length - 1)); */
+#endif
+ min_length=fc_a->length<=fc_b->length?fc_a->length:fc_b->length;
+ res=memcmp(fc_a->value,fc_b->value, min_length);
if(res!=0)
return res;
return (int)fc_b->length-(int)fc_a->length;
}
+/*@
+ @ requires \valid(file_check_new);
+ @ requires \valid(pos);
+ @*/
static void file_check_add_tail(file_check_t *file_check_new, file_check_list_t *pos)
{
unsigned int i;
+ const unsigned int tmp=(file_check_new->length==0?0:((const unsigned char *)file_check_new->value)[0]);
file_check_list_t *newe=(file_check_list_t *)MALLOC(sizeof(*newe));
newe->offset=file_check_new->offset;
+ /*@
+ @ loop unroll 256;
+ @ loop invariant 0 <= i <= 256;
+ @ loop assigns i, newe->file_checks[0 .. 255].list.prev, newe->file_checks[0 .. 255].list.next;
+ @ loop variant 255-i;
+ @*/
for(i=0;i<256;i++)
{
newe->file_checks[i].list.prev=&newe->file_checks[i].list;
newe->file_checks[i].list.next=&newe->file_checks[i].list;
+ /*@ assert newe->file_checks[i].list.prev == &newe->file_checks[i].list; */
+ /*@ assert newe->file_checks[i].list.next == &newe->file_checks[i].list; */
}
- td_list_add_tail(&file_check_new->list, &newe->file_checks[file_check_new->length==0?0:((const unsigned char *)file_check_new->value)[0]].list);
+ /*@ assert newe->file_checks[tmp].list.prev == &newe->file_checks[tmp].list; */
+ td_list_add_tail(&file_check_new->list, &newe->file_checks[tmp].list);
td_list_add_tail(&newe->list, &pos->list);
}
@@ -95,10 +126,15 @@ void register_header_check(const unsigned int offset, const void *value, const u
td_list_add_sorted(&file_check_new->list, &file_check_plist.list, file_check_cmp);
}
+/*@
+ @ requires \valid(file_check_new);
+ @*/
static void index_header_check_aux(file_check_t *file_check_new)
{
if(file_check_new->length>0)
{
+ /*@ assert file_check_new->offset < 0x80000000; */
+ /*@ assert 0 < file_check_new->length <= 4096; */
struct td_list_head *tmp;
td_list_for_each(tmp, &file_check_list.list)
{
@@ -146,6 +182,11 @@ void free_header_check(void)
{
unsigned int i;
file_check_list_t *pos=td_list_entry(tmpl, file_check_list_t, list);
+ /*@
+ @ loop unroll 256;
+ @ loop invariant 0 <= i <= 256;
+ @*/
+ /* TODO loop variant 255-i; */
for(i=0;i<256;i++)
{
struct td_list_head *tmp;
@@ -186,6 +227,9 @@ void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode)
if(my_fseek(file_recovery->handle, file_recovery->file_size,SEEK_SET)<0)
return;
taille=fread(buffer,1, 4096,file_recovery->handle);
+#ifdef __FRAMAC__
+ Frama_C_make_unknown((char *)&buffer, 4096);
+#endif
if(taille > 0 && buffer[0]=='\n' && (nl_mode&NL_BARENL)==NL_BARENL)
file_recovery->file_size++;
else if(taille > 1 && buffer[0]=='\r' && buffer[1]=='\n' && (nl_mode&NL_CRLF)==NL_CRLF)
@@ -198,20 +242,35 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
{
unsigned char*buffer;
assert(footer_length < 4096);
- buffer=(unsigned char*)MALLOC(4096+footer_length-1);
+ /*@ assert 0 < footer_length < 4096; */
+ /*
+ * 4096+footer_length-1: required size
+ * 4096+footer_length: to avoid a Frama-C warning when footer_length==1
+ * 8192: maximum size
+ * */
+ buffer=(unsigned char*)MALLOC(4096+footer_length);
memset(buffer+4096,0,footer_length-1);
do
{
int i;
int taille;
- const unsigned int read_size=(offset%4096!=0 ? offset%4096 : 4096);
- offset-=read_size;
+ if(offset <= 4096)
+ offset=0;
+ else if(offset%4096==0)
+ offset-=4096;
+ else
+ offset=offset-(offset%4096);
if(my_fseek(handle,offset,SEEK_SET)<0)
{
free(buffer);
return 0;
}
- taille=fread(buffer, 1, read_size, handle);
+ taille=fread(buffer, 1, 4096, handle);
+ if(taille <= 0)
+ {
+ free(buffer);
+ return 0;
+ }
for(i=taille-1;i>=0;i--)
{
if(buffer[i]==*(const unsigned char *)footer && memcmp(buffer+i,footer,footer_length)==0)
@@ -233,6 +292,7 @@ void file_search_footer(file_recovery_t *file_recovery, const void*footer, const
file_recovery->file_size=file_rsearch(file_recovery->handle, file_recovery->file_size-extra_length, footer, footer_length);
if(file_recovery->file_size > 0)
file_recovery->file_size+= footer_length + extra_length;
+ /*@ assert \valid(file_recovery->handle); */
}
#if 0
@@ -373,88 +433,81 @@ file_stat_t * init_file_stats(file_enable_t *files_enable)
/*@
@ requires \valid(file_recovery);
@ requires valid_read_string((const char*)&file_recovery->filename);
- @ requires new_ext==\null || valid_read_string(new_ext);
+ @ requires valid_read_string(new_ext);
+ @ ensures valid_read_string((char*)&file_recovery->filename);
@*/
-static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+static int file_rename_aux(file_recovery_t *file_recovery, const char *new_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 new_filename[sizeof(file_recovery->filename)];
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')
+ char *dst_dir_sep;
+ unsigned int len=strlen(file_recovery->filename)+1;
+ len+=strlen(new_ext);
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ if(len > sizeof(file_recovery->filename))
{
- if(*src=='/')
- {
- directory_sep=dst;
- ext=NULL;
- }
- if(*src=='.')
- ext=src;
- *dst++ = *src++;
+ return -1;
}
- *dst='\0';
- dst=directory_sep;
+ /*@ assert len <= sizeof(file_recovery->filename); */
+ /*@ assert valid_read_string((char*)&file_recovery->filename); */
+ strcpy(new_filename, (char *)&file_recovery->filename);
+ dst_dir_sep=strrchr(new_filename, '/');
+#ifndef __FRAMAC__
+ /*@ assert valid_read_string(dst_dir_sep); */
+ dst=dst_dir_sep;
while(*dst!='.' && *dst!='\0')
dst++;
/* Add extension */
- if(new_ext!=NULL)
{
+ const char *src;
src=new_ext;
*dst++ = '.';
while(*src!='\0')
*dst++ = *src++;
+ *dst='\0';
}
- else if(append_original_ext>0)
+#endif
+ /*@ assert valid_read_string(&new_filename[0]); */
+ if(strlen(new_filename) >= sizeof(file_recovery->filename))
{
- if(ext!=NULL)
- {
- while(*ext!='\0')
- *dst++ = *ext++;
- }
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ return -1;
}
- *dst='\0';
- if(rename(file_recovery->filename, new_filename)<0)
+ /*@ assert valid_read_string(&new_filename[0]); */
+ if(rename(&file_recovery->filename[0], new_filename)<0)
{
/* Rename has failed */
- free(new_filename);
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
return -1;
}
- if(strlen(new_filename)<sizeof(file_recovery->filename))
- {
- strcpy(file_recovery->filename, new_filename);
- }
- free(new_filename);
+ /*@ assert valid_read_string(&new_filename[0]); */
+ strcpy(file_recovery->filename, new_filename);
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
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)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires 0 <= offset < buffer_size;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @ ensures valid_read_string((char*)&file_recovery->filename);
+ @*/
+static 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;
const char *ext=NULL;
char *dst;
char *directory_sep;
int len;
- if(buffer_size<0)
- return -1;
len=strlen(src)+1;
- if(offset < buffer_size && buffer!=NULL)
- len+=buffer_size-offset+1;
+ /*@ assert offset < buffer_size; */
+ len+=buffer_size-offset+1;
if(new_ext!=NULL)
len+=strlen(new_ext);
+#ifndef __FRAMAC__
new_filename=(char*)MALLOC(len);
dst=new_filename;
directory_sep=new_filename;
@@ -474,7 +527,6 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
while(*dst!='.' && *dst!='\0')
dst++;
/* Add original filename */
- if(offset < buffer_size && buffer!=NULL)
{
char *dst_old=dst;
int off;
@@ -538,112 +590,72 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
}
}
*dst='\0';
- if(rename(file_recovery->filename, new_filename)<0)
- {
- /* Rename has failed */
- free(new_filename);
- if(buffer==NULL)
- return -1;
- /* Try without the original filename */
- return file_rename_aux(file_recovery, new_ext, append_original_ext);
- }
- if(strlen(new_filename)<sizeof(file_recovery->filename))
+ /*@ assert valid_read_string(new_filename); */
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ if(strlen(new_filename)<sizeof(file_recovery->filename) && rename(file_recovery->filename, new_filename)==0)
{
strcpy(file_recovery->filename, new_filename);
+ free(new_filename);
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ return 0;
+
}
free(new_filename);
#endif
- return 0;
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ return -1;
}
-/*@
- @ 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)
+/* 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)
{
- 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;
+ if(buffer!=NULL && 0 <= offset && offset < buffer_size &&
+ _file_rename(file_recovery, buffer, buffer_size, offset, new_ext, append_original_ext)==0)
+ return 0;
+ if(new_ext==NULL)
+ return 0;
+ /* Try without the original filename */
+ return file_rename_aux(file_recovery, new_ext);
}
/* 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)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires 0 <= offset < buffer_size;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @ ensures valid_read_string((char*)&file_recovery->filename);
+ @*/
+static 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;
- const char *ext=src;
+ const char *src_ext=src;
char *dst;
- char *directory_sep;
+ char *dst_dir_sep;
int len=strlen(src)+1;
- if(buffer_size<0)
- return -1;
- if(offset < buffer_size && buffer!=NULL)
- len+=buffer_size-offset;
+ /*@ assert offset < buffer_size; */
+ len+=buffer_size-offset;
if(new_ext!=NULL)
len+=strlen(new_ext);
+#ifndef __FRAMAC__
new_filename=(char*)MALLOC(len);
dst=new_filename;
- directory_sep=dst;
+ dst_dir_sep=dst;
while(*src!='\0')
{
if(*src=='/')
- directory_sep=dst;
+ dst_dir_sep=dst;
if(*src=='.')
- ext=src;
+ src_ext=src;
*dst++ = *src++;
}
*dst='\0';
- dst=directory_sep;
+ dst=dst_dir_sep;
while(*dst!='.' && *dst!='\0')
dst++;
/* Add original filename */
- if(offset < buffer_size && buffer!=NULL)
{
char *dst_old=dst;
int off;
@@ -698,32 +710,40 @@ int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, cons
while(*src!='\0')
*dst++ = *src++;
}
- else if(append_original_ext>0)
+ else if(append_original_ext>0 && src_ext!=NULL)
{
- while(*ext!='\0')
- *dst++ = *ext++;
+ while(*src_ext!='\0')
+ *dst++ = *src_ext++;
}
*dst='\0';
- if(rename(file_recovery->filename, new_filename)<0)
- {
- /* Rename has failed */
- free(new_filename);
- if(buffer==NULL)
- return -1;
- /* Try without the original filename */
- return file_rename_unicode_aux(file_recovery, new_ext, append_original_ext);
- }
- if(strlen(new_filename)<sizeof(file_recovery->filename))
+ if(strlen(new_filename)<sizeof(file_recovery->filename) && rename(file_recovery->filename, new_filename)==0)
{
strcpy(file_recovery->filename, new_filename);
+ free(new_filename);
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ return 0;
}
free(new_filename);
#endif
- return 0;
+ /*@ assert valid_read_string(&file_recovery->filename[0]); */
+ return -1;
+}
+
+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)
+{
+ if(buffer!=NULL && 0 <= offset && offset < buffer_size &&
+ _file_rename_unicode(file_recovery, buffer, buffer_size, offset, new_ext, append_original_ext)==0)
+ return 0;
+ if(new_ext==NULL)
+ return 0;
+ return file_rename_aux(file_recovery, new_ext);
}
static uint64_t offset_skipped_header=0;
+/*@
+ @ assigns offset_skipped_header;
+ @*/
void header_ignored_cond_reset(uint64_t start, uint64_t end)
{
if(start <= offset_skipped_header && offset_skipped_header <= end)
@@ -820,12 +840,13 @@ void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **cur
return;
}
*current_search_space=file_space;
- if(file_space->start < prev_location || file_space->start < offset_skipped_header)
+ if(file_space->start < offset_skipped_header)
{
#ifdef DEBUG_PREV_LOCATION
- log_info("get_prev_location_smart: file_space->start < prev_location=%llu (in 512-bytes sectors), offset=%llu\n",
+ log_info("get_prev_location_smart: file_space->start < offset_skipped_header, prev_location=%llu (in 512-bytes sectors), offset=%llu => %llu\n",
(long long unsigned)(prev_location/512),
- (long long unsigned)(*offset/512));
+ (long long unsigned)(*offset/512),
+ (long long unsigned)(offset_skipped_header/512));
#endif
*offset=offset_skipped_header;
offset_skipped_header=0;
diff --git a/src/filegen.h b/src/filegen.h
index 31aabfa..2c6af8a 100644
--- a/src/filegen.h
+++ b/src/filegen.h
@@ -122,6 +122,8 @@ void free_header_check(void);
/*@
@ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @ ensures \valid(file_recovery->handle);
@*/
void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode);
@@ -134,32 +136,43 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
/*@
@ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
@ requires footer_length > 0;
@ requires \valid_read((char *)footer+(0..footer_length-1));
+ @ ensures \valid(file_recovery->handle);
@*/
void file_search_footer(file_recovery_t *file_recovery, const void*footer, const unsigned int footer_length, const unsigned int extra_length);
/*@
- @ requires buffer_size > 0;
+ @ requires buffer_size >= 2;
+ @ requires (buffer_size&1)==0;
@ requires \valid_read((char *)buffer+(0..buffer_size-1));
@ requires \valid(file_recovery);
- @ assigns \nothing;
+ @ requires file_recovery->data_check == &data_check_size;
@ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @ ensures file_recovery->data_check == &data_check_size;
+ @ assigns \nothing;
@*/
data_check_t data_check_size(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
/*@
@ requires \valid(file_recovery);
+ @ requires file_recovery->file_check == &file_check_size;
+ @ assigns file_recovery->file_size;
@*/
void file_check_size(file_recovery_t *file_recovery);
/*@
@ requires \valid(file_recovery);
+ @ requires file_recovery->file_check == &file_check_size_min;
+ @ assigns file_recovery->file_size;
@*/
void file_check_size_min(file_recovery_t *file_recovery);
/*@
@ requires \valid(file_recovery);
+ @ requires file_recovery->file_check == &file_check_size_max;
+ @ assigns file_recovery->file_size;
@*/
void file_check_size_max(file_recovery_t *file_recovery);
@@ -211,6 +224,7 @@ void file_check_size_max(file_recovery_t *file_recovery);
void reset_file_recovery(file_recovery_t *file_recovery);
/*@
+ @ requires offset < 0x80000000;
@ requires 0 < length <= 4096;
@ requires \valid_read((char *)value+(0..length-1));
@ requires \valid_function(header_check);
@@ -230,6 +244,7 @@ file_stat_t * init_file_stats(file_enable_t *files_enable);
@ 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);
+ @ ensures valid_read_string((char*)&file_recovery->filename);
@*/
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);
@@ -238,6 +253,7 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
@ 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);
+ @ ensures valid_read_string((char*)&file_recovery->filename);
@*/
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);
diff --git a/src/list.h b/src/list.h
index 29e8dad..c4fbe67 100644
--- a/src/list.h
+++ b/src/list.h
@@ -59,6 +59,17 @@ struct td_list_head {
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
+/*@
+ @ requires \valid(newe);
+ @ requires \valid(prev);
+ @ requires \valid(next);
+ @ requires separation: \separated(newe, \union(prev,next));
+ @ ensures next->prev == newe;
+ @ ensures newe->next == next;
+ @ ensures newe->prev == prev;
+ @ ensures prev->next == newe;
+ @ assigns next->prev,newe->next,newe->prev,prev->next;
+ @*/
static inline void __td_list_add(struct td_list_head *newe,
struct td_list_head *prev,
struct td_list_head *next)
@@ -90,6 +101,17 @@ static inline void td_list_add(struct td_list_head *newe, struct td_list_head *h
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
+/*@
+ @ requires \valid(newe);
+ @ requires \valid(head);
+ @ requires \valid(head->prev);
+ @ requires separation: \separated(newe, head);
+ @ ensures head->prev == newe;
+ @ ensures newe->next == head;
+ @ ensures newe->prev == \old(head->prev);
+ @ ensures \old(head->prev)->next == newe;
+ @ assigns head->prev,newe->next,newe->prev,\old(head->prev)->next;
+ @*/
static inline void td_list_add_tail(struct td_list_head *newe, struct td_list_head *head)
{
__td_list_add(newe, head->prev, head);
@@ -102,10 +124,19 @@ static inline void td_list_add_tail(struct td_list_head *newe, struct td_list_he
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
+/*@
+ @ requires \valid(prev);
+ @ requires \valid(next);
+ @ ensures next->prev == prev;
+ @ ensures prev->next == next;
+ @ assigns next->prev,prev->next;
+ @*/
static inline void __td_list_del(struct td_list_head * prev, struct td_list_head * next)
{
next->prev = prev;
prev->next = next;
+ /*@ assert next->prev == prev; */
+ /*@ assert prev->next == next; */
}
/**
@@ -114,11 +145,23 @@ static inline void __td_list_del(struct td_list_head * prev, struct td_list_head
* Note: td_list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
+/*@
+ @ requires \valid(entry);
+ @ requires \valid(entry->prev);
+ @ requires \valid(entry->next);
+ @ ensures \old(entry->prev)->next == \old(entry->next);
+ @ ensures \old(entry->next)->prev == \old(entry->prev);
+ @ assigns \old(entry->prev)->next, \old(entry->next)->prev, entry->next, entry->prev;
+ @*/
static inline void td_list_del(struct td_list_head *entry)
{
__td_list_del(entry->prev, entry->next);
+ /*@ assert entry->prev->next == entry->next; */
+ /*@ assert entry->next->prev == entry->prev; */
entry->next = (struct td_list_head*)LIST_POISON1;
entry->prev = (struct td_list_head*)LIST_POISON2;
+ /*@ assert \at(entry->prev,Pre)->next == \at(entry->next,Pre); */
+ /*@ assert \at(entry->next,Pre)->prev == \at(entry->prev,Pre); */
}
/**
@@ -372,6 +415,12 @@ static inline void td_list_splice_init(struct td_list_head *list,
td_list_entry((pos)->member.prev, typeof(*(pos)), member)
+/*@
+ @ requires \valid(newe);
+ @ requires \valid(head);
+ @ requires \valid_function(compar);
+ @ requires separation: \separated(newe, head);
+ @*/
static inline void td_list_add_sorted(struct td_list_head *newe, struct td_list_head *head,
int (*compar)(const struct td_list_head *a, const struct td_list_head *b))
{
@@ -387,6 +436,12 @@ static inline void td_list_add_sorted(struct td_list_head *newe, struct td_list_
td_list_add_tail(newe, head);
}
+/*@
+ @ requires \valid(newe);
+ @ requires \valid(head);
+ @ requires \valid_function(compar);
+ @ requires separation: \separated(newe, head);
+ @*/
static inline int td_list_add_sorted_uniq(struct td_list_head *newe, struct td_list_head *head,
int (*compar)(const struct td_list_head *a, const struct td_list_head *b))
{
diff --git a/src/memmem.h b/src/memmem.h
index d738dba..caa6873 100644
--- a/src/memmem.h
+++ b/src/memmem.h
@@ -22,6 +22,11 @@
*/
+/*@
+ @ requires \valid_read((const char *)haystack+(0..haystack_len-1));
+ @ requires \valid_read((const char *)needle+(0..needle_len-1));
+ @ assigns \nothing;
+ @*/
static inline const void *td_memmem(const void *haystack, const unsigned int haystack_len, const void *needle, const unsigned int needle_len)
{
const char *begin;
@@ -37,6 +42,9 @@ static inline const void *td_memmem(const void *haystack, const unsigned int hay
if (haystack_len < needle_len)
return NULL;
+ /*@
+ @ loop assigns begin;
+ @*/
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0] &&
!memcmp ((const void *) &begin[1],
diff --git a/src/misc.c b/src/misc.c
index 8ac00d6..fb89ce8 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -172,7 +172,7 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834%28v=vs.85%29.a
}
#elif defined(DJGPP)
return "DOS";
-#elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
+#elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) && !defined(__FRAMAC__)
{
struct utsname Ver;
if(uname(&Ver)==0)
@@ -281,7 +281,7 @@ const char *get_compilation_date(void)
{
static char buffer[100] = {0x00};
#ifdef __DATE__
-#ifdef HAVE_STRPTIME
+#if defined(HAVE_STRPTIME) && !defined(__FRAMAC__)
struct tm tm;
memset(&tm,0,sizeof(tm));
if(strptime(__DATE__, "%b %d %Y", &tm)!=NULL)
diff --git a/src/partgpt.c b/src/partgpt.c
index 025439d..4ede59c 100644
--- a/src/partgpt.c
+++ b/src/partgpt.c
@@ -108,6 +108,7 @@ const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_MAC_BOOT, "Mac Boot" },
{ GPT_ENT_TYPE_MAC_LABEL, "Mac Label" },
{ GPT_ENT_TYPE_MAC_TV_RECOVERY, "Mac TV Recovery" },
+ { GPT_ENT_TYPE_APPLE_CORE_STORAGE, "Apple Core Storage" },
{ GPT_ENT_TYPE_SOLARIS_BOOT, "Solaris /boot" },
{ GPT_ENT_TYPE_SOLARIS_ROOT, "Solaris /" },
{ GPT_ENT_TYPE_SOLARIS_SWAP, "Solaris Swap" },
diff --git a/src/pdiskseln.c b/src/pdiskseln.c
index c00d65a..9779c8c 100644
--- a/src/pdiskseln.c
+++ b/src/pdiskseln.c
@@ -267,14 +267,15 @@ int do_curses_photorec(struct ph_param *params, struct ph_options *options, cons
static alloc_data_t list_search_space={
.list = TD_LIST_HEAD_INIT(list_search_space.list)
};
- if(params->cmd_device==NULL)
+ const int resume_session=(params->cmd_device!=NULL && strcmp(params->cmd_device,"resume")==0);
+ if(params->cmd_device==NULL || resume_session!=0)
{
char *saved_device=NULL;
char *saved_cmd=NULL;
session_load(&saved_device, &saved_cmd,&list_search_space);
if(saved_device!=NULL && saved_cmd!=NULL && !td_list_empty(&list_search_space.list)
#ifdef HAVE_NCURSES
- && ask_confirmation("Continue previous session ? (Y/N)")!=0
+ && ( resume_session!=0 || ask_confirmation("Continue previous session ? (Y/N)")!=0)
#endif
)
{
diff --git a/src/phbf.c b/src/phbf.c
index 523abe4..f5e1103 100644
--- a/src/phbf.c
+++ b/src/phbf.c
@@ -76,6 +76,7 @@
#define READ_SIZE 1024*512
extern file_check_list_t file_check_list;
extern uint64_t free_list_allocation_end;
+extern int need_to_stop;
typedef enum { BF_OK=0, BF_STOP=1, BF_EACCES=2, BF_ENOSPC=3, BF_FRAG_FOUND=4, BF_EOF=5, BF_ENOENT=6, BF_ERANGE=7} bf_status_t;
@@ -643,6 +644,8 @@ static bf_status_t photorec_bf_frag(struct ph_param *params, file_recovery_t *fi
ind_stop=photorec_progressbar(stdscr, testbf, params,
file_recovery->location.start, current_time);
#endif
+ if(need_to_stop!=0)
+ ind_stop=PSTATUS_STOP;
if(ind_stop!=PSTATUS_OK)
{
file_recovery->flags=0;
diff --git a/src/phbs.c b/src/phbs.c
index 9ce2d0d..dbc63d5 100644
--- a/src/phbs.c
+++ b/src/phbs.c
@@ -56,6 +56,7 @@
#define READ_SIZE 1024*512
extern const file_hint_t file_hint_tar;
extern file_check_list_t file_check_list;
+extern int need_to_stop;
static inline void file_recovery_cpy(file_recovery_t *dst, file_recovery_t *src)
{
@@ -203,6 +204,11 @@ pstatus_t photorec_find_blocksize(struct ph_param *params, const struct ph_optio
}
}
#endif
+ if(need_to_stop!=0)
+ {
+ log_info("PhotoRec has been stopped\n");
+ current_search_space=list_search_space;
+ }
}
} /* end while(current_search_space!=list_search_space) */
free(buffer_start);
diff --git a/src/phcli.c b/src/phcli.c
index c08c05c..952d13d 100644
--- a/src/phcli.c
+++ b/src/phcli.c
@@ -41,6 +41,7 @@
#include "poptions.h"
#include "phcli.h"
+extern int need_to_stop;
typedef enum { INIT_SPACE_WHOLE, INIT_SPACE_PREINIT, INIT_SPACE_EXT2_GROUP, INIT_SPACE_EXT2_INODE } init_mode_t;
static int spacerange_cmp(const struct td_list_head *a, const struct td_list_head *b)
@@ -136,6 +137,8 @@ int menu_photorec_cli(list_part_t *list_part, struct ph_param *params, struct ph
skip_comma_in_command(&params->cmd_run);
if(params->cmd_run[0]=='\0')
return 0;
+ if(need_to_stop!=0)
+ return 0;
if(check_command(&params->cmd_run,"search",6)==0)
{
if(mode_init_space==INIT_SPACE_EXT2_GROUP)
diff --git a/src/phmain.c b/src/phmain.c
index 0949376..cbba88e 100644
--- a/src/phmain.c
+++ b/src/phmain.c
@@ -77,6 +77,7 @@
#include "pdiskseln.h"
#include "dfxml.h"
+int need_to_stop=0;
extern file_enable_t list_file_enable[];
#ifdef HAVE_SIGACTION
@@ -87,12 +88,19 @@ static void sighup_hdlr(int sig)
{
if(sig == SIGINT)
log_critical("SIGINT detected! PhotoRec has been killed.\n");
- else
+ else if(sig == SIGHUP)
log_critical("SIGHUP detected! PhotoRec has been killed.\n");
+ else
+ log_critical("SIGTERM detected! PhotoRec has been killed.\n");
log_flush();
- action.sa_handler=SIG_DFL;
- sigaction(sig,&action,NULL);
- kill(0, sig);
+ if(need_to_stop==1)
+ {
+ action.sa_handler=SIG_DFL;
+ sigaction(sig,&action,NULL);
+ kill(0, sig);
+ return ;
+ }
+ need_to_stop=1;
}
#endif
@@ -156,6 +164,7 @@ int main( int argc, char **argv )
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGINT);
sigaddset(&action.sa_mask, SIGHUP);
+ sigaddset(&action.sa_mask, SIGTERM);
action.sa_handler = &sighup_hdlr;
action.sa_flags = 0;
if(sigaction(SIGINT, &action, NULL)==-1)
@@ -168,6 +177,11 @@ int main( int argc, char **argv )
printf("Error on SIGACTION call\n");
return -1;
}
+ if(sigaction(SIGTERM, &action, NULL)==-1)
+ {
+ printf("Error on SIGACTION call\n");
+ return -1;
+ }
#endif
printf("PhotoRec %s, Data Recovery Utility, %s\nChristophe GRENIER <grenier@cgsecurity.org>\nhttps://www.cgsecurity.org\n",VERSION,TESTDISKDATE);
for(i=1;i<argc;i++)
@@ -231,6 +245,10 @@ int main( int argc, char **argv )
}
else if((strcmp(argv[i],"/nosetlocale")==0) || (strcmp(argv[i],"-nosetlocale")==0))
run_setlocale=0;
+ else if(i+1 <= argc && strcmp(argv[i],"/cmd")==0 && strcmp(argv[i+1],"resume")==0)
+ {
+ params.cmd_device=argv[++i];
+ }
else if(strcmp(argv[i],"/cmd")==0)
{
if(i+2>=argc)
diff --git a/src/phrecn.c b/src/phrecn.c
index 5599078..972de61 100644
--- a/src/phrecn.c
+++ b/src/phrecn.c
@@ -85,6 +85,7 @@
#define DEFAULT_IMAGE_NAME "image_remaining.dd"
extern file_check_list_t file_check_list;
+extern int need_to_stop;
static int interface_cannot_create_file(void);
@@ -347,7 +348,8 @@ int photorec(struct ph_param *params, const struct ph_options *options, alloc_da
break;
}
session_save(list_search_space, params, options);
-
+ if(need_to_stop!=0)
+ ind_stop=PSTATUS_STOP;
switch(ind_stop)
{
case PSTATUS_ENOSPC:
@@ -400,7 +402,7 @@ int photorec(struct ph_param *params, const struct ph_options *options, alloc_da
{
log_flush();
#ifdef HAVE_NCURSES
- if(ask_confirmation("Answer Y to really Quit, N to resume the recovery")!=0)
+ if(need_to_stop!=0 || ask_confirmation("Answer Y to really Quit, N to resume the recovery")!=0)
#endif
params->status=STATUS_QUIT;
}
diff --git a/src/ppartseln.c b/src/ppartseln.c
index da3dced..2213d65 100644
--- a/src/ppartseln.c
+++ b/src/ppartseln.c
@@ -54,6 +54,7 @@
#include "addpartn.h"
#include "intrfn.h"
+extern int need_to_stop;
extern const arch_fnct_t arch_none;
#ifdef HAVE_NCURSES
@@ -137,7 +138,7 @@ void menu_photorec(struct ph_param *params, struct ph_options *options, alloc_da
current_element_num=0;
current_element=list_part;
}
- while(done==0)
+ while(done==0 && need_to_stop==0)
{ /* ncurses interface */
list_part_t *element;
unsigned int i;
diff --git a/src/psearchn.c b/src/psearchn.c
index 553d050..70e50de 100644
--- a/src/psearchn.c
+++ b/src/psearchn.c
@@ -70,6 +70,7 @@
#include "psearchn.h"
#include "photorec_check_header.h"
#define READ_SIZE 1024*512
+extern int need_to_stop;
pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
{
@@ -282,6 +283,8 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
#ifdef HAVE_NCURSES
ind_stop=photorec_progressbar(stdscr, params->pass, params, offset, current_time);
#endif
+ if(need_to_stop!=0)
+ ind_stop=PSTATUS_STOP;
params->offset=offset;
if(ind_stop!=PSTATUS_OK)
{