summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/askloc.c12
-rw-r--r--src/common.c12
-rw-r--r--src/common.h13
-rw-r--r--src/exfatp.c1
-rw-r--r--src/ext2p.c1
-rw-r--r--src/fatp.c1
-rw-r--r--src/file_ape.c9
-rw-r--r--src/file_bmp.c138
-rw-r--r--src/file_doc.c1808
-rw-r--r--src/file_evtx.c80
-rw-r--r--src/file_exe.c969
-rw-r--r--src/file_exr.c58
-rw-r--r--src/file_fp7.c2
-rw-r--r--src/file_gpg.c271
-rw-r--r--src/file_ico.c30
-rw-r--r--src/file_jpg.c2
-rw-r--r--src/file_list.c4
-rw-r--r--src/file_m2ts.c2
-rw-r--r--src/file_mov.c484
-rw-r--r--src/file_mp3.c446
-rw-r--r--src/file_orf.c2
-rw-r--r--src/file_pf.c118
-rw-r--r--src/file_raf.c14
-rw-r--r--src/file_rw2.c2
-rw-r--r--src/file_sig.c51
-rw-r--r--src/file_tiff.c56
-rw-r--r--src/file_tiff.h67
-rw-r--r--src/file_tiff_be.c300
-rw-r--r--src/file_tiff_le.c388
-rw-r--r--src/file_txt.c52
-rw-r--r--src/file_wdp.c2
-rw-r--r--src/file_x3f.c8
-rw-r--r--src/file_x3i.c1
-rw-r--r--src/file_zip.c590
-rw-r--r--src/filegen.c180
-rw-r--r--src/filegen.h154
-rw-r--r--src/godmode.c4
-rw-r--r--src/icon_ph.rc10
-rw-r--r--src/icon_qph.rc10
-rw-r--r--src/icon_tst.rc10
-rw-r--r--src/lang.h1
-rw-r--r--src/lang/qphotorec.ca.ts86
-rw-r--r--src/lang/qphotorec.cs.ts256
-rw-r--r--src/lang/qphotorec.es.ts133
-rw-r--r--src/lang/qphotorec.fr.ts86
-rw-r--r--src/lang/qphotorec.it.ts86
-rw-r--r--src/lang/qphotorec.ja.ts86
-rw-r--r--src/lang/qphotorec.pt.ts86
-rw-r--r--src/lang/qphotorec.ru.ts86
-rw-r--r--src/lang/qphotorec.tr.ts86
-rw-r--r--src/lang/qphotorec.zh_TW.ts86
-rw-r--r--src/ntfs.c6
-rw-r--r--src/ntfs.h2
-rw-r--r--src/ntfs_fix.c2
-rw-r--r--src/ntfsp.c1
-rw-r--r--src/partgpt.c18
-rw-r--r--src/partgptn.c3
-rw-r--r--src/partgptw.c3
-rw-r--r--src/parti386.c1
-rw-r--r--src/phbf.c2
-rw-r--r--src/phbs.c1
-rw-r--r--src/phmain.c6
-rw-r--r--src/photorec.c6
-rw-r--r--src/photorec.h7
-rw-r--r--src/photorec_check_header.h2
-rw-r--r--src/qphotorec_locale.qrc3
-rw-r--r--src/setdate.c2
-rw-r--r--src/sudo.c26
-rw-r--r--src/sudo.h2
-rw-r--r--src/testdisk.c8
-rw-r--r--src/tpartwr.c7
72 files changed, 5536 insertions, 2015 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 52ea960..a7c2a2b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -120,7 +120,9 @@ file_C = filegen.c \
file_emf.c \
file_ess.c \
file_evt.c \
+ file_evtx.c \
file_exe.c \
+ file_exr.c \
file_exs.c \
file_ext.c \
file_ext2.c \
@@ -369,6 +371,7 @@ photorec_ncurses_H = addpartn.h askloc.h chgarchn.h chgtype.h chgtypen.h fat_clu
QT_TS = \
lang/qphotorec.ca.ts \
+ lang/qphotorec.cs.ts \
lang/qphotorec.es.ts \
lang/qphotorec.fr.ts \
lang/qphotorec.it.ts \
diff --git a/src/askloc.c b/src/askloc.c
index 792ed2b..4ca1130 100644
--- a/src/askloc.c
+++ b/src/askloc.c
@@ -99,7 +99,7 @@ char *get_default_location(void)
static void set_parent_directory(char *dst_directory);
static void dir_aff_entry(WINDOW *window, file_info_t *file_info);
-static int aff_txt(int line, WINDOW *window, const char *_format, ...) __attribute__ ((format (printf, 3, 4)));
+static int aff_txt(const int line, WINDOW *window, const char *_format, ...) __attribute__ ((format (printf, 3, 4)));
#if defined(DJGPP) || defined(__OS2__)
void get_dos_drive_list(struct td_list_head *list);
@@ -229,7 +229,7 @@ char *ask_location(const char*msg, const char *src_dir, const char *dst_org)
break;
/* hide filename beginning by '.' except '.' and '..' */
if(dir_entrie->d_name[0]=='.' &&
- !dir_entrie->d_name[1]=='\0' &&
+ !(dir_entrie->d_name[1]=='\0') &&
!(dir_entrie->d_name[1]=='.' && dir_entrie->d_name[2]=='\0'))
continue;
if(strlen(dst_directory) + 1 + strlen(dir_entrie->d_name) + 1 <= sizeof(current_file)
@@ -519,7 +519,6 @@ char *ask_location(const char*msg, const char *src_dir, const char *dst_org)
file_info=td_list_entry(current_file, file_info_t, list);
if(current_file!=&dir_list.list &&
(LINUX_S_ISDIR(file_info->st_mode) || LINUX_S_ISLNK(file_info->st_mode)))
- if(current_file!=&dir_list.list)
{
if(strcmp(file_info->name, ".")==0)
{
@@ -583,13 +582,14 @@ static void dir_aff_entry(WINDOW *window, file_info_t *file_info)
wprintw(window, " %s %s", datestr, file_info->name);
}
-static int aff_txt(int line, WINDOW *window, const char *_format, ...)
+static int aff_txt(const int line, WINDOW *window, const char *_format, ...)
{
+ int next_line;
va_list ap;
va_start(ap,_format);
- line=vaff_txt(line, window, _format, ap);
+ next_line=vaff_txt(line, window, _format, ap);
va_end(ap);
- return line;
+ return next_line;
}
#endif
diff --git a/src/common.c b/src/common.c
index 3b1f45b..afcf387 100644
--- a/src/common.c
+++ b/src/common.c
@@ -61,7 +61,7 @@ void *MALLOC(size_t size)
/* Warning, memory leak checker must be posix_memalign/memalign aware, otherwise *
* reports may look strange. Aligned memory is required if the buffer is *
* used for read/write operation with a file opened with O_DIRECT */
-#if defined(HAVE_POSIX_MEMALIGN)
+#if defined(HAVE_POSIX_MEMALIGN) && !defined(__FRAMAC__)
if(size>=512)
{
if(posix_memalign(&res,4096,size)==0)
@@ -70,7 +70,7 @@ void *MALLOC(size_t size)
return res;
}
}
-#elif defined(HAVE_MEMALIGN)
+#elif defined(HAVE_MEMALIGN) && !defined(__FRAMAC__)
if(size>=512)
{
if((res=memalign(4096, size))!=NULL)
@@ -226,12 +226,12 @@ char* strip_dup(char* str)
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
+time_t date_dos2unix(const unsigned short f_time, const unsigned short f_date)
{
- static const int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ static const unsigned int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
/* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
- int month,year,secs;
+ unsigned int month,year,secs;
/* first subtract and mask after that... Otherwise, if
f_date == 0, bad things happen */
@@ -247,7 +247,7 @@ int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
void set_secwest(void)
{
const time_t t = time(NULL);
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(__FRAMAC__)
const struct tm *tmptr = localtime(&t);
#else
struct tm tmp;
diff --git a/src/common.h b/src/common.h
index c031222..8a5e5ea 100644
--- a/src/common.h
+++ b/src/common.h
@@ -122,6 +122,9 @@ struct efi_guid_s
((const efi_guid_t){le32(0x00000000),le16(0x0000),le16(0x0000),0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}})
#define GPT_ENT_TYPE_EFI \
((const efi_guid_t){le32(0xc12a7328),le16(0xf81f),le16(0x11d2),0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}})
+/* Extended Boot Partition */
+#define GPT_ENT_TYPE_EBP \
+ ((const efi_guid_t){le32(0xbc13c2ff),le16(0x59e6),le16(0x4262),0xa3,0x52,{0xb2,0x75,0xfd,0x6f,0x71,0x72}})
#define GPT_ENT_TYPE_MBR \
((const efi_guid_t){le32(0x024dee41),le16(0x33e7),le16(0x11d3),0x9d,0x69,{0x00,0x08,0xc7,0x81,0xf3,0x9f}})
#define GPT_ENT_TYPE_FREEBSD \
@@ -174,6 +177,8 @@ struct efi_guid_s
#define GPT_ENT_TYPE_HPUX_SERVICE \
((const efi_guid_t){le32(0xe2a1e728),le16(0x32e3),le16(0x11d6),0xa6,0x82,{0x7b,0x03,0xa0,0x00,0x00,0x00}})
+#define GPT_ENT_TYPE_MAC_AFS \
+ ((const efi_guid_t){le32(0x7c3457ef),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
#define GPT_ENT_TYPE_MAC_HFS \
((const efi_guid_t){le32(0x48465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
#define GPT_ENT_TYPE_MAC_UFS \
@@ -433,12 +438,18 @@ struct my_data_struct
uint64_t offset;
};
+/*@
+ @ requires size > 0;
+ @ ensures \valid(((char *)\result)+(0..size-1));
+ @ ensures zero_initialization: \subset(((char *)\result)[0..size-1], {0});
+ @*/
void *MALLOC(size_t size);
+
unsigned int up2power(const unsigned int number);
void set_part_name(partition_t *partition, const char *src, const unsigned int max_size);
void set_part_name_chomp(partition_t *partition, const unsigned char *src, const unsigned int max_size);
char* strip_dup(char* str);
-int date_dos2unix(const unsigned short f_time,const unsigned short f_date);
+time_t date_dos2unix(const unsigned short f_time,const unsigned short f_date);
void set_secwest(void);
time_t td_ntfs2utc (int64_t ntfstime);
#ifndef BSD_MAXPARTITIONS
diff --git a/src/exfatp.c b/src/exfatp.c
index 00374ac..06c24ec 100644
--- a/src/exfatp.c
+++ b/src/exfatp.c
@@ -31,6 +31,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "exfatp.h"
#include "exfat.h"
#include "log.h"
diff --git a/src/ext2p.c b/src/ext2p.c
index 84b2ca6..6cbb0f7 100644
--- a/src/ext2p.c
+++ b/src/ext2p.c
@@ -33,6 +33,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "intrf.h"
#include "dir.h"
#ifdef HAVE_EXT2FS_EXT2_FS_H
diff --git a/src/fatp.c b/src/fatp.c
index af33ec3..81fd62f 100644
--- a/src/fatp.c
+++ b/src/fatp.c
@@ -31,6 +31,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#include "fatp.h"
#include "fat.h"
#include "fat_common.h"
diff --git a/src/file_ape.c b/src/file_ape.c
index 3391a39..c013880 100644
--- a/src/file_ape.c
+++ b/src/file_ape.c
@@ -31,7 +31,6 @@
#include "common.h"
static void register_header_check_ape(file_stat_t *file_stat);
-static int header_check_ape(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_ape= {
.extension="ape",
@@ -106,7 +105,6 @@ static int header_check_ape(const unsigned char *buffer, const unsigned int buff
if(le16(ape->nVersion)>=3980)
{
const struct APE_DESCRIPTOR *descr=(const struct APE_DESCRIPTOR*)buffer;
- const struct APE_HEADER *apeh=(const struct APE_HEADER*)&buffer[le32(descr->nDescriptorBytes)];
if(le32(descr->nDescriptorBytes) < sizeof(struct APE_DESCRIPTOR))
return 0;
if(le32(descr->nHeaderDataBytes) > 0 && le32(descr->nHeaderDataBytes) < sizeof(struct APE_HEADER))
@@ -115,8 +113,11 @@ static int header_check_ape(const unsigned char *buffer, const unsigned int buff
return 0;
if(le32(descr->nDescriptorBytes) + sizeof(struct APE_HEADER) >= buffer_size)
return 0;
- if(le16(apeh->nChannels)<1 || le16(apeh->nChannels)>2)
- return 0;
+ {
+ const struct APE_HEADER *apeh=(const struct APE_HEADER*)&buffer[le32(descr->nDescriptorBytes)];
+ if(le16(apeh->nChannels)<1 || le16(apeh->nChannels)>2)
+ return 0;
+ }
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_ape.extension;
return 1;
diff --git a/src/file_bmp.c b/src/file_bmp.c
index f20326a..42209d2 100644
--- a/src/file_bmp.c
+++ b/src/file_bmp.c
@@ -30,9 +30,11 @@
#include "types.h"
#include "filegen.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_bmp(file_stat_t *file_stat);
-static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_bmp= {
.extension="bmp",
@@ -45,28 +47,45 @@ const file_hint_t file_hint_bmp= {
static const unsigned char bmp_header[2]= {'B','M'};
-static void register_header_check_bmp(file_stat_t *file_stat)
-{
- register_header_check(0, bmp_header,sizeof(bmp_header), &header_check_bmp, file_stat);
-}
-
struct bmp_header
{
uint16_t magic;
uint32_t size;
uint32_t reserved;
uint32_t offset;
+ uint32_t hdr_size;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires buffer_size >= 18;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_bmp.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= 65);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 65);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @*/
static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const struct bmp_header *bm=(const struct bmp_header *)buffer;
- if(buffer[0]=='B' && buffer[1]=='M' && bm->reserved==0 &&
+ if(buffer[0]!='B' || buffer[1]!='M')
+ return 0;
+ if(bm->reserved!=0)
+ return 0;
+ if(
(buffer[14]==12 || buffer[14]==64 || buffer[14]==40 || buffer[14]==52 ||
buffer[14]==56 || buffer[14]==108 || buffer[14]==124) &&
buffer[15]==0 && buffer[16]==0 && buffer[17]==0 &&
le32(bm->offset) < le32(bm->size) &&
- le32(bm->size) >= 65)
+ le32(bm->size) >= 65 &&
+ le32(bm->hdr_size) < le32(bm->size))
{
/* See http://en.wikipedia.org/wiki/BMP_file_format */
reset_file_recovery(file_recovery_new);
@@ -75,7 +94,110 @@ static int header_check_bmp(const unsigned char *buffer, const unsigned int buff
file_recovery_new->calculated_file_size=(uint64_t)le32(bm->size);
file_recovery_new->data_check=&data_check_size;
file_recovery_new->file_check=&file_check_size;
+ /*@ assert file_recovery_new->extension == file_hint_bmp.extension; */
+ /*@ assert file_recovery_new->calculated_file_size >= 65; */
+ /*@ assert file_recovery_new->file_size == 0; */
+ /*@ assert file_recovery_new->min_filesize == 65; */
+ /*@ assert file_recovery_new->data_check == &data_check_size; */
+ /*@ assert file_recovery_new->file_check == &file_check_size; */
return 1;
}
return 0;
}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_bmp(file_stat_t *file_stat)
+{
+ register_header_check(0, bmp_header,sizeof(bmp_header), &header_check_bmp, file_stat);
+}
+
+#if defined(MAIN_bmp)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.bmp";
+ unsigned char buffer[BLOCKSIZE];
+ int res;
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_bmp;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_bmp(&file_stats);
+ if(header_check_bmp(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.extension == file_hint_bmp.extension; */
+ /*@ assert file_recovery_new.calculated_file_size >= 65; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.min_filesize == 65; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ {
+ file_recovery_t file_recovery_new2;
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_bmp(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_doc.c b/src/file_doc.c
index 4451796..4c28452 100644
--- a/src/file_doc.c
+++ b/src/file_doc.c
@@ -39,13 +39,11 @@
#include "memmem.h"
#include "setdate.h"
#include "file_doc.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_doc(file_stat_t *file_stat);
-static void file_check_doc(file_recovery_t *file_recovery);
-static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-static void file_rename_doc(file_recovery_t *file_recovery);
-static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset);
-static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries, const uint64_t offset);
const file_hint_t file_hint_doc= {
.extension="doc",
@@ -56,6 +54,45 @@ const file_hint_t file_hint_doc= {
.register_header_check=&register_header_check_doc
};
+static const char *extension_albm="albm";
+static const char *extension_amb="amb";
+static const char *extension_apr="apr";
+static const char *extension_camrec="camrec";
+static const char *extension_db="db";
+static const char *extension_dgn="dgn";
+static const char *extension_emb="emb";
+static const char *extension_et="et";
+static const char *extension_fla="fla";
+static const char *extension_ipt="ipt";
+static const char *extension_jnb="jnb";
+static const char *extension_max="max";
+static const char *extension_mdb="mdb";
+static const char *extension_mws="mws";
+static const char *extension_msg="msg";
+static const char *extension_p65="p65";
+static const char *extension_ppt="ppt";
+static const char *extension_psmodel="psmodel";
+static const char *extension_pub="pub";
+static const char *extension_qbb="qbb";
+static const char *extension_qdf_backup="qdf-backup";
+static const char *extension_qpw="qpw";
+static const char *extension_rvt="rvt";
+static const char *extension_sda="sda";
+static const char *extension_sdc="sdc";
+static const char *extension_sdd="sdd";
+static const char *extension_sdw="sdw";
+#ifdef DJGPP
+static const char *extension_sldprt="sld";
+#else
+static const char *extension_sldprt="sldprt";
+#endif
+static const char *extension_snt="snt";
+static const char *extension_tcw="tcw";
+static const char *extension_vsd="vsd";
+static const char *extension_wps="wps";
+static const char *extension_xlr="xlr";
+static const char *extension_xls="xls";
+static const char *extension_wdb="wdb";
const char WilcomDesignInformationDDD[56]=
{
@@ -68,6 +105,330 @@ const char WilcomDesignInformationDDD[56]=
'D', '\0', 'D', '\0', 'D', '\0', '\0', '\0'
};
+/*@
+ @ requires \valid(IN);
+ @ requires (9 == uSectorShift) || (12 == uSectorShift);
+ @ requires \valid( buf + (0 .. (1<<uSectorShift)-1));
+ @ ensures \result == -1 || \result == 0;
+ @*/
+/* TODO: ensures \result == 0 ==> \initialized(buf + (0 .. (1<<uSectorShift)-1)); */
+static int OLE_read_block(FILE *IN, unsigned char *buf, const unsigned int uSectorShift, const unsigned int block, const uint64_t offset)
+{
+ const size_t size=1<<uSectorShift;
+ if(block==0xFFFFFFFF || block==0xFFFFFFFE)
+ return -1;
+ if(my_fseek(IN, offset + ((uint64_t)(1+block)<<uSectorShift), SEEK_SET) < 0)
+ {
+ return -1;
+ }
+ if(fread(buf, size, 1, IN)!=1)
+ {
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buf, size);
+#endif
+ /* TODO: assert \initialized((char *)buf + (0 .. size-1)); */
+ return 0;
+}
+
+/*@
+ @ requires \valid_read(dir_entry);
+ @ ensures \result == \null || valid_read_string(\result);
+ @*/
+static const char *entry2ext(const struct OLE_DIR *dir_entry)
+{
+ switch(le16(dir_entry->namsiz))
+ {
+ case 10:
+ if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
+ return extension_qdf_backup;
+ break;
+ case 12:
+ /* 3ds max */
+ if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
+ return extension_max;
+ /* Licom AlphaCAM */
+ else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
+ return extension_amb;
+ break;
+ case 18:
+ /* Microsoft Works .wps */
+ if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
+ return extension_wps;
+ break;
+ case 20:
+ /* Page Maker */
+ if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0)
+ return extension_p65;
+ break;
+ case 22:
+ /* SigmaPlot .jnb */
+ if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0\0", 22)==0)
+ return extension_jnb;
+ /* Autodesk Inventor part ipt or iam file */
+ if(memcmp(dir_entry->name, "R\0S\0e\0S\0t\0o\0r\0a\0g\0e\0\0\0", 22)==0)
+ return extension_ipt;
+ break;
+ case 24:
+ /* HP Photosmart Photo Printing Album */
+ if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0)
+ return extension_albm;
+ /* Lotus Approch */
+ if(memcmp(dir_entry->name,"A\0p\0p\0r\0o\0a\0c\0h\0D\0o\0c\0\0\0",24)==0)
+ return extension_apr;
+ break;
+ case 28:
+ /* Microsoft Works Spreadsheet or Chart */
+ if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0)
+ return extension_xlr;
+ /* Visio */
+ else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0)
+ return extension_vsd;
+ /* SolidWorks */
+ else if(memcmp(&dir_entry->name,"s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0",28)==0)
+ return extension_sldprt;
+ break;
+ case 32:
+ if(memcmp(dir_entry->name, "m\0a\0n\0i\0f\0e\0s\0t\0.\0c\0a\0m\0x\0m\0l\0\0\0",32)==0)
+ return extension_camrec;
+ /* Revit */
+ if(memcmp(dir_entry->name, "R\0e\0v\0i\0t\0P\0r\0e\0v\0i\0e\0w\0004\0.\0000\0\0", 32)==0)
+ return extension_rvt;
+ break;
+ case 34:
+ if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0)
+ return extension_sdc;
+ break;
+ case 36:
+ if(memcmp(dir_entry->name, "f\0i\0l\0e\0_\0C\0O\0M\0P\0A\0N\0Y\0_\0F\0I\0L\0E\0\0\0", 36)==0)
+ return extension_qbb;
+ break;
+ case 38:
+ /* Quattro Pro spreadsheet */
+ if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0)
+ return extension_qpw;
+ else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0)
+ return extension_sdw;
+ break;
+ case 40:
+ if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
+ return extension_ppt;
+ /* Outlook */
+ else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0)
+ return extension_msg;
+ break;
+ case 46:
+ if(memcmp(dir_entry->name,
+ "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0)
+ {
+ return extension_sldprt;
+ }
+ break;
+ case 56:
+ /* Wilcom ES Software */
+ if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
+ return extension_emb;
+ break;
+ }
+ return NULL;
+}
+
+/*@
+ @ requires buffer_size >= sizeof(struct OLE_HDR);
+ @ requires \valid_read((char *)header + (0 .. buffer_size-1));
+ @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift);
+ @ requires le32(header->num_FAT_blocks)>0;
+ @ requires 0 <= le32(header->num_extra_FAT_blocks) <= 50;
+ @ ensures \result == \null || valid_read_string(\result);
+ @*/
+static const char *ole_get_file_extension(const struct OLE_HDR *header, const unsigned int buffer_size)
+{
+ const unsigned char *buffer=(const unsigned char *)header;
+ unsigned int fat_entries;
+ unsigned int block;
+ unsigned int i;
+ const unsigned int uSectorShift=le16(header->uSectorShift);
+ unsigned int fat_size;
+ if(buffer_size<512)
+ return NULL;
+ /*@ assert buffer_size >= 512; */
+ fat_size=(le32(header->num_FAT_blocks) << uSectorShift);
+ fat_entries=fat_size/4;
+ /* FFFFFFFE = ENDOFCHAIN
+ * Use a loop count i to avoid endless loop */
+#ifdef DEBUG_OLE
+ log_info("ole_get_file_extension root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
+#endif
+ for(block=le32(header->root_start_block), i=0;
+ block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
+ i++)
+ {
+ const uint64_t offset_root_dir=((uint64_t)1+block)<<uSectorShift;
+#ifdef DEBUG_OLE
+ log_info("Root Directory block=%u (0x%x)\n", block, block);
+#endif
+ if(offset_root_dir>buffer_size-512)
+ return NULL;
+ /*@ assert offset_root_dir + 512 <= buffer_size; */
+ {
+ unsigned int sid;
+ const struct OLE_DIR *dir_entries=(const struct OLE_DIR *)&buffer[offset_root_dir];
+ /*@ assert \valid_read((char *)dir_entries + (0 .. 512-1)); */
+ /*@ assert \valid_read(dir_entries + (0 .. 512/sizeof(struct OLE_DIR)-1)); */
+ const char *ext=NULL;
+ int is_db=0;
+ for(sid=0;
+ sid<512/sizeof(struct OLE_DIR);
+ sid++)
+ {
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
+ if(dir_entry->type==NO_ENTRY)
+ break;
+#ifdef DEBUG_OLE
+ {
+ unsigned int j;
+ for(j=0;j<64 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
+ {
+ log_info("%c",dir_entry->name[j]);
+ }
+ for(;j<64;j+=2)
+ log_info(" ");
+ log_info(" namsiz=%u type %u", le16(dir_entry->namsiz), dir_entry->type);
+ log_info(" Flags=%s", (dir_entry->bflags==0?"Red ":"Black"));
+ log_info(" sector %u (%u bytes)\n",
+ (unsigned int)le32(dir_entry->start_block),
+ (unsigned int)le32(dir_entry->size));
+ }
+#endif
+ {
+ const char *tmp=entry2ext(dir_entry);
+ /*@ assert tmp == \null || valid_read_string(tmp); */
+ if(tmp!=NULL)
+ return tmp;
+ }
+ 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 ||
+ memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0", 14)==0))
+ is_db=2;
+ switch(le16(dir_entry->namsiz))
+ {
+ case 18:
+ /* MS Excel
+ * Note: Microsoft Works Spreadsheet contains the same signature */
+ if(memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
+ ext=extension_xls;
+ break;
+ case 36:
+ /* sda=StarDraw, sdd=StarImpress */
+ if(memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
+ return extension_sda;
+ break;
+ }
+ if(sid==1 && memcmp(&dir_entry->name, "D\0g\0n", 6)==0)
+ return extension_dgn;
+ }
+ if(ext!=NULL)
+ {
+ /*@ assert ext == extension_xls; */
+ return ext;
+ }
+ /* Thumbs.db */
+ if(is_db==2)
+ return extension_db;
+ }
+ {
+ const uint32_t *fati=(const uint32_t *)(header+1);
+ const uint64_t fat_offset=((uint64_t)1+le32(fati[0])) << uSectorShift;
+ unsigned int fat_test_size;
+ const uint32_t *val32_ptr;
+ if(fat_offset >= buffer_size)
+ return NULL;
+ /*@ assert 0 < fat_offset < buffer_size; */
+ fat_test_size=fat_offset+block*4;
+ if(fat_test_size + 4 > buffer_size)
+ return NULL;
+ /*@ assert fat_test_size + 4 <= buffer_size; */
+ val32_ptr=(const uint32_t *)&buffer[fat_test_size];
+ block=le32(*val32_ptr);
+ }
+ }
+#ifdef DEBUG_OLE
+ log_info("Root Directory end\n");
+#endif
+ return NULL;
+}
+
+/*@
+ @ requires \valid(IN);
+ @ requires \valid_read(header);
+ @ requires le32(header->num_FAT_blocks) > 0;
+ @ requires 0 <= le32(header->num_extra_FAT_blocks)<= 50;
+ @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift);
+ @ requires le32(header->num_FAT_blocks) <= 109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))/4-1);
+ @ ensures \result==\null || \valid_read((const char *)\result + ( 0 .. (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))-1));
+ @*/
+static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
+{
+ uint32_t *fat;
+ uint32_t *dif;
+ const unsigned int uSectorShift=le16(header->uSectorShift);
+ const unsigned int num_FAT_blocks=le32(header->num_FAT_blocks);
+ /*@ assert uSectorShift == le16(header->uSectorShift); */
+ /*@ assert num_FAT_blocks==le32(header->num_FAT_blocks); */
+ /*@ assert num_FAT_blocks <= 109+le32(header->num_extra_FAT_blocks)*((1<<uSectorShift)/4-1); */
+ const unsigned int dif_size=109*4+(le32(header->num_extra_FAT_blocks)<<uSectorShift);
+ /*@ assert 109*4 <= dif_size <= 109*4+(50<<12); */
+#ifdef __FRAMAC__
+ dif=(uint32_t*)MALLOC(109*4+(50<<12));
+#else
+ dif=(uint32_t*)MALLOC(dif_size);
+#endif
+ /*@ assert \valid((char *)dif+(0..dif_size-1)); */
+ memcpy(dif,(header+1),109*4);
+ if(le32(header->num_extra_FAT_blocks)>0)
+ { /* Load DIF*/
+ unsigned long int i;
+ for(i=0; i<le32(header->num_extra_FAT_blocks); i++)
+ {
+ const unsigned int block=(i==0 ? le32(header->FAT_next_block) : le32(dif[109+i*(((1<<uSectorShift)/4)-1)]));
+ unsigned char *data=(unsigned char*)&dif[109]+i*((1<<uSectorShift)-4);
+ if(OLE_read_block(IN, data, uSectorShift, block, offset) < 0)
+ {
+ free(dif);
+ return NULL;
+ }
+ }
+ }
+#ifdef __FRAMAC__
+ /*@ assert (109+50*((1<<12)/4-1))<<12 >= num_FAT_blocks<<uSectorShift; */
+ fat=(uint32_t*)MALLOC((109+50*((1<<12)/4-1))<<12);
+#else
+ fat=(uint32_t*)MALLOC(num_FAT_blocks<<uSectorShift);
+#endif
+ /*@ assert \valid((char *)fat + (0 .. (num_FAT_blocks<<uSectorShift)-1)); */
+ { /* Load FAT */
+ unsigned int j;
+ for(j=0; j<num_FAT_blocks; j++)
+ {
+ if(OLE_read_block(IN, (unsigned char*)fat + (j<<uSectorShift), uSectorShift, le32(dif[j]), offset)<0)
+ {
+ free(dif);
+ free(fat);
+ return NULL;
+ }
+ }
+ }
+ free(dif);
+ return fat;
+}
+
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @*/
void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
{
unsigned char buffer_header[512];
@@ -77,22 +438,36 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
unsigned int freesect_count=0;
const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
const uint64_t doc_file_size_org=file_recovery->file_size;
+ unsigned int uSectorShift;
+ unsigned int num_FAT_blocks;
file_recovery->file_size=offset;
/*reads first sector including OLE header */
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 ||
fread(&buffer_header, sizeof(buffer_header), 1, file_recovery->handle) != 1)
return ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer_header, sizeof(buffer_header));
+#endif
+ uSectorShift=le16(header->uSectorShift);
+ num_FAT_blocks=le32(header->num_FAT_blocks);
+ /* Sanity check */
+ if( uSectorShift != 9 && uSectorShift != 12)
+ return ;
+ /*@ assert 9 == uSectorShift || 12 == uSectorShift; */
#ifdef DEBUG_OLE
log_info("file_check_doc %s\n", file_recovery->filename);
- log_trace("sector size %u\n",1<<le16(header->uSectorShift));
- log_trace("num_FAT_blocks %u\n",le32(header->num_FAT_blocks));
+ log_trace("sector size %u\n",1<<uSectorShift);
+ log_trace("num_FAT_blocks %u\n",num_FAT_blocks);
log_trace("num_extra_FAT_blocks %u\n",le32(header->num_extra_FAT_blocks));
#endif
- /* Sanity check */
- if(le32(header->num_FAT_blocks)==0 ||
- le32(header->num_extra_FAT_blocks)>50 ||
- le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
+ if(num_FAT_blocks==0 ||
+ le32(header->num_extra_FAT_blocks)>50)
+ return ;
+ /*@ assert num_FAT_blocks > 0; */
+ /*@ assert 0 <= le32(header->num_extra_FAT_blocks) <= 50; */
+ if(num_FAT_blocks > 109+le32(header->num_extra_FAT_blocks)*((1<<uSectorShift)/4-1))
return ;
+ /*@ assert num_FAT_blocks <= 109+le32(header->num_extra_FAT_blocks)*((1<<uSectorShift)/4-1); */
if((fat=OLE_load_FAT(file_recovery->handle, header, offset))==NULL)
{
#ifdef DEBUG_OLE
@@ -101,18 +476,34 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
return ;
}
/* Search how many entries are not used at the end of the FAT */
- for(i=(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-1;
- i>0 && le32(fat[i])==0xFFFFFFFF;
- i--)
- freesect_count++;
- doc_file_size=offset + ((1+(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-freesect_count)<<le16(header->uSectorShift));
+ {
+ const unsigned int val_max=(num_FAT_blocks<<uSectorShift)/4-1;
+ /*@ assert \valid_read((char *)fat + ( 0 .. val_max)); */
+ /*@
+ @ loop invariant 0 <= freesect_count <= val_max;
+ @ loop assigns freesect_count;
+ @ loop variant val_max - freesect_count;
+ @*/
+ for(freesect_count=0; freesect_count < val_max; freesect_count++)
+ {
+ const unsigned j=val_max-freesect_count;
+ /*@ assert 0 <= j <= val_max; */
+ if(fat[j]!=0xFFFFFFFF)
+ break;
+ }
+ }
+ /*@ assert 0 <= freesect_count <= (num_FAT_blocks<<uSectorShift)/4-1; */
+ {
+ const unsigned int block=(num_FAT_blocks<<uSectorShift)/4-freesect_count;
+ doc_file_size=offset + (((uint64_t)1+block)<<uSectorShift);
+ }
if(doc_file_size > doc_file_size_org)
{
#ifdef DEBUG_OLE
log_info("doc_file_size=%llu + (1+(%u<<%u)/4-%u)<<%u\n",
(unsigned long long)offset,
- le32(header->num_FAT_blocks), le16(header->uSectorShift),
- freesect_count, le16(header->uSectorShift));
+ num_FAT_blocks, uSectorShift,
+ freesect_count, uSectorShift);
log_info("doc_file_size %llu > doc_file_size_org %llu\n",
(unsigned long long)doc_file_size, (unsigned long long)doc_file_size_org);
#endif
@@ -124,9 +515,9 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
#endif
{
unsigned int block;
- const unsigned int fat_entries=(le32(header->num_FAT_blocks)==0 ?
+ const unsigned int fat_entries=(num_FAT_blocks==0 ?
109:
- (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
+ (num_FAT_blocks<<uSectorShift)/4);
#ifdef DEBUG_OLE
log_info("root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
@@ -145,19 +536,15 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
free(fat);
return ;
}
- if(my_fseek(file_recovery->handle, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET)<0)
- {
-#ifdef DEBUG_OLE
- log_info("fseek failed\n");
+#ifdef __FRAMAC__
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<12);
+#else
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<uSectorShift);
#endif
- free(fat);
- return ;
- }
- dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
- if(fread(dir_entries, (1<<le16(header->uSectorShift)), 1, file_recovery->handle)!=1)
+ if(OLE_read_block(file_recovery->handle, (unsigned char *)dir_entries, uSectorShift, block, offset)<0)
{
#ifdef DEBUG_OLE
- log_info("fread failed\n");
+ log_info("OLE_read_block failed\n");
#endif
free(dir_entries);
free(fat);
@@ -165,12 +552,14 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
}
{
unsigned int sid;
- struct OLE_DIR *dir_entry;
- for(sid=0, dir_entry=dir_entries;
- sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
- sid++,dir_entry++)
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
{
- if(offset +
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
+ if(dir_entry->type==NO_ENTRY)
+ break;
+ if(offset +
le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 &&
((le32(dir_entry->size) >= le32(header->miniSectorCutoff)
&& le32(dir_entry->start_block) > fat_entries) ||
@@ -192,388 +581,47 @@ void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
file_recovery->file_size=doc_file_size;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @*/
static void file_check_doc(file_recovery_t *file_recovery)
{
file_check_doc_aux(file_recovery, 0);
}
-static const char *ole_get_file_extension(const unsigned char *buffer, const unsigned int buffer_size)
-{
- const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
- const uint32_t *fat;
- unsigned int fat_entries;
- unsigned int block;
- unsigned int i;
- if(buffer_size<512)
- return NULL;
- if(le32(header->num_FAT_blocks)==0)
- {
- fat=(const uint32_t *)(header+1);
- fat_entries=109;
- }
- else
- {
- const uint32_t *fati=(const uint32_t *)(header+1);
- const unsigned int fat_offset=(1+le32(fati[0])) << le16(header->uSectorShift);
- fat=(const uint32_t *)&buffer[fat_offset];
- fat_entries=(le32(header->num_FAT_blocks) << le16(header->uSectorShift))/4;
- if(fat_offset>buffer_size)
- fat_entries=0;
- else if(fat_offset+fat_entries>buffer_size)
- fat_entries=buffer_size-fat_offset;
- }
- /* FFFFFFFE = ENDOFCHAIN
- * Use a loop count i to avoid endless loop */
-#ifdef DEBUG_OLE
- log_info("ole_get_file_extension root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
-#endif
- for(block=le32(header->root_start_block), i=0;
- block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
- block=le32(fat[block]), i++)
- {
- const unsigned int offset_root_dir=(1+block)<<le16(header->uSectorShift);
-#ifdef DEBUG_OLE
- log_info("Root Directory block=%u (0x%x)\n", block, block);
-#endif
- if(offset_root_dir>buffer_size-512)
- return NULL;
- {
- unsigned int sid;
- const struct OLE_DIR *dir_entry;
- const char *ext=NULL;
- int is_db=0;
- for(sid=0,dir_entry=(const struct OLE_DIR *)&buffer[offset_root_dir];
- sid<512/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
- sid++,dir_entry++)
- {
-#ifdef DEBUG_OLE
- unsigned int j;
- for(j=0;j<64 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
- {
- log_info("%c",dir_entry->name[j]);
- }
- for(;j<64;j+=2)
- log_info(" ");
- log_info(" namsiz=%u type %u", le16(dir_entry->namsiz), dir_entry->type);
- log_info(" Flags=%s", (dir_entry->bflags==0?"Red ":"Black"));
- log_info(" sector %u (%u bytes)\n",
- (unsigned int)le32(dir_entry->start_block),
- (unsigned int)le32(dir_entry->size));
-#endif
- if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0)
- is_db++;
- else if(sid==2 && (memcmp(&dir_entry->name, "2\0\0\0", 4)==0 ||
- memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0", 14)==0))
- is_db++;
- switch(le16(dir_entry->namsiz))
- {
- case 10:
- if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
- return "qdf-backup";
- break;
- case 12:
- /* 3ds max */
- if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
- return "max";
- /* Licom AlphaCAM */
- else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
- return "amb";
- break;
- case 18:
- /* MS Excel
- * Note: Microsoft Works Spreadsheet contains the same signature */
- if(memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
- ext="xls";
- /* Microsoft Works .wps */
- else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
- return "wps";
- break;
- case 20:
- /* Page Maker */
- if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0)
- return "p65";
- break;
- case 22:
- /* SigmaPlot .jnb */
- if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0\0", 22)==0)
- return "jnb";
- /* Autodesk Inventor part ipt or iam file */
- if(memcmp(dir_entry->name, "R\0S\0e\0S\0t\0o\0r\0a\0g\0e\0\0\0", 22)==0)
- return "ipt";
- break;
- case 24:
- /* HP Photosmart Photo Printing Album */
- if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0)
- return "albm";
- /* Lotus Approch */
- if(memcmp(dir_entry->name,"A\0p\0p\0r\0o\0a\0c\0h\0D\0o\0c\0\0\0",24)==0)
- return "apr";
- break;
- case 28:
- /* Microsoft Works Spreadsheet or Chart */
- if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0)
- return "xlr";
- /* Visio */
- else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0)
- return "vsd";
- /* SolidWorks */
- else if(memcmp(&dir_entry->name,"s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0",28)==0)
- {
-#ifdef DJGPP
- return "sld";
-#else
- return "sldprt";
-#endif
- }
- break;
- case 32:
- /* Revit */
- if(memcmp(dir_entry->name, "R\0e\0v\0i\0t\0P\0r\0e\0v\0i\0e\0w\0004\0.\0000\0\0", 32)==0)
- return "rvt";
- break;
- case 34:
- if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0)
- return "sdc";
- break;
- case 36:
- if(memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
- return "sda";
- break;
- case 38:
- /* Quattro Pro spreadsheet */
- if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0)
- return "qpw";
- else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0)
- return "sdw";
- break;
- case 40:
- if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
- return "ppt";
- /* Outlook */
- else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0)
- return "msg";
- break;
- case 46:
- if(memcmp(dir_entry->name,
- "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0)
- {
-#ifdef DJGPP
- return "sld";
-#else
- return "sldprt";
-#endif
- }
- break;
- case 56:
- /* Wilcom ES Software */
- if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
- return "emb";
- break;
- }
- if(sid==1 && memcmp(&dir_entry->name, "D\0g\0n", 6)==0)
- return "dgn";
- }
- if(ext!=NULL)
- return ext;
- /* Thumbs.db */
- if(is_db==2)
- return "db";
- }
- }
-#ifdef DEBUG_OLE
- log_info("Root Directory end\n");
-#endif
- return NULL;
-}
-
-static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
-{
- const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
- /* Check for Little Endian */
- if(le16(header->uByteOrder)!=0xFFFE)
- return 0;
- if(le16(header->uDllVersion)!=3 && le16(header->uDllVersion)!=4)
- return 0;
- if(le16(header->reserved)!=0 || le32(header->reserved1)!=0)
- return 0;
- if(le16(header->uMiniSectorShift)!=6)
- return 0;
- if(le16(header->uDllVersion)==3 && le16(header->uSectorShift)!=9)
- return 0;
- /* max and qbb file have uSectorShift=12 */
- if(le16(header->uDllVersion)==4 && le16(header->uSectorShift)!=12)
- return 0;
- if(le16(header->uDllVersion)==3 && le32(header->csectDir)!=0)
- return 0;
- /* max file have csectDir=1
- * qbb file have csectDir=4 */
- if(le16(header->uDllVersion)==4 && le32(header->csectDir)==0)
- return 0;
- /*
- num_FAT_blocks=109+num_extra_FAT_blocks*(512-1);
- maximum file size is 512+(num_FAT_blocks*128)*512, about 1.6GB
- */
- if(le32(header->num_FAT_blocks)==0 ||
- le32(header->num_extra_FAT_blocks)>50 ||
- le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
- return 0;
- reset_file_recovery(file_recovery_new);
- file_recovery_new->file_check=&file_check_doc;
- file_recovery_new->file_rename=&file_rename_doc;
- file_recovery_new->extension=ole_get_file_extension(buffer, buffer_size);
- if(file_recovery_new->extension!=NULL)
- {
- if(strcmp(file_recovery_new->extension,"sda")==0)
- {
- if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
- file_recovery_new->extension="sdd";
- }
- else if(strcmp(file_recovery_new->extension,"wps")==0)
- {
- /* Distinguish between MS Works .wps and MS Publisher .pub */
- if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
- file_recovery_new->extension="pub";
- }
- return 1;
- }
- if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL)
- {
- file_recovery_new->extension="doc";
- }
- else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL)
- {
- file_recovery_new->extension="sda";
- }
- else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL)
- {
- file_recovery_new->extension="sdc";
- }
- else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
- {
- file_recovery_new->extension="sdd";
- }
- else if(td_memmem(buffer,buffer_size,"Worksheet",9)!=NULL ||
- td_memmem(buffer,buffer_size,"Book",4)!=NULL ||
- td_memmem(buffer,buffer_size,"Workbook",8)!=NULL ||
- td_memmem(buffer,buffer_size,"Calc",4)!=NULL)
- {
- file_recovery_new->extension="xls";
- }
- else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL)
- {
- file_recovery_new->extension="ppt";
- }
- else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
- {
- file_recovery_new->extension="mdb";
- }
- else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL)
- {
- file_recovery_new->extension="vsd";
- }
- else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL)
- {
- file_recovery_new->extension="sdw";
- }
- else if(td_memmem(buffer,buffer_size,"CPicPage",8)!=NULL)
- { /* Flash Project File */
- file_recovery_new->extension="fla";
- }
- else if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
- { /* Publisher */
- file_recovery_new->extension="pub";
- }
- else if(td_memmem(buffer, buffer_size, "Microsoft Works Database", 24)!=NULL
- || td_memmem( buffer, buffer_size, "MSWorksDBDoc", 12)!=NULL)
- { /* Microsoft Works .wdb */
- file_recovery_new->extension="wdb";
- }
- else if(td_memmem(buffer,buffer_size,"MetaStock",9)!=NULL)
- { /* MetaStock */
- file_recovery_new->extension="mws";
- }
- else
- file_recovery_new->extension=file_hint_doc.extension;
- return 1;
-}
-
-static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
-{
- uint32_t *fat;
- uint32_t *dif;
- dif=(uint32_t*)MALLOC(109*4+(le32(header->num_extra_FAT_blocks)<<le16(header->uSectorShift)));
- memcpy(dif,(header+1),109*4);
- if(le32(header->num_extra_FAT_blocks)>0)
- { /* Load DIF*/
- unsigned long int i;
- unsigned long int block;
- unsigned char *data=(unsigned char*)&dif[109];
- for(i=0, block=le32(header->FAT_next_block);
- i<le32(header->num_extra_FAT_blocks) && block!=0xFFFFFFFF && block!=0xFFFFFFFE;
- i++, block=le32(dif[109+i*(((1<<le16(header->uSectorShift))/4)-1)]))
- {
- if(my_fseek(IN, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET) < 0)
- {
- free(dif);
- return NULL;
- }
- if(fread(data, 1<<le16(header->uSectorShift), 1, IN)!=1)
- {
- free(dif);
- return NULL;
- }
- data+=(1<<le16(header->uSectorShift))-4;
- }
- }
- fat=(uint32_t*)MALLOC(le32(header->num_FAT_blocks)<<le16(header->uSectorShift));
- { /* Load FAT */
- unsigned long int j;
- unsigned char *data;
- for(j=0, data=(unsigned char*)fat;
- j<le32(header->num_FAT_blocks);
- j++, data+=(1<<le16(header->uSectorShift)))
- {
- if(my_fseek(IN, offset + ((1+le32(dif[j]))<<le16(header->uSectorShift)), SEEK_SET)<0)
- {
- free(dif);
- free(fat);
- return NULL;
- }
- if(fread(data, (1<<le16(header->uSectorShift)), 1, IN)!=1)
- {
- free(dif);
- free(fat);
- return NULL;
- }
- }
- }
- free(dif);
- return fat;
-}
-
+/*@
+ @ requires \valid(IN);
+ @ requires \valid_read(fat + (0 .. fat_entries-1));
+ @ requires 9 == uSectorShift || 12 == uSectorShift;
+ @ requires 0 < len <= 1024*1024;
+ @ ensures \result!=\null ==> \valid((char *)\result + (0 .. len - 1));
+ @*/
static void *OLE_read_stream(FILE *IN,
const uint32_t *fat, const unsigned int fat_entries, const unsigned int uSectorShift,
const unsigned int block_start, const unsigned int len, const uint64_t offset)
{
+ //@ split uSectorShift;
unsigned char *dataPt;
unsigned int block;
- unsigned int size_read;
- dataPt=(unsigned char *)MALLOC((len+(1<<uSectorShift)-1) / (1<<uSectorShift) * (1<<uSectorShift));
- for(block=block_start, size_read=0;
- size_read < len;
- block=le32(fat[block]), size_read+=(1<<uSectorShift))
+ unsigned int i;
+ const unsigned int i_max=((len+(1<<uSectorShift)-1) >> uSectorShift);
+#ifdef __FRAMAC__
+ dataPt=(unsigned char *)MALLOC(((1024*1024+(1<<uSectorShift)-1) >> uSectorShift) << uSectorShift);
+#else
+ dataPt=(unsigned char *)MALLOC(i_max << uSectorShift);
+#endif
+ /*@ assert \valid(dataPt + ( 0 .. len-1)); */
+ for(i=0, block=block_start;
+ i < i_max;
+ i++, block=le32(fat[block]))
{
if(!(block < fat_entries))
{
free(dataPt);
return NULL;
}
- if(my_fseek(IN, offset + ((1+block)<<uSectorShift), SEEK_SET)<0)
- {
- free(dataPt);
- return NULL;
- }
- if(fread(&dataPt[size_read], (1<<uSectorShift), 1, IN)!=1)
+ if(OLE_read_block(IN, &dataPt[i<<uSectorShift], uSectorShift, block, offset)<0)
{
free(dataPt);
return NULL;
@@ -582,201 +630,516 @@ static void *OLE_read_stream(FILE *IN,
return dataPt;
}
+/*@
+ @ requires \valid(IN);
+ @ requires \valid_read(header);
+ @ requires \valid_read(fat);
+ @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift);
+ @ requires 0 < le32(header->csectMiniFat) <= 2048;
+ @ ensures \result!=\null ==> \valid((char *)\result + (0 .. (le32(header->csectMiniFat) << le16(header->uSectorShift)) - 1));
+ @*/
static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries, const uint64_t offset)
{
- unsigned char*minifat_pos;
uint32_t *minifat;
unsigned int block;
unsigned int i;
+ const unsigned int uSectorShift=le16(header->uSectorShift);
if(le32(header->csectMiniFat)==0)
return NULL;
- minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << le16(header->uSectorShift));
- minifat_pos=(unsigned char*)minifat;
+ /*@ assert le32(header->csectMiniFat)!=0; */
+#ifdef __FRAMAC__
+ minifat=(uint32_t*)MALLOC(2048 << 12);
+#else
+ minifat=(uint32_t*)MALLOC(le32(header->csectMiniFat) << uSectorShift);
+#endif
block=le32(header->MiniFat_block);
- for(i=0; i < le32(header->csectMiniFat) && block < fat_entries; i++)
+ for(i=0; i < le32(header->csectMiniFat); i++)
{
- if(my_fseek(IN, offset + (((uint64_t)1+block) << le16(header->uSectorShift)), SEEK_SET) < 0)
+ unsigned char*minifat_pos=(unsigned char*)minifat + (i << uSectorShift);
+ if(block >= fat_entries)
{
free(minifat);
return NULL;
}
- if(fread(minifat_pos, 1 << le16(header->uSectorShift), 1, IN) != 1)
+ if(OLE_read_block(IN, (unsigned char *)minifat_pos, uSectorShift, block, offset)<0)
{
free(minifat);
return NULL;
}
- minifat_pos+=1 << le16(header->uSectorShift);
block=le32(fat[block]);
}
return minifat;
}
+/*@
+ @ requires \valid_read((char *)buffer + (offset .. offset + 4 - 1));
+ @ requires \initialized((char *)buffer + (offset .. offset + 4 - 1));
+ @*/
static uint32_t get32u(const void *buffer, const unsigned int offset)
{
const uint32_t *val=(const uint32_t *)((const unsigned char *)buffer+offset);
return le32(*val);
}
+/*@
+ @ requires \valid_read((char *)buffer + (offset .. offset + 8 - 1));
+ @ requires \initialized((char *)buffer + (offset .. offset + 8 - 1));
+ @*/
static uint64_t get64u(const void *buffer, const unsigned int offset)
{
const uint64_t *val=(const uint64_t *)((const unsigned char *)buffer+offset);
return le64(*val);
}
-static void software2ext(const char **ext, const unsigned int count, const unsigned char *software)
+/*@
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. count-1));
+ @ requires \initialized(software + (0 .. count-1));
+ @ ensures *ext != \null || valid_read_string(*ext);
+ @*/
+static void software2ext(const char **ext, const unsigned char *software, const unsigned int count)
{
if(count>=12 && memcmp(software, "MicroStation", 12)==0)
{
- *ext="dgn";
+ *ext=extension_dgn;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=14 && memcmp(software, "Microsoft Word", 14)==0)
{
- *ext="doc";
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=15 && memcmp(software, "Microsoft Excel", 15)==0)
{
if(*ext==NULL || strcmp(*ext,"sldprt")!=0)
- *ext="xls";
+ {
+ *ext=extension_xls;
+ /*@ assert valid_read_string(*ext); */
+ }
return;
}
if(count>=20 && memcmp(software, "Microsoft PowerPoint", 20)==0)
{
- *ext="ppt";
+ *ext=extension_ppt;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count>=21 && memcmp(software, "Microsoft Office Word", 21)==0)
{
- *ext="doc";
+ *ext=file_hint_doc.extension;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count==21 && memcmp(software, "TurboCAD for Windows", 21)==0)
{
- *ext="tcw";
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
return;
}
if(count==22 && memcmp(software, "TurboCAD pour Windows", 22)==0)
{
- *ext="tcw";
+ *ext=extension_tcw;
+ /*@ assert valid_read_string(*ext); */
return;
}
+ /*@ assert *ext != \null || valid_read_string(*ext); */
return ;
}
-static const char *software_uni2ext(const unsigned int count, const unsigned char *software)
+/*@
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. 2*count-1));
+ @ requires \initialized(software + (0 .. 2*count-1));
+ @ ensures \result == \null || \result == extension_et || \result == extension_psmodel;
+ @ ensures \result == \null || valid_read_string(\result);
+ @*/
+static const char *software_uni2ext(const unsigned char *software, const unsigned int count)
{
if(count>=15 && memcmp(software, "M\0i\0c\0r\0o\0s\0o\0f\0t\0 \0E\0x\0c\0e\0l\0", 30)==0)
- return "et";
+ {
+ /*@ assert valid_read_string(extension_et); */
+ return extension_et;
+ }
if(count>=17 && memcmp(software, "D\0e\0l\0c\0a\0m\0 \0P\0o\0w\0e\0r\0S\0H\0A\0P\0E\0", 34)==0)
- return "psmodel";
+ {
+ /*@ assert valid_read_string(extension_psmodel); */
+ return extension_psmodel;
+ }
return NULL;
}
-static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char **title, time_t *file_time)
+struct summary_entry
{
- unsigned int pos;
- assert(dirLen >= 48 && dirLen<=1024*1024);
+ uint32_t tag;
+ uint32_t offset;
+};
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @*/
+static void OLE_parse_software_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, const char **ext)
+{
+ if(offset >= size - 8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert offset < size - 8; */
+ {
+ const unsigned int count=get32u(buffer, offset + 4);
+ const unsigned int offset_soft=offset + 8;
+ /*@ assert offset_soft == offset + 8; */
+ if(count == 0 || count > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert 0 < count <= size; */
+ if(offset_soft + count > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert offset_soft + count <= size; */
#ifdef DEBUG_OLE
- dump_log(dataPt, dirLen);
+ {
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j<count; j++)
+ {
+ log_info("%c", buffer[offset_soft + j]);
+ }
+ log_info("\n");
+ }
#endif
- if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
- return ;
- pos=get32u(dataPt, 44);
- if(pos > dirLen - 8)
+#ifndef MAIN_doc
+ software2ext(ext, &buffer[offset_soft], count);
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @*/
+static void OLE_parse_uni_software_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, const char **ext)
+{
+ if(offset >= size - 8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
return ;
+ }
+ /*@ assert offset < size - 8; */
{
-// unsigned int size;
- unsigned int numEntries;
- unsigned int i;
- numEntries=get32u(dataPt, pos+4);
+ const unsigned int offset8=offset + 8;
+ /*@ assert offset8 < size; */
+ const unsigned int count=get32u(buffer, offset + 4);
+ unsigned int count2;
+ if(count == 0 || count > size/2)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert 0 < count <= size/2; */
+ count2=2*count;
+ /*@ assert 0 < count2 <= size; */
+ if(count2 > size - offset8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ return ;
+ }
+ /*@ assert count2 <= size - offset8; */
+ /*@ assert \valid_read(buffer + (0 .. size - 1)) && \initialized(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read(buffer + (0 .. offset8 + count2 - 1)); */
#ifdef DEBUG_OLE
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j < 2 * count; j+=2)
{
- unsigned int size=get32u(dataPt, pos);
- log_info("Property Info %u - %u at 0x%x\n", numEntries, size, pos);
+ log_info("%c", buffer[offset + 8 + j]);
}
+ log_info("\n");
#endif
- if(pos + 8 + 8 * numEntries > dirLen)
+#ifndef __FRAMAC__
+ /*@ assert \initialized(buffer + (0 .. offset8 + count2 - 1)); */
+ *ext=software_uni2ext(&buffer[offset8], count);
+#endif
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(title);
+ @ requires *title == \null || valid_read_string(*title);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
+static void OLE_parse_title_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, char **title)
+{
+ if(offset + 8 > size)
+ {
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert offset + 8 <= size; */
+ {
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ const unsigned int count=get32u(buffer, offset + 4);
+ const unsigned int offset_tmp=offset + 8;
+ char *tmp;
+ if(count <= 1 || count > size)
+ {
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
- for(i=0; i<numEntries; i++)
+ }
+ /*@ assert 1 < count <= size; */
+ if(offset_tmp + count > size)
{
- const unsigned int entry = pos + 8 + 8 * i;
- const unsigned int tag=get32u(dataPt, entry);
- const unsigned int offset=get32u(dataPt, entry + 4);
- const unsigned int valStart = pos + 4 + offset;
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert offset_tmp + count <= size; */
+#ifndef MAIN_doc
+ tmp=(char*)MALLOC(count+1);
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert offset_tmp + count <= size; */
+ /*@ assert \valid_read(buffer + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read((char*)buffer + (0 .. offset_tmp + count - 1)); */
+ /*@ assert \valid_read((buffer + offset_tmp) + (0 .. count - 1)); */
+ /*@ assert \valid_read((buffer + offset_tmp) + (1 .. count - 1)); */
+ /*@ assert \valid_read(((char*)(buffer+offset_tmp))+(0..count-1)); */
+ /*@ assert \valid_read(((char*)(buffer+offset_tmp))+(1..count-1)); */
+ /*@ assert \valid_read((char*)(buffer + offset_tmp)); */
+ /*@ assert \valid_read((char*)(buffer + offset_tmp)) && \valid_read(((char*)(buffer+offset_tmp))+(1..count-1)); */
+ /*@ assert valid_read_or_empty((void const *)(buffer + offset_tmp), count); */
+ memcpy(tmp, &buffer[offset_tmp], count);
+ tmp[count]='\0';
+ /*@ assert valid_read_string(tmp); */
+#ifdef DEBUG_OLE
+ log_info("Title %s\n", tmp);
+#endif
+ *title=tmp;
+ /*@ assert valid_read_string(*title); */
+#endif
+ }
+ /*@ assert *title == \null || valid_read_string(*title); */
+}
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(file_time);
+ @*/
+static void OLE_parse_filetime_entry(const unsigned char *buffer, const unsigned int size, const unsigned int offset, time_t *file_time)
+{
+ uint64_t tmp;
+ if(offset + 12 > size)
+ {
+ return ;
+ }
+ /*@ assert offset + 12 <= size; */
+ tmp=get64u(buffer, offset + 4);
+ tmp/=10000000;
+ if(tmp > (uint64_t)134774 * 24 * 3600)
+ {
+ tmp -= (uint64_t)134774 * 24 * 3600;
+ *file_time=tmp;
+ }
+}
+
+/*@
+ @ requires 8 <= size <= 1024*1024;
+ @ requires \valid_read(buffer+ (0 .. size-1));
+ @ requires \initialized(buffer+ (0 .. size-1));
+ @ requires \valid(ext);
+ @ requires \valid(title);
+ @ requires \valid(file_time);
+ @ requires *title == \null || valid_read_string(*title);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
+static void OLE_parse_PropertySet(const unsigned char *buffer, const unsigned int size, const char **ext, char **title, time_t *file_time)
+{
+ const struct summary_entry *entries=(const struct summary_entry *)&buffer[8];
+ const unsigned int numEntries=get32u(buffer, 4);
+ unsigned int i;
+#ifdef DEBUG_OLE
+ log_info("Property Info %u entries - %u bytes\n", numEntries, size);
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ if(numEntries == 0 || numEntries > 1024*1024)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 0 < numEntries <= 1024*1024; */
+ if(8 + numEntries * 8 > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 8 + numEntries * 8 <= size; */
+ /*@ assert numEntries * 8 <= size - 8; */
+ /*@ assert numEntries < size/8; */
+ if((const unsigned char *)&entries[numEntries] > &buffer[size])
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read((buffer+8) + (8 .. size - 8 - 1)); */
+ /*@
+ @ loop invariant *ext == \null || valid_read_string(*ext);
+ @ loop invariant *title == \null || valid_read_string(*title);
+ @ loop invariant 0 <= i <= numEntries;
+ @ loop variant numEntries-i;
+ @*/
+ for(i=0; i<numEntries; i++)
+ {
+ const unsigned int entry_offset=8+8*i;
+ if(entry_offset + 8 > size)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert entry_offset + 8 <= size; */
+ {
+ const struct summary_entry *entry=(const struct summary_entry *)&buffer[entry_offset];
+ const unsigned int tag=le32(entry->tag);
+ const unsigned int offset=le32(entry->offset);
unsigned int type;
- if(valStart >= dirLen)
+ if(offset >= size - 4)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
- type=get32u(dataPt, pos + offset);
+ }
+ /*@ assert offset < size - 4; */
+ /*@ assert \valid_read(buffer + (0 .. offset + 4 - 1)); */
+ type=get32u(buffer, offset);
#ifdef DEBUG_OLE
- log_info("entry 0x%x, tag 0x%x, offset 0x%x, valStart 0x%x, type 0x%x\n",
- entry, tag, offset, valStart, type);
+ log_info("entry 0x%x, tag 0x%x, offset 0x%x, offset + 4 0x%x, type 0x%x\n",
+ entry, tag, offset, offset + 4, type);
#endif
/* tag: Software, type: VT_LPSTR */
if(tag==0x12 && type==30)
{
- unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + count > dirLen)
- return ;
-#ifdef DEBUG_OLE
- {
- unsigned int j;
- log_info("Software ");
- for(j=0; j<count; j++)
- {
- log_info("%c", dataPt[valStart + 4 + j]);
- }
- log_info("\n");
- }
-#endif
- software2ext(ext, count, &dataPt[valStart + 4]);
+ OLE_parse_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
/* tag: Software, type: VT_LPWSTR */
if(tag==0x12 && type==31)
{
- unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + 2 * count > dirLen)
- return ;
-#ifdef DEBUG_OLE
- {
- unsigned int j;
- log_info("Software ");
- for(j=0; j < 2 * count; j+=2)
- {
- log_info("%c", dataPt[valStart + 4 + j]);
- }
- log_info("\n");
- }
-#endif
- *ext=software_uni2ext(count, &dataPt[valStart + 4]);
+ OLE_parse_uni_software_entry(buffer, size, offset, ext);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
}
+ /* tag: title, type: VT_LPSTR */
if(tag==0x02 && type==30 && *title==NULL)
{
- const unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + count > dirLen)
- return ;
- *title=(char*)MALLOC(count+1);
- memcpy(*title, &dataPt[valStart + 4], count);
- (*title)[count]='\0';
-#ifdef DEBUG_OLE
- log_info("Title %s\n", *title);
-#endif
+ OLE_parse_title_entry(buffer, size, offset, title);
+ /*@ assert *title == \null || valid_read_string(*title); */
}
/* ModifyDate, type=VT_FILETIME */
if(tag==0x0d && type==64)
{
- uint64_t tmp=get64u(dataPt, valStart);
- tmp/=10000000;
- if(tmp > (uint64_t)134774 * 24 * 3600)
- {
- tmp -= (uint64_t)134774 * 24 * 3600;
- *file_time=tmp;
- }
+ OLE_parse_filetime_entry(buffer, size, offset, file_time);
}
}
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ }
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+}
+
+/*@
+ @ requires 48 <= dirLen <= 1024*1024;
+ @ requires \valid_read(dataPt + (0 .. dirLen-1));
+ @ requires \initialized(dataPt + (0 .. dirLen-1));
+ @ requires \valid(ext);
+ @ requires \valid(title);
+ @ requires \valid(file_time);
+ @ requires *title == \null || valid_read_string(*title);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
+static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned int dirLen, const char **ext, char **title, time_t *file_time)
+{
+ unsigned int pos;
+ assert(dirLen >= 48 && dirLen<=1024*1024);
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+#ifdef DEBUG_OLE
+ dump_log(dataPt, dirLen);
+#endif
+ if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
+ return ;
+ pos=get32u(dataPt, 44);
+ if(pos > dirLen - 8)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert pos <= dirLen - 8; */
+ {
+ /* PropertySet */
+ const unsigned int size=get32u(dataPt, pos);
+ if(size <= 8 || size > dirLen || pos + size > dirLen)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 8 < size; */
+ /*@ assert size <= dirLen; */
+ /*@ assert dirLen <=1024*1024; */
+ /*@ assert \valid_read(dataPt + (0 .. dirLen-1)); */
+ /*@ assert pos + size <= dirLen; */
+ /*@ assert \valid_read(dataPt + (0 .. pos+size-1)); */
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+#ifndef __FRAMAC__
+ OLE_parse_PropertySet(&dataPt[pos], size, ext, title, file_time);
+#endif
}
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
}
+/*@
+ @ requires \valid_read(ministream + (0 .. ministream_size-1));
+ @ requires \valid_read(minifat + (0 .. minifat_entries-1));
+ @ requires uMiniSectorShift==6;
+ @ requires 48 <= len <= 1024*1024;
+ @ ensures \result!=\null ==> \valid((char *)\result + (0 .. len-1));
+ @*/
static void *OLE_read_ministream(unsigned char *ministream,
const uint32_t *minifat, const unsigned int minifat_entries, const unsigned int uMiniSectorShift,
const unsigned int miniblock_start, const unsigned int len, const unsigned int ministream_size)
@@ -784,41 +1147,91 @@ static void *OLE_read_ministream(unsigned char *ministream,
unsigned char *dataPt;
unsigned int mblock;
unsigned int size_read;
+#ifdef __FRAMAC__
+ dataPt=(unsigned char *)MALLOC((1024*1024+(1<<uMiniSectorShift)-1) / (1<<uMiniSectorShift) * (1<<uMiniSectorShift));
+#else
dataPt=(unsigned char *)MALLOC((len+(1<<uMiniSectorShift)-1) / (1<<uMiniSectorShift) * (1<<uMiniSectorShift));
+#endif
for(mblock=miniblock_start, size_read=0;
size_read < len;
- mblock=le32(minifat[mblock]), size_read+=(1<<uMiniSectorShift))
+ size_read+=(1<<uMiniSectorShift))
{
- if(!(mblock < minifat_entries))
+ if(mblock >= minifat_entries)
{
free(dataPt);
return NULL;
}
- if((mblock<<uMiniSectorShift)+ (1<<uMiniSectorShift) <= ministream_size)
- memcpy(&dataPt[size_read], &ministream[mblock<<uMiniSectorShift], (1<<uMiniSectorShift));
+ /* TODO assert mblock < minifat_entries; */
+ if((mblock+1)> ministream_size>>uMiniSectorShift)
+ {
+ free(dataPt);
+ return NULL;
+ }
+ memcpy(&dataPt[size_read], &ministream[mblock<<uMiniSectorShift], (1<<uMiniSectorShift));
+#ifdef __FRAMAC__
+ mblock=Frama_C_interval(0, minifat_entries);
+#else
+ mblock=le32(minifat[mblock]);
+#endif
}
return dataPt;
}
+/*@
+ @ requires \valid(file);
+ @ requires \valid_read(fat + (0 .. fat_entries-1));
+ @ requires \valid_read(header);
+ @ requires 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift);
+ @ requires 6 == le16(header->uMiniSectorShift);
+ @ requires \valid(ext);
+ @ requires \valid(title);
+ @ requires \valid(file_time);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires *title == \null || valid_read_string(*title);
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @ ensures *title == \null || valid_read_string(*title);
+ @*/
static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries,
const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size,
const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time,
const uint64_t offset)
{
+ const unsigned int uSectorShift=le16(header->uSectorShift);
unsigned char *summary=NULL;
if(len < 48 || len>1024*1024)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
+ }
+ /*@ assert 48 <= len <= 1024*1024; */
if(len < le32(header->miniSectorCutoff))
{
- if(le32(header->csectMiniFat)!=0 && ministream_size > 0 && ministream_size < 1024*1024)
+ if(le32(header->csectMiniFat)==0 || ministream_size == 0)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ if(ministream_size > 1024*1024 || le32(header->csectMiniFat) > 2048)
{
- const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << le16(header->uSectorShift)) / 4;
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
+ return ;
+ }
+ /*@ assert 0 < le32(header->csectMiniFat) <= 2048; */
+ {
+ const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << uSectorShift) / 4;
uint32_t *minifat;
unsigned char *ministream;
if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries, offset))==NULL)
+ {
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
return ;
+ }
ministream=(unsigned char *)OLE_read_stream(file,
- fat, fat_entries, le16(header->uSectorShift),
+ fat, fat_entries, uSectorShift,
ministream_block, ministream_size, offset);
if(ministream != NULL)
{
@@ -832,15 +1245,34 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
}
else
summary=(unsigned char *)OLE_read_stream(file,
- fat, fat_entries, le16(header->uSectorShift),
+ fat, fat_entries, uSectorShift,
block, len, offset);
+#if defined(__FRAMAC__)
+ {
+ free(summary);
+ summary=MALLOC(4096);
+ Frama_C_make_unknown((char *)summary, 4096);
+ /*@ assert \initialized((char *)summary + (0 .. 4096 - 1)); */
+// OLE_parse_summary_aux(summary, 4096, ext, title, file_time);
+ /*@ assert *title == \null || valid_read_string(*title); */
+ OLE_parse_PropertySet(summary, 4096, ext, title, file_time);
+ free(summary);
+ }
+#else
if(summary!=NULL)
{
OLE_parse_summary_aux(summary, len, ext, title, file_time);
free(summary);
}
+#endif
+ /*@ assert *ext == \null || valid_read_string(*ext); */
+ /*@ assert *title == \null || valid_read_string(*title); */
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_doc(file_recovery_t *file_recovery)
{
const char *ext=NULL;
@@ -851,8 +1283,10 @@ static void file_rename_doc(file_recovery_t *file_recovery)
const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
time_t file_time=0;
unsigned int fat_entries;
+ unsigned int uSectorShift;
+ unsigned int num_FAT_blocks;
if(strstr(file_recovery->filename, ".sdd")!=NULL)
- ext="sdd";
+ ext=extension_sdd;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
return;
#ifdef DEBUG_OLE
@@ -865,10 +1299,33 @@ static void file_rename_doc(file_recovery_t *file_recovery)
fclose(file);
return ;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer_header, sizeof(buffer_header));
+#endif
+ uSectorShift=le16(header->uSectorShift);
+ num_FAT_blocks=le32(header->num_FAT_blocks);
/* Sanity check */
- if(le32(header->num_FAT_blocks)==0 ||
- le32(header->num_extra_FAT_blocks)>50 ||
- le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
+ if( uSectorShift != 9 && uSectorShift != 12)
+ {
+ fclose(file);
+ return ;
+ }
+ /*@ assert 9 == uSectorShift || 12 == uSectorShift; */
+ if(le16(header->uMiniSectorShift) != 6)
+ {
+ fclose(file);
+ return ;
+ }
+ /* Sanity check */
+ if(num_FAT_blocks==0 ||
+ le32(header->num_extra_FAT_blocks)>50)
+ {
+ fclose(file);
+ return ;
+ }
+ /*@ assert num_FAT_blocks > 0; */
+ /*@ assert 0 <= le32(header->num_extra_FAT_blocks) <= 50; */
+ if(num_FAT_blocks > 109+le32(header->num_extra_FAT_blocks)*((1<<uSectorShift)/4-1))
{
fclose(file);
return ;
@@ -878,9 +1335,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
fclose(file);
return ;
}
- fat_entries=(le32(header->num_FAT_blocks)==0 ?
- 109:
- (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
+ fat_entries=(num_FAT_blocks==0 ? 109 : (num_FAT_blocks<<uSectorShift)/4);
{
unsigned int ministream_block=0;
unsigned int ministream_size=0;
@@ -896,15 +1351,12 @@ static void file_rename_doc(file_recovery_t *file_recovery)
block=le32(fat[block]), i++)
{
struct OLE_DIR *dir_entries;
- if(my_fseek(file, (1+block)<<le16(header->uSectorShift), SEEK_SET)<0)
- {
- free(fat);
- fclose(file);
- free(title);
- return ;
- }
- dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
- if(fread(dir_entries, 1<<le16(header->uSectorShift), 1, file)!=1)
+#ifdef __FRAMAC__
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<12);
+#else
+ dir_entries=(struct OLE_DIR *)MALLOC(1<<uSectorShift);
+#endif
+ if(OLE_read_block(file, (unsigned char *)dir_entries, uSectorShift, block, 0)<0)
{
free(fat);
free(dir_entries);
@@ -912,22 +1364,23 @@ static void file_rename_doc(file_recovery_t *file_recovery)
free(title);
return ;
}
-
#ifdef DEBUG_OLE
log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
{
unsigned int sid;
- const struct OLE_DIR *dir_entry=dir_entries;
+ int is_db=0;
if(i==0)
{
+ const struct OLE_DIR *dir_entry=dir_entries;
ministream_block=le32(dir_entry->start_block);
ministream_size=le32(dir_entry->size);
}
- for(sid=0, dir_entry=dir_entries;
- sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR);
- sid++,dir_entry++)
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
{
+ const struct OLE_DIR *dir_entry=&dir_entries[sid];
if(dir_entry->type!=NO_ENTRY)
{
const char SummaryInformation[40]=
@@ -950,97 +1403,42 @@ static void file_rename_doc(file_recovery_t *file_recovery)
(unsigned int)le32(dir_entry->start_block),
(unsigned int)le32(dir_entry->size));
#endif
+ {
+ const char *tmp=entry2ext(dir_entry);
+ /*@ assert tmp == \null || valid_read_string(tmp); */
+ if(tmp!=NULL)
+ ext=tmp;
+ /*@ assert ext == \null || valid_read_string(ext); */
+ }
switch(le16(dir_entry->namsiz))
{
- case 10:
- if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
- ext="qdf-backup";
- break;
- case 12:
- /* 3ds max */
- if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
- ext="max";
- /* Licom AlphaCAM */
- else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
- ext="amb";
+ case 4:
+ if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0)
+ is_db=1;
+ if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "2\0\0\0", 4)==0)
+ is_db=2;
break;
case 16:
if(sid==1 && memcmp(dir_entry->name, "d\0o\0c\0.\0d\0e\0t\0\0\0", 16)==0)
- ext="psmodel";
+ ext=extension_psmodel;
/* Windows Sticky Notes */
else if(sid==1 && memcmp(dir_entry->name, "V\0e\0r\0s\0i\0o\0n\0\0\0", 16)==0)
- ext="snt";
+ ext=extension_snt;
+ else if(is_db==1 && sid==2 && memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0\0\0", 16)==0)
+ is_db=2;
break;
case 18:
/* MS Excel
* Note: Microsoft Works Spreadsheet contains the same signature */
if(ext==NULL &&
memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
- ext="xls";
- /* Microsoft Works .wps */
- else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
- ext="wps";
- break;
- case 20:
- /* Page Maker */
- if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0)
- ext="p65";
- break;
- case 22:
- /* SigmaPlot .jnb */
- if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0\0", 22)==0)
- ext="jnb";
- /* Autodesk Inventor part ipt or iam file */
- if(memcmp(dir_entry->name, "R\0S\0e\0S\0t\0o\0r\0a\0g\0e\0\0\0", 22)==0)
- ext="ipt";
- break;
- case 24:
- /* HP Photosmart Photo Printing Album */
- if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0)
- ext="albm";
- /* Lotus Approach */
- else if(memcmp(dir_entry->name,"A\0p\0p\0r\0o\0a\0c\0h\0D\0o\0c\0\0\0",24)==0)
- ext="apr";
- break;
- case 28:
- /* Microsoft Works Spreadsheet or Chart */
- if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0)
- ext="xlr";
- /* Visio */
- else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0)
- ext="vsd";
- /* SolidWorks */
- else if(memcmp(&dir_entry->name, "s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0", 28)==0)
- {
-#ifdef DJGPP
- ext="sld";
-#else
- ext="sldprt";
-#endif
- }
- break;
- case 32:
- if(memcmp(dir_entry->name, "m\0a\0n\0i\0f\0e\0s\0t\0.\0c\0a\0m\0x\0m\0l\0\0\0",32)==0)
- ext="camrec";
- break;
- case 34:
- if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0)
- ext="sdc";
+ ext=extension_xls;
break;
case 36:
/* sda=StarDraw, sdd=StarImpress */
- if((ext==NULL || strcmp(ext,"sdd")!=0) &&
+ if(ext!=extension_sdd &&
memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
- ext="sda";
- else if(memcmp(dir_entry->name, "f\0i\0l\0e\0_\0C\0O\0M\0P\0A\0N\0Y\0_\0F\0I\0L\0E\0\0\0", 36)==0)
- ext="qbb";
- break;
- case 38:
- /* Quattro Pro spreadsheet */
- if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0)
- ext="qpw";
- else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0)
- ext="sdw";
+ ext=extension_sda;
break;
case 40:
if(memcmp(dir_entry->name, SummaryInformation, 40)==0)
@@ -1050,38 +1448,19 @@ static void file_rename_doc(file_recovery_t *file_recovery)
le32(dir_entry->start_block), le32(dir_entry->size),
&ext, &title, &file_time, 0);
}
- else if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
- ext="ppt";
- /* Outlook */
- else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0)
- ext="msg";
- break;
- case 46:
- if(memcmp(dir_entry->name,
- "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0)
- {
-#ifdef DJGPP
- ext="sld";
-#else
- ext="sldprt";
-#endif
- }
- break;
- case 56:
- /* Wilcom ES Software */
- if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
- ext="emb";
break;
}
if(sid==1 && le16(dir_entry->namsiz) >=6 &&
memcmp(dir_entry->name, "D\0g\0n", 6)==0)
- ext="dgn";
+ ext=extension_dgn;
#ifdef DEBUG_OLE
if(ext!=NULL)
log_info("Found %s %u\n", ext, le16(dir_entry->namsiz));
#endif
}
}
+ if(ext==NULL && is_db==2)
+ ext=extension_db;
}
free(dir_entries);
}
@@ -1099,8 +1478,211 @@ static void file_rename_doc(file_recovery_t *file_recovery)
file_rename(file_recovery, NULL, 0, 0, ext, 1);
}
+/*@
+ @ requires buffer_size >= sizeof(struct OLE_HDR);
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ 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);
+ @*/
+static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /*@ assert file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename); */
+ const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
+ /* Check for Little Endian */
+ if(le16(header->uByteOrder)!=0xFFFE)
+ return 0;
+ if(le16(header->uDllVersion)!=3 && le16(header->uDllVersion)!=4)
+ return 0;
+ if(le16(header->reserved)!=0 || le32(header->reserved1)!=0)
+ return 0;
+ if(le16(header->uMiniSectorShift)!=6)
+ return 0;
+ if(le16(header->uDllVersion)==3 && le16(header->uSectorShift)!=9)
+ return 0;
+ /* max and qbb file have uSectorShift=12 */
+ if(le16(header->uDllVersion)==4 && le16(header->uSectorShift)!=12)
+ return 0;
+ if(le16(header->uDllVersion)==3 && le32(header->csectDir)!=0)
+ return 0;
+ /* max file have csectDir=1
+ * qbb file have csectDir=4 */
+ if(le16(header->uDllVersion)==4 && le32(header->csectDir)==0)
+ return 0;
+ /*
+ num_FAT_blocks=109+num_extra_FAT_blocks*(512-1);
+ maximum file size is 512+(num_FAT_blocks*128)*512, about 1.6GB
+ */
+ if(le32(header->num_FAT_blocks)==0 ||
+ le32(header->num_extra_FAT_blocks)>50 ||
+ le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))/4-1))
+ return 0;
+ /*@ assert file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename); */
+ /*@ assert le32(header->num_FAT_blocks) <= 109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))/4-1); */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->file_check=&file_check_doc;
+ file_recovery_new->file_rename=&file_rename_doc;
+ file_recovery_new->extension=ole_get_file_extension(header, buffer_size);
+ if(file_recovery_new->extension!=NULL)
+ {
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ if(strcmp(file_recovery_new->extension,"sda")==0)
+ {
+ if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
+ file_recovery_new->extension=extension_sdd;
+ }
+ else if(strcmp(file_recovery_new->extension,"wps")==0)
+ {
+ /* Distinguish between MS Works .wps and MS Publisher .pub */
+ if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
+ file_recovery_new->extension=extension_pub;
+ }
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ return 1;
+ }
+ if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL)
+ {
+ file_recovery_new->extension=file_hint_doc.extension;
+ }
+ else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL)
+ {
+ file_recovery_new->extension=extension_sda;
+ }
+ else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL)
+ {
+ file_recovery_new->extension=extension_sdc;
+ }
+ else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
+ {
+ file_recovery_new->extension=extension_sdd;
+ }
+ else if(td_memmem(buffer,buffer_size,"Worksheet",9)!=NULL ||
+ td_memmem(buffer,buffer_size,"Book",4)!=NULL ||
+ td_memmem(buffer,buffer_size,"Workbook",8)!=NULL ||
+ td_memmem(buffer,buffer_size,"Calc",4)!=NULL)
+ {
+ file_recovery_new->extension=extension_xls;
+ }
+ else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL)
+ {
+ file_recovery_new->extension=extension_ppt;
+ }
+ else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
+ {
+ file_recovery_new->extension=extension_mdb;
+ }
+ else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL)
+ {
+ file_recovery_new->extension=extension_vsd;
+ }
+ else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL)
+ {
+ file_recovery_new->extension=extension_sdw;
+ }
+ else if(td_memmem(buffer,buffer_size,"CPicPage",8)!=NULL)
+ { /* Flash Project File */
+ file_recovery_new->extension=extension_fla;
+ }
+ else if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
+ { /* Publisher */
+ file_recovery_new->extension=extension_pub;
+ }
+ else if(td_memmem(buffer, buffer_size, "Microsoft Works Database", 24)!=NULL
+ || td_memmem( buffer, buffer_size, "MSWorksDBDoc", 12)!=NULL)
+ { /* Microsoft Works .wdb */
+ file_recovery_new->extension=extension_wdb;
+ }
+ else if(td_memmem(buffer,buffer_size,"MetaStock",9)!=NULL)
+ { /* MetaStock */
+ file_recovery_new->extension=extension_mws;
+ }
+ else
+ file_recovery_new->extension=file_hint_doc.extension;
+ /*@ assert valid_read_string(file_recovery_new->extension); */
+ return 1;
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_doc(file_stat_t *file_stat)
{
static const unsigned char doc_header[]= { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1};
register_header_check(0, doc_header,sizeof(doc_header), &header_check_doc, file_stat);
}
+
+#if defined(MAIN_doc)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.doc";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_doc;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_doc(&file_stats);
+ if(header_check_doc(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.file_check == &file_check_doc; */
+ /*@ assert file_recovery_new.file_rename == &file_rename_doc; */
+#ifdef __FRAMAC__
+ file_recovery_new.file_size = 512*Frama_C_interval(1, 1000);
+#endif
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.file_stat=&file_stats;
+ if(file_recovery_new.file_stat!=NULL)
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_doc(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ {
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_doc(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_doc(&file_recovery_new);
+ return 0;
+}
+#endif
diff --git a/src/file_evtx.c b/src/file_evtx.c
new file mode 100644
index 0000000..68f884f
--- /dev/null
+++ b/src/file_evtx.c
@@ -0,0 +1,80 @@
+/*
+
+ File: file_evtx.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+
+struct evtx_header
+{
+ char magic[8];
+ uint64_t OldestChunk;
+ uint64_t CurrentChunkNum;
+ uint64_t NextRecordNum;
+ uint32_t HeaderPart1Len; /* 0x80 */
+ uint16_t MinorVersion; /* 1 */
+ uint16_t MajorVersion; /* 3 */
+ uint16_t HeaderSize; /* 0x1000 */
+ uint16_t ChunkCount;
+ char unk[76]; /* 0 */
+ uint32_t Flags;
+ uint32_t Checksum;
+} __attribute__ ((gcc_struct, __packed__));
+
+static void register_header_check_evtx(file_stat_t *file_stat);
+
+const file_hint_t file_hint_evtx= {
+ .extension="evtx",
+ .description="Microsoft Event Log",
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .enable_by_default=1,
+ .register_header_check=&register_header_check_evtx
+};
+
+static int header_check_evtx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const struct evtx_header *hdr=(const struct evtx_header *)buffer;
+ if(le32(hdr->HeaderPart1Len) != 0x80 ||
+ le16(hdr->MinorVersion) != 1 ||
+ le16(hdr->MajorVersion) != 3 ||
+ le16(hdr->HeaderSize) != 0x1000)
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_evtx.extension;
+ file_recovery_new->calculated_file_size=(uint64_t)le16(hdr->HeaderSize) + (uint64_t)le16(hdr->ChunkCount) * 64 * 1024;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+}
+
+static void register_header_check_evtx(file_stat_t *file_stat)
+{
+ register_header_check(0, "ElfFile", 8, &header_check_evtx, file_stat);
+}
diff --git a/src/file_exe.c b/src/file_exe.c
index 1348db5..ade58b0 100644
--- a/src/file_exe.c
+++ b/src/file_exe.c
@@ -35,9 +35,11 @@
#include "filegen.h"
#include "pe.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_exe(file_stat_t *file_stat);
-static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
static void file_rename_pe_exe(file_recovery_t *file_recovery);
const file_hint_t file_hint_exe= {
@@ -49,124 +51,141 @@ const file_hint_t file_hint_exe= {
.register_header_check=&register_header_check_exe
};
+static const char *extension_dll="dll";
static const unsigned char exe_header[2] = {'M','Z'};
-static void register_header_check_exe(file_stat_t *file_stat)
-{
- register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat);
-}
-
+/*@
+ @ requires buffer_size >= 2;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_exe.extension || file_recovery_new->extension == extension_dll);
+ @*/
static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer;
- const struct pe_image_file_hdr *pe_hdr;
if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
return 0;
- pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
- if(le32(dos_hdr->e_lfanew)>0 &&
- le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
- (le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
- {
- /* NE Win16 */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_exe.extension;
- return 1;
- }
if(le32(dos_hdr->e_lfanew)>0 &&
- le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
- (le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
+ le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr))
{
- /* Windows PE */
- if(le16(pe_hdr->Characteristics) & 0x2000)
- {
- /* Dynamic Link Library */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="dll";
- }
- else if(le16(pe_hdr->Characteristics) & 0x02)
+ const struct pe_image_file_hdr *pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
+ if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
{
+ /* NE Win16 */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
+ file_recovery_new->min_filesize=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr);
+ return 1;
}
- else
+ if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
{
+ /* Windows PE */
+ if(le16(pe_hdr->Characteristics) & 0x2000)
+ {
+ /* Dynamic Link Library */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=extension_dll;
+ }
+ else if(le16(pe_hdr->Characteristics) & 0x02)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_exe.extension;
+ }
+ else
+ {
#ifdef DEBUG_EXE
- log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
+ log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
#endif
- return 0;
- }
- file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
-#ifdef DEBUG_EXE
- {
- const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
- (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
- if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
- {
- log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
- log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
+ return 0;
}
- else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
+#ifdef DEBUG_EXE
{
- const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
(((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ if((const unsigned char*)(pe_image_optional32+1) <= buffer+buffer_size)
+ {
+ /*@ assert \valid_read(pe_image_optional32); */
+ if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
+ {
+ log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
+ log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
+ }
+ else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ }
+ log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
+ (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
+ }
}
- log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
- (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
- }
#endif
- {
- unsigned int i;
- uint64_t sum=0;
- const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
- ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
- for(i=0;
- i<le16(pe_hdr->NumberOfSections) &&
- (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
- i++,pe_image_section++)
{
- if(le32(pe_image_section->SizeOfRawData)>0)
+ unsigned int i;
+ uint64_t sum=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr);
+ const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
+ ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
+ for(i=0;
+ i<le16(pe_hdr->NumberOfSections) &&
+ (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
+ i++,pe_image_section++)
{
+ if(le32(pe_image_section->SizeOfRawData)>0)
+ {
+ const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
#ifdef DEBUG_EXE
- log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
- (unsigned long)le32(pe_image_section->PointerToRawData),
- (unsigned long)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
+ log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
+ (unsigned long)le32(pe_image_section->PointerToRawData),
+ (unsigned long)(tmp-1));
#endif
- if(le32(pe_image_section->SizeOfRawData)%32==0)
- {
- if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
- sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
+ if(le32(pe_image_section->SizeOfRawData)%32==0)
+ {
+ if(sum < tmp)
+ sum=tmp;
+ }
}
- }
- if(le16(pe_image_section->NumberOfRelocations)>0)
- {
+ if(le16(pe_image_section->NumberOfRelocations)>0)
+ {
+ /*@ assert le16(pe_image_section->NumberOfRelocations)>0; */
+ const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ /*@ assert tmp > 0; */
#ifdef DEBUG_EXE
- log_debug("relocations 0x%lx-0x%lx\n",
- (unsigned long)le32(pe_image_section->PointerToRelocations),
- (unsigned long)le32(pe_image_section->PointerToRelocations)+1*le16(pe_image_section->NumberOfRelocations)-1);
+ log_debug("relocations 0x%lx-0x%lx\n",
+ (unsigned long)le32(pe_image_section->PointerToRelocations),
+ (unsigned long)(tmp-1));
#endif
- if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
- sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ if(sum < tmp)
+ sum = tmp;
+ }
}
- }
- if(le32(pe_hdr->NumberOfSymbols)>0)
- {
+ if(le32(pe_hdr->NumberOfSymbols)>0)
+ {
+ /*@ assert le32(pe_hdr->NumberOfSymbols)>0; */
+ const uint64_t tmp=(uint64_t)le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*(uint64_t)le32(pe_hdr->NumberOfSymbols);
+ /*@ assert tmp > 0; */
#ifdef DEBUG_EXE
- log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
- (long unsigned)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
+ log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
+ (long unsigned)(tmp-1));
#endif
- if(le32(pe_hdr->NumberOfSymbols)<0x10000)
- {
- if(sum < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
- sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
+ if(le32(pe_hdr->NumberOfSymbols)<0x10000)
+ {
+ if(sum < tmp)
+ sum = tmp;
+ }
}
+ /* It's not perfect, EXE overlay are not recovered */
+ file_recovery_new->calculated_file_size=sum;
}
- /* It's not perfect, EXE overlay are not recovered */
- file_recovery_new->calculated_file_size=sum;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->file_rename=&file_rename_pe_exe;
+ return 1;
}
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->file_rename=&file_rename_pe_exe;
- return 1;
}
if(le16(dos_hdr->bytes_in_last_block) <= 512 &&
le16(dos_hdr->blocks_in_file) > 0 &&
@@ -183,23 +202,36 @@ static int header_check_exe(const unsigned char *buffer, const unsigned int buff
{ /* COFF_I386MAGIC */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
+ file_recovery_new->min_filesize=coff_offset+2;
return 1;
}
#ifdef DEBUG_EXE
{
- unsigned int i;
- const struct exe_reloc *exe_reloc;
+ const struct exe_reloc *exe_relocs;
+ const unsigned int reloc_table_offset=le16(dos_hdr->reloc_table_offset);
+ const unsigned int num_relocs=le16(dos_hdr->num_relocs);
log_info("Maybe a DOS EXE\n");
log_info("blocks %llu\n", (long long unsigned)coff_offset);
log_info("data start %llx\n", (long long unsigned)16*le16(dos_hdr->header_paragraphs));
- log_info("reloc %u\n", le16(dos_hdr->num_relocs));
- for(i=0, exe_reloc=(const struct exe_reloc *)(buffer+le16(dos_hdr->reloc_table_offset));
- i < le16(dos_hdr->num_relocs) &&
- le16(dos_hdr->reloc_table_offset)+ (i+1)*sizeof(struct exe_reloc) < buffer_size;
- i++, exe_reloc++)
+ log_info("reloc %u\n", num_relocs);
+ if(reloc_table_offset + num_relocs * sizeof(struct exe_reloc) <= buffer_size)
{
- log_info("offset %x, segment %x\n",
- le16(exe_reloc->offset), le16(exe_reloc->segment));
+ unsigned int i;
+ /*@ assert reloc_table_offset + num_relocs * sizeof(struct exe_reloc) <= buffer_size; */
+ exe_relocs=(const struct exe_reloc *)(buffer+reloc_table_offset);
+ /*@ assert \valid_read(exe_relocs + (0 .. num_relocs-1)); */
+ /*@
+ @ loop invariant 0 <= i <= num_relocs;
+ @ loop variant num_relocs -i;
+ @ */
+ for(i=0; i < num_relocs; i++)
+ {
+ /*@ assert 0 <= i <= num_relocs; */
+ const struct exe_reloc *exe_reloc=&exe_relocs[i];
+ /*@ assert \valid_read(exe_reloc); */
+ log_info("offset %x, segment %x\n",
+ le16(exe_reloc->offset), le16(exe_reloc->segment));
+ }
}
}
#endif
@@ -213,11 +245,17 @@ struct rsrc_entries_s
uint32_t Pos;
} __attribute__ ((gcc_struct, __packed__));
+struct rsrc_offlen
+{
+ uint32_t off;
+ uint32_t len;
+} __attribute__ ((gcc_struct, __packed__));
+
struct PE_index
{
uint16_t len;
uint16_t val_len;
- uint16_t type;
+ uint16_t type; /* 0=binary data, 1=text*/
} __attribute__ ((gcc_struct, __packed__));
static char vs_version_info[32]={
@@ -241,276 +279,595 @@ static char InternalName[24]={
'N', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0
};
-static unsigned int ReadUnicodeStr(const char *buffer, unsigned int pos, const unsigned int len)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_String(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
- for(; pos+2<len && (buffer[pos]!='\0' || buffer[pos+1]!='\0'); pos+=2)
+ const struct PE_index *PE_index;
+ unsigned int len;
+ unsigned int val_len;
+ unsigned int type;
+ if(6 > end)
{
-#ifdef DEBUG_EXE
- log_info("%c", buffer[pos]);
-#endif
+ return -1;
+ }
+ PE_index=(const struct PE_index*)buffer;
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ type=le16(PE_index->type);
+ log_info("parse_String len=%u val_len=%u type=%u\n", len, val_len, type);
+ if(len > end)
+ return -1;
+ if(6 + 2 * val_len > len)
+ return -1;
+ dump_log(buffer, len);
+// type=1 => text
+ if(6+needle_len < end && type==1 && memcmp(&buffer[6], needle, needle_len)==0)
+ {
+ if(6 + needle_len + 2 * val_len > len)
+ return -1;
+ file_rename_unicode(file_recovery, buffer, end, 6+needle_len, NULL, force_ext);
+ }
+ return len;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_StringArray(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
+{
+ unsigned int pos=0;
+ log_info("parse_StringArray end=%u\n", end);
+ /*@
+ @ loop variant end - pos;
+ @*/
+ while(pos<end)
+ {
+ const int res=parse_String(file_recovery, &buffer[pos], end - pos, needle, needle_len, force_ext);
+ if(res <= 0)
+ return -1;
+ /*@ assert res > 0; */
+ pos+=res;
+ /* Padding */
+ if((pos & 0x03)!=0)
+ pos+=2;
+ }
+ return 0;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_StringTable(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
+{
+ const struct PE_index *PE_index;
+ unsigned int pos;
+ unsigned int len;
+ unsigned int val_len;
+ if(6 > end)
+ {
+ return -1;
+ }
+ PE_index=(const struct PE_index*)buffer;
+ /*@ assert \valid_read(PE_index); */
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ log_info("parse_StringTable len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ if(len > end)
+ return -1;
+ /* szKey: language identifier + code page */
+ pos = 6 + 2*8 + 2;
+ /* Padding */
+ if((pos & 0x03)!=0)
+ pos+=2;
+ if(pos > len)
+ return -1;
+ /* An array of one or more String structures */
+ return parse_StringArray(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext);
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
+{
+ /* https://docs.microsoft.com/en-us/windows/win32/menurc/stringfileinfo */
+ const struct PE_index *PE_index;
+ unsigned int pos;
+ unsigned int len;
+ unsigned int val_len;
+ if(6 > end)
+ {
+ return -1;
}
- pos+=2;
+ PE_index=(const struct PE_index*)buffer;
+ /*@ assert \valid_read(PE_index); */
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ log_info("parse_StringFileInfo len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ if(len > end)
+ return -1;
+ if(6 + sizeof(StringFileInfo) > end)
+ return 0;
+ /* szKey == StringFileInfo ? */
+ if(memcmp(&buffer[6], StringFileInfo, sizeof(StringFileInfo))!=0)
+ return 0;
+ if(val_len!=0)
+ return -1;
+ pos=6 + sizeof(StringFileInfo);
+ /* Padding */
if((pos & 0x03)!=0)
pos+=2;
- return pos;
+ if(pos > len)
+ return -1;
+ return parse_StringTable(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext);
}
-static int PEVersion_aux(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires end > 0;
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_VS_VERSIONINFO(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
+ /* https://docs.microsoft.com/en-us/windows/win32/menurc/vs-versioninfo */
unsigned int pos=0;
- while(1)
+ const struct PE_index *PE_index;
+ const char *stringName;
+ unsigned int len;
+ unsigned int val_len;
+ if(6 > end)
{
- const struct PE_index *PE_index;
- pos=(pos + 3) & 0xfffffffc; /* align on a 4-byte boundary */
- if(pos + 6 > end)
- {
- return -1;
- }
- PE_index=(const struct PE_index*)&buffer[pos];
- if(le16(PE_index->len)==0 && le16(PE_index->val_len)==0)
- {
- return -1;
- }
- {
- const char *stringName=&buffer[pos+6];
- if(pos + 6 + sizeof(vs_version_info) < end &&
- memcmp(stringName, vs_version_info, sizeof(vs_version_info))==0)
- {
- pos+=6+sizeof(vs_version_info);
- if((pos & 0x03)!=0)
- pos+=2;
- pos+=le16(PE_index->val_len);
- }
- else if(pos + 6 + sizeof(StringFileInfo) < end &&
- memcmp(stringName, StringFileInfo, sizeof(StringFileInfo))==0 &&
- le16(PE_index->val_len)==0)
- {
- unsigned int i;
- unsigned int pt=pos+6+sizeof(StringFileInfo);
- pos+=le16(PE_index->len);
- for(i=0; pt + 6 < pos; i++)
- {
- if(i==0)
- {
- pt=ReadUnicodeStr(buffer, pt+6, pos);
- }
- else
- {
- int do_rename=0;
- PE_index=(const struct PE_index*)&buffer[pt];
- if(pt+6+needle_len < end &&
- memcmp(&buffer[pt+6], needle, needle_len)==0)
- {
- do_rename=1;
- }
- pt=ReadUnicodeStr(buffer, pt+6, pos);
- if(le16(PE_index->val_len)>0)
- {
- if(do_rename)
- {
- file_rename_unicode(file_recovery, buffer, end, pt, NULL, force_ext);
- return 0;
- }
-#ifdef DEBUG_EXE
- log_info(": ");
-#endif
- pt=ReadUnicodeStr(buffer, pt, pos);
- }
- }
-#ifdef DEBUG_EXE
- log_info("\n");
-#endif
- }
- }
- else
- {
- pos+=le16(PE_index->len)+le16(PE_index->val_len);
- }
- }
+ return -1;
+ }
+ PE_index=(const struct PE_index*)buffer;
+ /*@ assert \valid_read(PE_index); */
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ log_info("parse_VS_VERSIONINFO len=%u val_len=%u type=%u\n", len, val_len, le16(PE_index->type));
+ if(len==0 && val_len==0)
+ {
+ return -1;
}
+ if(val_len > len)
+ return -1;
+ if(len > end)
+ return -1;
+ /*@ assert len <= end; */
+ pos+=6;
+ if(pos + sizeof(vs_version_info) >= len)
+ return -1;
+ stringName=&buffer[pos];
+ /* szKey */
+ if(memcmp(stringName, vs_version_info, sizeof(vs_version_info))!=0)
+ return -1;
+ pos+=sizeof(vs_version_info);
+ /* Padding1 */
+ if((pos & 0x03)!=0)
+ pos+=2;
+ /* VS_FIXEDFILEINFO */
+ pos+=val_len;
+ /* Padding2 */
+ if((pos & 0x03)!=0)
+ pos+=2;
+ if(pos > len)
+ return -1;
+ /* Children */
+ /* An array of zero or one StringFileInfo structures, and zero or one
+ * VarFileInfo structures that are children of the current VS_VERSIONINFO structure. */
+ if(parse_StringFileInfo(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext) < 0)
+ return -1;
+ return 0;
}
+/*@
+ @ requires \valid(file);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
static void PEVersion(FILE *file, const unsigned int offset, const unsigned int length, file_recovery_t *file_recovery)
{
- char *buffer;
+ char buffer[1024*1024];
+ log_info("PEVersion(file, %u, %u, file_recovery)\n", offset, length);
if(length==0 || length > 1024*1024)
return;
if(fseek(file, offset, SEEK_SET)<0)
return ;
- buffer=(char*)MALLOC(length);
- if(fread(buffer, length, 1, file) != 1)
+ if(fread(&buffer, length, 1, file) != 1)
{
- free(buffer);
return ;
}
- if(PEVersion_aux(file_recovery, buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#endif
+ if(parse_VS_VERSIONINFO(file_recovery, (const char *)&buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
{
- free(buffer);
return;
}
- PEVersion_aux(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
- free(buffer);
+ parse_VS_VERSIONINFO(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
+}
+
+/*@
+ @ requires \valid(file);
+ @ requires base <= 0x7fffffff;
+ @ requires \valid_read(pe_sections);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read(rsrc_entry);
+ @*/
+static int pe_resource_language_aux(FILE *file, const unsigned int base, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery, const struct rsrc_entries_s *rsrc_entry)
+{
+ struct rsrc_offlen buffer;
+ uint32_t off;
+ unsigned int len;
+ unsigned int j;
+#ifdef DEBUG_EXE
+ log_info("resource lang=%u, %x, offset %u\n",
+ le32(rsrc_entry->Type),
+ le32(rsrc_entry->Pos),
+ base + (le32(rsrc_entry->Pos) & 0x7fffffff));
+#endif
+ if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0)
+ {
+ return -1;
+ }
+ if(fread(&buffer, 1, sizeof(buffer), file) != sizeof(buffer))
+ {
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#endif
+ off=le32(buffer.off);
+ len=le32(buffer.len);
+ /*TODO: loop invariant 0 <= j <= nbr_sections; */
+ for(j=0; j<nbr_sections; j++)
+ {
+ const struct pe_image_section_hdr *pe_section=&pe_sections[j];
+ const uint32_t virt_addr_start=le32(pe_section->VirtualAddress);
+ const uint64_t virt_addr_end=(uint64_t)virt_addr_start + le32(pe_section->SizeOfRawData);
+ if(virt_addr_end <= 0xffffffff && virt_addr_start <= off && off < virt_addr_end && (uint64_t)off - virt_addr_start + base <=0xffffffff)
+ {
+ PEVersion(file, off - virt_addr_start + base, len, file_recovery);
+ return 0;
+ }
+ }
+ return 1;
}
-static void file_exe_ressource(FILE *file, const unsigned int base, const unsigned int dir_start, const unsigned int size, const unsigned int rsrcType, const unsigned int level, const struct pe_image_section_hdr *pe_sections, unsigned int nbr_sections, file_recovery_t *file_recovery)
+/*@
+ @ requires \valid(file);
+ @ requires base <= 0x7fffffff;
+ @ requires dir_start <= 0x7fffffff;
+ @ requires \valid_read(pe_sections);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
+static void pe_resource_language(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery)
{
struct rsrc_entries_s *rsrc_entries;
- struct rsrc_entries_s *rsrc_entry;
- unsigned char buffer[16];
- int buffer_size;
- unsigned int nameEntries;
- unsigned idEntries;
unsigned int count;
unsigned int i;
#ifdef DEBUG_EXE
- log_info("file_exe_ressource(file, %u, %u, %u, %u)\n", base, dir_start, size, level);
+ log_info("pe_resource_language(file, %u, %u)\n", base, dir_start);
+#endif
+ {
+ unsigned char buffer[16];
+ unsigned int nameEntries;
+ unsigned int idEntries;
+ if(fseek(file, base + dir_start, SEEK_SET)<0)
+ return ;
+ if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer))
+ return ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
#endif
- if(level > 2)
+ nameEntries = buffer[12]+(buffer[13]<<8);
+ idEntries = buffer[14]+(buffer[15]<<8);
+ count = nameEntries + idEntries;
+ }
+ log_info("pe_resource_language count=%u\n", count);
+ if(count==0 || count > 1024)
return ;
- if(fseek(file, base + dir_start, SEEK_SET)<0)
+ /*@ assert 0 < count <= 1024; */
+#ifdef __FRAMAC__
+ rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s));
+#else
+ rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s));
+#endif
+ /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */
+ if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count)
+ {
+ free(rsrc_entries);
return ;
- buffer_size=fread(buffer, 1, sizeof(buffer), file);
- if(buffer_size<16)
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
+ {
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+ int res=pe_resource_language_aux(file, base, pe_sections, nbr_sections, file_recovery, rsrc_entry);
+ if(res <= 0)
+ {
+ free(rsrc_entries);
+ return ;
+ }
+ }
+ free(rsrc_entries);
+}
+
+/*@
+ @ requires \valid(file);
+ @ requires base <= 0x7fffffff;
+ @ requires dir_start <= 0x7fffffff;
+ @ requires \valid_read(pe_sections);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
+static void pe_resource_id(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery)
+{
+ struct rsrc_entries_s *rsrc_entries;
+ unsigned int count;
+ unsigned int i;
+#ifdef DEBUG_EXE
+ log_info("pe_resource_id(file, %u, %u)\n", base, dir_start);
+#endif
+ {
+ unsigned char buffer[16];
+ unsigned int nameEntries;
+ unsigned int idEntries;
+ if(fseek(file, base + dir_start, SEEK_SET)<0)
+ return ;
+ if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer))
+ return ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
+ nameEntries = buffer[12]+(buffer[13]<<8);
+ idEntries = buffer[14]+(buffer[15]<<8);
+ count = nameEntries + idEntries;
+ }
+ if(count==0 || count > 1024)
+ return ;
+ /*@ assert 0 < count <= 1024; */
+#ifdef __FRAMAC__
+ rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s));
+#else
+ rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s));
+#endif
+ /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */
+ if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count)
+ {
+ free(rsrc_entries);
+ return ;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
+ {
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+#ifdef DEBUG_EXE
+ log_info("resource id=%u, %x, offset %u\n",
+ le32(rsrc_entry->Type),
+ le32(rsrc_entry->Pos),
+ base + (le32(rsrc_entry->Pos) & 0x7fffffff));
+#endif
+ if((le32(rsrc_entry->Pos) & 0x80000000)!=0)
+ {
+ pe_resource_language(file,
+ base,
+ le32(rsrc_entry->Pos) & 0x7fffffff,
+ pe_sections, nbr_sections, file_recovery);
+ }
+ }
+ free(rsrc_entries);
+}
+
+/*@
+ @ requires \valid(file);
+ @ requires \valid_read(pe_sections);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
+static void pe_resource_type(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery)
+{
+ struct rsrc_entries_s *rsrc_entries;
+ unsigned int count;
+ unsigned int i;
+#ifdef DEBUG_EXE
+ log_info("pe_resource_type(file, %u, %u)\n", base, dir_start);
+#endif
+ /* TODO: remove these artifical limits ? */
+ if(base > 0x7fffffff || dir_start > 0x7fffffff)
return ;
- nameEntries = buffer[12]+(buffer[13]<<8);
- idEntries = buffer[14]+(buffer[15]<<8);
- count = nameEntries + idEntries;
+ /*@ assert base <= 0x7fffffff; */
+ {
+ unsigned char buffer[16];
+ unsigned int nameEntries;
+ unsigned int idEntries;
+ if(fseek(file, base, SEEK_SET)<0)
+ return ;
+ if(fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer))
+ return ;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
+ nameEntries = buffer[12]+(buffer[13]<<8);
+ idEntries = buffer[14]+(buffer[15]<<8);
+ count = nameEntries + idEntries;
+ }
if(count==0 || count > 1024)
return ;
+ /*@ assert 0 < count <= 1024; */
+#ifdef __FRAMAC__
+ rsrc_entries=(struct rsrc_entries_s *)MALLOC(1024 * sizeof(struct rsrc_entries_s));
+#else
rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s));
+#endif
+ /*@ assert \valid((char *)rsrc_entries + (0 .. (unsigned long)((unsigned long)count * sizeof(struct rsrc_entries_s)) - 1)); */
if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count)
{
free(rsrc_entries);
return ;
}
- for(i=0, rsrc_entry=rsrc_entries; i<count; i++, rsrc_entry++)
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
{
- const unsigned int rsrcType_new=(level==0?le32(rsrc_entry->Type):rsrcType);
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
+ const unsigned int rsrcType=le32(rsrc_entry->Type);
#ifdef DEBUG_EXE
- log_info("ressource %u, %x, offset %u\n",
- rsrcType_new,
+ log_info("resource type=%u, %x, offset %u\n",
+ rsrcType,
le32(rsrc_entry->Pos),
base + (le32(rsrc_entry->Pos) & 0x7fffffff));
#endif
- /* Only intersted by version resources */
- if(rsrcType_new==16)
+ /* https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
+ * RT_CURSOR=1, RT_ICON=3, RT_VERSION=16 */
+ /* Only interested by version resources */
+ if(rsrcType==16)
{
if((le32(rsrc_entry->Pos) & 0x80000000)!=0)
{
- file_exe_ressource(file,
+ pe_resource_id(file,
base,
le32(rsrc_entry->Pos) & 0x7fffffff,
- size,
- (level==0?le32(rsrc_entry->Type):rsrcType),
- level + 1,
pe_sections, nbr_sections, file_recovery);
}
- if(level==2)
- {
- unsigned int off;
- unsigned int len;
- if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0)
- {
- free(rsrc_entries);
- return ;
- }
- buffer_size=fread(buffer, 1, sizeof(buffer), file);
- if(buffer_size<16)
- {
- free(rsrc_entries);
- return ;
- }
- off=buffer[0]+ (buffer[1]<<8) + (buffer[2]<<16) + (buffer[3]<<24);
- len=buffer[4]+ (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
- {
- const struct pe_image_section_hdr *pe_section;
- for(i=0, pe_section=pe_sections; i<nbr_sections; i++,pe_section++)
- {
- if(le32(pe_section->VirtualAddress) <= off
- && off < le32(pe_section->VirtualAddress) + le32(pe_section->SizeOfRawData))
- {
- PEVersion(file, off - le32(pe_section->VirtualAddress) + base, len, file_recovery);
- free(rsrc_entries);
- return ;
- }
- }
- }
- free(rsrc_entries);
- return ;
- }
}
}
free(rsrc_entries);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
static void file_rename_pe_exe(file_recovery_t *file_recovery)
{
unsigned char buffer[4096];
FILE *file;
int buffer_size;
- const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer;
+ const struct dos_image_file_hdr *dos_hdr;
const struct pe_image_file_hdr *pe_hdr;
+ unsigned int e_lfanew;
if((file=fopen(file_recovery->filename, "rb"))==NULL)
return;
buffer_size=fread(buffer, 1, sizeof(buffer), file);
+ /*@ assert buffer_size <= sizeof(buffer); */
if(buffer_size < (int)sizeof(struct dos_image_file_hdr))
{
fclose(file);
return ;
}
+ /*@ assert buffer_size >= sizeof(struct dos_image_file_hdr); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
{
fclose(file);
return ;
}
- if((unsigned int)buffer_size < le32(dos_hdr->e_lfanew)+sizeof(struct pe_image_file_hdr))
+ dos_hdr=(const struct dos_image_file_hdr*)buffer;
+ e_lfanew=le32(dos_hdr->e_lfanew);
+ if((unsigned int)buffer_size < e_lfanew+sizeof(struct pe_image_file_hdr))
+ {
+ fclose(file);
+ return ;
+ }
+ if(e_lfanew==0 ||
+ e_lfanew > buffer_size-sizeof(struct pe_image_file_hdr))
{
fclose(file);
return ;
}
- pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
- if(le32(dos_hdr->e_lfanew)==0 ||
- le32(dos_hdr->e_lfanew) > buffer_size-sizeof(struct pe_image_file_hdr) ||
- le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
+ pe_hdr=(const struct pe_image_file_hdr *)(buffer+e_lfanew);
+ if(le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
{
fclose(file);
return ;
}
{
+ const uint64_t offset_sections=e_lfanew + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader);
+ /* https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+ * Windows loader limits the number of sections to 96
+ */
+ const unsigned int nbr_sections=(le16(pe_hdr->NumberOfSections) < 96?le16(pe_hdr->NumberOfSections) : 96);
+ struct pe_image_section_hdr pe_sections[96];
unsigned int i;
- const struct pe_image_section_hdr *pe_sections;
- const struct pe_image_section_hdr *pe_section;
- unsigned int nbr_sections;
- pe_sections=(const struct pe_image_section_hdr*)
- ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
- for(i=0, pe_section=pe_sections;
- i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
- i++, pe_section++)
+ if(nbr_sections == 0)
+ {
+ fclose(file);
+ return ;
+ }
+ /*@ assert 0 < nbr_sections <= 96; */
+ if(fseek(file, offset_sections, SEEK_SET)<0)
{
+ fclose(file);
+ return ;
+ }
+ if(fread(pe_sections, sizeof(struct pe_image_section_hdr), nbr_sections, file) != nbr_sections)
+ {
+ fclose(file);
+ return ;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)pe_sections, sizeof(pe_sections));
+#endif
#ifdef DEBUG_EXE
- if(le32(pe_section->SizeOfRawData)>0)
+ /*@
+ @ loop invariant 0 <= i <= nbr_sections;
+ @*/
+ for(i=0; i<nbr_sections; i++)
+ {
+ const struct pe_image_section_hdr *pe_section=&pe_sections[i];
+ /*@ assert \valid_read(pe_section); */
+ if(le32(pe_section->VirtualSize)>0)
{
log_info("%s 0x%lx-0x%lx\n", pe_section->Name,
(unsigned long)le32(pe_section->VirtualAddress),
(unsigned long)le32(pe_section->VirtualAddress)+le32(pe_section->VirtualSize)-1);
}
-#endif
}
- nbr_sections=i;
- for(i=0, pe_section=pe_sections;
- i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
- i++, pe_section++)
+#endif
+ /*@
+ @ loop invariant 0 <= i <= nbr_sections;
+ @*/
+ for(i=0; i<nbr_sections; i++)
{
+ const struct pe_image_section_hdr *pe_section=&pe_sections[i];
+ /*@ assert \valid_read(pe_section); */
if(le32(pe_section->SizeOfRawData)>0)
{
if(memcmp((const char*)pe_section->Name, ".rsrc", 6)==0)
{
- file_exe_ressource(file,
+ pe_resource_type(file,
le32(pe_section->PointerToRawData),
- 0,
le32(pe_section->SizeOfRawData),
- 0,
- 0,
pe_sections, nbr_sections, file_recovery);
fclose(file);
return;
@@ -520,3 +877,95 @@ static void file_rename_pe_exe(file_recovery_t *file_recovery)
}
fclose(file);
}
+
+static void register_header_check_exe(file_stat_t *file_stat)
+{
+ register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat);
+}
+
+#if defined(MAIN_exe)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.exe";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_exe;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_exe(&file_stats);
+ if(header_check_exe(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.extension == file_hint_exe.extension || file_recovery_new.extension == extension_dll; */
+ file_recovery_new.file_stat=&file_stats;
+ if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL &&
+ file_recovery_new.data_check!=NULL)
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ if(file_recovery_new.file_stat!=NULL)
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_exe(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ if(file_recovery_new.file_check!=NULL)
+ {
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ (file_recovery_new.file_check)(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&file_recovery_new);
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_exr.c b/src/file_exr.c
new file mode 100644
index 0000000..f0df6ba
--- /dev/null
+++ b/src/file_exr.c
@@ -0,0 +1,58 @@
+/*
+
+ File: file_exr.c
+
+ Copyright (C) 2019 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_exr(file_stat_t *file_stat);
+
+const file_hint_t file_hint_exr= {
+ .extension="exr",
+ .description="OpenEXR",
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .enable_by_default=1,
+ .register_header_check=&register_header_check_exr
+};
+
+/* https://www.openexr.com/documentation/openexrfilelayout.pdf */
+static int header_check_exr(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_exr.extension;
+ file_recovery_new->min_filesize=0x20;
+ return 1;
+}
+
+static void register_header_check_exr(file_stat_t *file_stat)
+{
+ /* OpenEXR v2 */
+ static const unsigned char exr_header[5]= { 'v' , 0x2f, '1' , 0x01, 0x02 };
+ register_header_check(0, exr_header, sizeof(exr_header), &header_check_exr, file_stat);
+}
diff --git a/src/file_fp7.c b/src/file_fp7.c
index c82763c..8e54e54 100644
--- a/src/file_fp7.c
+++ b/src/file_fp7.c
@@ -54,7 +54,7 @@ static int header_check_fp7(const unsigned char *buffer, const unsigned int buff
file_recovery_new->min_filesize=4096;
file_recovery_new->file_check=&file_check_fp7;
if(memcmp(&buffer[0x21e], "Pro 12", 6)==0)
- file_recovery_new->extension="fp12";
+ file_recovery_new->extension="fmp12";
else
file_recovery_new->extension=file_hint_fp7.extension;
return 1;
diff --git a/src/file_gpg.c b/src/file_gpg.c
index 387e168..84a5587 100644
--- a/src/file_gpg.c
+++ b/src/file_gpg.c
@@ -33,9 +33,12 @@
#ifdef DEBUG_GPG
#include "log.h"
#endif
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+static const char *extension_pgp="pgp";
static void register_header_check_gpg(file_stat_t *file_stat);
-static int header_check_gpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_gpg= {
.extension="gpg",
@@ -82,31 +85,22 @@ const file_hint_t file_hint_gpg= {
static const unsigned char pgp_header[5]= {0xa8, 0x03, 'P', 'G', 'P'};
-static void register_header_check_gpg(file_stat_t *file_stat)
-{
- static const unsigned char gpg_header_pkey_enc[1]= {0x85};
- static const unsigned char gpg_header_symkey_enc[1]= {0x8c};
- static const unsigned char gpg_header_seckey[1]= {0x95};
-#if 1
- static const unsigned char gpg_header_pkey[1]= {0x99};
-#endif
- register_header_check(0, gpg_header_seckey, sizeof(gpg_header_seckey), &header_check_gpg, file_stat);
- register_header_check(0, gpg_header_symkey_enc, sizeof(gpg_header_symkey_enc), &header_check_gpg, file_stat);
- register_header_check(0, gpg_header_pkey_enc, sizeof(gpg_header_pkey_enc), &header_check_gpg, file_stat);
- register_header_check(0, pgp_header, sizeof(pgp_header), &header_check_gpg, file_stat);
-#if 1
- register_header_check(0, gpg_header_pkey, sizeof(gpg_header_pkey), &header_check_gpg, file_stat);
-#endif
-}
-
-static unsigned int openpgp_packet_tag(const unsigned char *buf)
+/*@
+ @ ensures 0 <= \result <= 0x3f;
+ @*/
+static unsigned int openpgp_packet_tag(const unsigned char buf)
{
/* Bit 7 -- Always one */
- if((buf[0]&0x80)==0)
+ if((buf&0x80)==0)
return 0; /* Invalid */
- return ((buf[0]&0x40)==0?((buf[0]>>2)&0x0f):(buf[0]&0x3f));
+ return ((buf&0x40)==0?((buf>>2)&0x0f):(buf&0x3f));
}
+/*@ requires \valid_read(buf+(0..5));
+ @ requires \valid(length_type);
+ @ requires \valid(indeterminate_length);
+ @ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==3)|| (*length_type==5);
+ */
static unsigned int old_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *indeterminate_length)
{
/* Old format */
@@ -119,8 +113,11 @@ static unsigned int old_format_packet_length(const unsigned char *buf, unsigned
*length_type=3;
return (buf[1] << 8) | buf[2];
case 2:
- *length_type=5;
- return (buf[1] << 24) |(buf[2] << 16) | (buf[3] << 8) | buf[4];
+ {
+ const uint32_t *tmp32_ptr=(const uint32_t *)&buf[1];
+ *length_type=5;
+ return be32(*tmp32_ptr);
+ }
default:
*length_type=1;
*indeterminate_length=1;
@@ -128,6 +125,12 @@ static unsigned int old_format_packet_length(const unsigned char *buf, unsigned
}
}
+/*@ requires \valid_read(buf+(0..5));
+ @ requires \valid(length_type);
+ @ requires \valid(partial_body_length);
+ @ ensures (*length_type == 1) || (*length_type == 2) || (*length_type==5);
+ @ ensures (*partial_body_length==0) || (*partial_body_length==1);
+ */
static unsigned int new_format_packet_length(const unsigned char *buf, unsigned int *length_type, int *partial_body_length)
{
*partial_body_length=0;
@@ -135,34 +138,53 @@ static unsigned int new_format_packet_length(const unsigned char *buf, unsigned
if(buf[0]<=191)
{
*length_type=1;
+ /*@ assert 0 <= buf[0] <= 191; */
return buf[0];
}
/* Two-Octet Body Length */
if(buf[0]<=223)
{
+ /*@ assert 192 <= buf[0] <= 223; */
+ unsigned int tmp=buf[0];
+ /*@ assert 192 <= tmp <= 223; */
+ tmp = ((tmp-192) << 8) + buf[1] + 192;
+ /*@ assert 192 <= tmp <= ((223-192) << 8) + 255 + 192; */
*length_type=2;
- return ((buf[0] - 192) << 8) + buf[1] + 192;
+ return tmp;
}
/* Five-Octet Body Length */
if(buf[0]==255)
{
+ const uint32_t *tmp32=(const uint32_t *)&buf[1];
+ const unsigned int tmp=be32(*tmp32);
*length_type=5;
- return (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
+ return tmp;
+ }
+ {
+ /*@ assert 224 <= buf[0] <= 254; */
+ const unsigned int tmp=buf[0]&0x1fu;
+ /* Partial Body Lengths */
+ *length_type=1;
+ *partial_body_length=1;
+ return 1u << tmp;
}
- /* Partial Body Lengths */
- *length_type=1;
- *partial_body_length=1;
- return 1 << (buf[0]& 0x1F);
}
-static int is_valid_mpi(const uint16_t *size)
+/*@
+ @ ensures \result == -1 || 0 <= \result <= 2048;
+ @*/
+static int is_valid_mpi(const uint16_t size)
{
- if(be16(*size) <= 16384)
- return (be16(*size)+7)/8;
+ const uint16_t tmp=be16(size);
+ if(tmp <= 16384)
+ return (tmp+7)/8;
return -1;
}
-static int is_valid_pubkey_algo(const int algo)
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @*/
+static int is_valid_pubkey_algo(const int algo)
{
/* 1 - RSA (Encrypt or Sign)
* 2 - RSA Encrypt-Only
@@ -189,6 +211,9 @@ static int is_valid_pubkey_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @*/
static int is_valid_sym_algo(const int algo)
{
/*
@@ -222,6 +247,9 @@ static int is_valid_sym_algo(const int algo)
}
}
+/*@
+ @ ensures \result == 0 || \result == 1;
+ @*/
static int is_valid_S2K(const unsigned int algo)
{
/* ID S2K Type
@@ -235,48 +263,62 @@ static int is_valid_S2K(const unsigned int algo)
return (algo==0 || algo==1 || algo==3);
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @*/
static void file_check_gpg(file_recovery_t *file_recovery)
{
unsigned int tag=0;
unsigned int nbr=0;
int partial_body_length=0;
int stop=0;
- off_t offset=0;
- unsigned char buffer[32];
+ uint64_t offset=0;
const uint64_t org_file_size=file_recovery->file_size;
file_recovery->file_size=0;
while(stop==0)
{
+ unsigned char buffer[32];
unsigned int i=0;
unsigned int length_type=0;
unsigned int length;
const int old_partial_body_length=partial_body_length;
+ if(nbr >=0xffffffff || offset + 6 >= 0x8000000000000000)
+ return;
+ /*@ assert offset < 0x8000000000000000 - 6; */
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 ||
fread(&buffer, sizeof(buffer), 1, file_recovery->handle) != 1)
return;
+#ifdef __FRAMAC__
+ Frama_C_make_unknown((char *)&buffer, sizeof(buffer));
+#endif
if(partial_body_length==0)
{
- if((buffer[i]&0x80)==0)
+ if((buffer[0]&0x80)==0)
break; /* Invalid */
- tag=openpgp_packet_tag(&buffer[i]);
- if((buffer[i]&0x40)==0)
+ tag=openpgp_packet_tag(buffer[0]);
+ if((buffer[0]&0x40)==0)
{
- length=old_format_packet_length(&buffer[i], &length_type, &stop);
+ length=old_format_packet_length(&buffer[0], &length_type, &stop);
+ /*@ assert (length_type == 1) || (length_type == 2) || (length_type==3) || (length_type==5); */
}
else
{
- length=new_format_packet_length(&buffer[i+1], &length_type, &partial_body_length);
+ length=new_format_packet_length(&buffer[1], &length_type, &partial_body_length);
length_type++;
+ /*@ assert (length_type == 2) || (length_type == 3) || (length_type==6); */
}
}
else
{
- length=new_format_packet_length(&buffer[i], &length_type, &partial_body_length);
+ length=new_format_packet_length(&buffer[0], &length_type, &partial_body_length);
+ /*@ assert (length_type == 1) || (length_type == 2) || (length_type==5); */
}
+ /*@ assert 0 <= length_type <= 6; */
#ifdef DEBUG_GPG
log_info("GPG 0x%04x: %02u tag=%2u, size=%u + %u)\n",
- i, nbr, tag, length_type, length);
+ 0, nbr, tag, length_type, length);
#endif
#if 0
if(tag==0 || tag==15 || (tag>19 && tag!=61)) /* Reserved or unused */
@@ -284,14 +326,19 @@ static void file_check_gpg(file_recovery_t *file_recovery)
#endif
if(length_type==0)
break; /* Don't know how to find the size */
+ /*@ assert 0 < length_type <= 6; */
i+=length_type;
+ /*@ assert 0 < i <= 6; */
offset+=length_type;
+ /*@ assert offset < 0x8000000000000000; */
+ if(offset + length >= 0x8000000000000000)
+ return ;
if(old_partial_body_length==0)
{
if(tag==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY)
{
- const uint16_t *mpi=(const uint16_t *)&buffer[i+1+8+1];
- const int len=is_valid_mpi(mpi);
+ const uint16_t *mpi_ptr=(const uint16_t *)&buffer[i+1+8+1];
+ const int len=is_valid_mpi(*mpi_ptr);
/* uint8_t version must be 3
* uint64_t pub_key_id
* uint8_t pub_key_algo
@@ -311,14 +358,16 @@ static void file_check_gpg(file_recovery_t *file_recovery)
if(buffer[i+1+8]==16 || buffer[i+1+8]==20)
{
int len2;
- unsigned char tmp[2];
+ uint16_t mpi2;
if(my_fseek(file_recovery->handle, offset+1+8+1+2+len, SEEK_SET) < 0 ||
- fread(&tmp, sizeof(tmp), 1, file_recovery->handle) != 1)
+ fread(&mpi2, sizeof(mpi2), 1, file_recovery->handle) != 1)
return;
- mpi=(const uint16_t *)&tmp[0];
- len2=is_valid_mpi(mpi);
+#ifdef __FRAMAC__
+ Frama_C_make_unknown((char *)&mpi2, sizeof(mpi2));
+#endif
+ len2=is_valid_mpi(mpi2);
#ifdef DEBUG_GPG
- log_info(" data: [ %u bits]\n", be16(*mpi));
+ log_info(" data: [ %u bits]\n", be16(*mpi2));
#endif
if(len2 <= 0)
return ;
@@ -408,6 +457,18 @@ static void file_check_gpg(file_recovery_t *file_recovery)
file_recovery->file_size=(stop==0?org_file_size:(uint64_t)offset);
}
+/*@
+ @ requires buffer_size >= 23;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_gpg);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_gpg.extension || file_recovery_new->extension == extension_pgp);
+ @*/
static int header_check_gpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
uint64_t i=0;
@@ -416,8 +477,12 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
int partial_body_length=0;
int stop=0;
memset(packet_tag, 0, sizeof(packet_tag));
- while(nbr<16 && i < buffer_size - 20 && stop==0)
+ /*@
+ @ loop invariant 0 <= nbr <=16;
+ @*/
+ while(nbr<16 && i < buffer_size - 23 && stop==0)
{
+ /*@ assert 0 <= i < buffer_size - 23; */
unsigned int length_type=0;
unsigned int tag;
unsigned int length;
@@ -426,21 +491,25 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
{
if((buffer[i]&0x80)==0)
break; /* Invalid */
- packet_tag[nbr]=openpgp_packet_tag(&buffer[i]);
+ packet_tag[nbr]=openpgp_packet_tag(buffer[i]);
if((buffer[i]&0x40)==0)
{
length=old_format_packet_length(&buffer[i], &length_type, &stop);
+ /*@ assert (length_type == 1) || (length_type == 2) || (length_type==3) || (length_type==5); */
}
else
{
length=new_format_packet_length(&buffer[i+1], &length_type, &partial_body_length);
length_type++;
+ /*@ assert (length_type == 2) || (length_type == 3) || (length_type==6); */
}
}
else
{
length=new_format_packet_length(&buffer[i], &length_type, &partial_body_length);
+ /*@ assert (length_type == 1) || (length_type == 2) || (length_type==5); */
}
+ /*@ assert 0 <= length_type <= 6; */
tag=packet_tag[nbr];
#ifdef DEBUG_GPG
log_info("GPG 0x%04x: %02u tag=%2u, size=%u + %u)\n",
@@ -452,13 +521,15 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
#endif
if(length_type==0)
break; /* Don't know how to find the size */
+ /*@ assert 0 < length_type <= 6; */
i+=length_type;
+ /*@ assert 0 <= i < buffer_size - 23 + 6; */
if(old_partial_body_length==0)
{
if(tag==OPENPGP_TAG_PUBKEY_ENC_SESSION_KEY)
{
- const uint16_t *mpi=(const uint16_t *)&buffer[i+1+8+1];
- const int len=is_valid_mpi(mpi);
+ const uint16_t *mpi_ptr=(const uint16_t *)&buffer[i+1+8+1];
+ const int len=is_valid_mpi(*mpi_ptr);
/* uint8_t version must be 3
* uint64_t pub_key_id
* uint8_t pub_key_algo
@@ -466,6 +537,7 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
if(buffer[i]==3 && is_valid_pubkey_algo(buffer[i+1+8]) &&
len>0)
{
+ const unsigned int offset_mpi=i+1+8+1+2+len;
#ifdef DEBUG_GPG
log_info("GPG :pubkey enc packet: version %u, algo %u, keyid %02X%02X%02X%02X%02X%02X%02X%02X\n",
buffer[i], buffer[i+1+8],
@@ -473,14 +545,15 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
buffer[i+5], buffer[i+6], buffer[i+7], buffer[i+8]);
log_info(" data: [ %u bits]\n", be16(*mpi));
#endif
- if((unsigned)(1+8+1+2+len) > length)
+ if(offset_mpi +2 > length)
return 0;
if((buffer[i+1+8]==16 || buffer[i+1+8]==20) &&
- i+1+8+1+2+len+2<buffer_size)
+ offset_mpi + 2 <= buffer_size)
{
int len2;
- mpi=(const uint16_t *)&buffer[i+1+8+1+2+len];
- len2=is_valid_mpi(mpi);
+ /*@ assert 0 <= offset_mpi + 2 <= buffer_size; */
+ mpi_ptr=(const uint16_t *)&buffer[offset_mpi];
+ len2=is_valid_mpi(*mpi_ptr);
#ifdef DEBUG_GPG
log_info(" data: [ %u bits]\n", be16(*mpi));
#endif
@@ -600,7 +673,7 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
{
reset_file_recovery(file_recovery_new);
file_recovery_new->file_check=&file_check_gpg;
- file_recovery_new->extension="pgp";
+ file_recovery_new->extension=extension_pgp;
return 1;
}
if( /* encrypted_data.gpg */
@@ -641,3 +714,85 @@ static int header_check_gpg(const unsigned char *buffer, const unsigned int buff
#endif
return 0;
}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_gpg(file_stat_t *file_stat)
+{
+ static const unsigned char gpg_header_pkey_enc[1]= {0x85};
+ static const unsigned char gpg_header_symkey_enc[1]= {0x8c};
+ static const unsigned char gpg_header_seckey[1]= {0x95};
+ static const unsigned char gpg_header_pkey[1]= {0x99};
+ register_header_check(0, gpg_header_seckey, sizeof(gpg_header_seckey), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_symkey_enc, sizeof(gpg_header_symkey_enc), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_pkey_enc, sizeof(gpg_header_pkey_enc), &header_check_gpg, file_stat);
+ register_header_check(0, pgp_header, sizeof(pgp_header), &header_check_gpg, file_stat);
+ register_header_check(0, gpg_header_pkey, sizeof(gpg_header_pkey), &header_check_gpg, file_stat);
+}
+
+#if defined(MAIN_gpg)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.gpg";
+ unsigned char buffer[BLOCKSIZE];
+ int res;
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_gpg;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_gpg(&file_stats);
+ if(header_check_gpg(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.extension == file_hint_gpg.extension || file_recovery_new.extension == extension_pgp; */
+ /*@ assert file_recovery_new.file_check == &file_check_gpg; */
+ /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */
+ {
+ file_recovery_t file_recovery_new2;
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_gpg(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ /*@ assert file_recovery_new.file_check == &file_check_gpg; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_gpg(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_ico.c b/src/file_ico.c
index 03bebb3..af2ae41 100644
--- a/src/file_ico.c
+++ b/src/file_ico.c
@@ -33,7 +33,6 @@
#include "log.h"
static void register_header_check_ico(file_stat_t *file_stat);
-static int header_check_ico(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_ico= {
.extension="ico",
@@ -54,20 +53,6 @@ static const unsigned char header_ico7[6]= {0x00 , 0x00, 0x01, 0x00, 0x07, 0x00}
static const unsigned char header_ico8[6]= {0x00 , 0x00, 0x01, 0x00, 0x08, 0x00};
static const unsigned char header_ico9[6]= {0x00 , 0x00, 0x01, 0x00, 0x09, 0x00};
-
-static void register_header_check_ico(file_stat_t *file_stat)
-{
- register_header_check(0, header_ico1, sizeof(header_ico1), &header_check_ico, file_stat);
- register_header_check(0, header_ico2, sizeof(header_ico2), &header_check_ico, file_stat);
- register_header_check(0, header_ico3, sizeof(header_ico3), &header_check_ico, file_stat);
- register_header_check(0, header_ico4, sizeof(header_ico4), &header_check_ico, file_stat);
- register_header_check(0, header_ico5, sizeof(header_ico5), &header_check_ico, file_stat);
- register_header_check(0, header_ico6, sizeof(header_ico6), &header_check_ico, file_stat);
- register_header_check(0, header_ico7, sizeof(header_ico7), &header_check_ico, file_stat);
- register_header_check(0, header_ico8, sizeof(header_ico8), &header_check_ico, file_stat);
- register_header_check(0, header_ico9, sizeof(header_ico9), &header_check_ico, file_stat);
-}
-
/*
* http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)
*/
@@ -103,7 +88,7 @@ static int header_check_ico(const unsigned char *buffer, const unsigned int buff
if(le16(ico->reserved)!=0 || le16(ico->type)!=1 || le16(ico->count)==0)
return 0;
for(i=0, ico_dir=(const struct ico_directory*)(ico+1);
- i<le16(ico->count);
+ (const unsigned char *)(ico_dir+1) <= buffer+buffer_size && i<le16(ico->count);
i++, ico_dir++)
{
#ifdef DEBUG_ICO
@@ -157,3 +142,16 @@ static int header_check_ico(const unsigned char *buffer, const unsigned int buff
file_recovery_new->file_check=&file_check_size;
return 1;
}
+
+static void register_header_check_ico(file_stat_t *file_stat)
+{
+ register_header_check(0, header_ico1, sizeof(header_ico1), &header_check_ico, file_stat);
+ register_header_check(0, header_ico2, sizeof(header_ico2), &header_check_ico, file_stat);
+ register_header_check(0, header_ico3, sizeof(header_ico3), &header_check_ico, file_stat);
+ register_header_check(0, header_ico4, sizeof(header_ico4), &header_check_ico, file_stat);
+ register_header_check(0, header_ico5, sizeof(header_ico5), &header_check_ico, file_stat);
+ register_header_check(0, header_ico6, sizeof(header_ico6), &header_check_ico, file_stat);
+ register_header_check(0, header_ico7, sizeof(header_ico7), &header_check_ico, file_stat);
+ register_header_check(0, header_ico8, sizeof(header_ico8), &header_check_ico, file_stat);
+ register_header_check(0, header_ico9, sizeof(header_ico9), &header_check_ico, file_stat);
+}
diff --git a/src/file_jpg.c b/src/file_jpg.c
index 8c8ae08..bf82acd 100644
--- a/src/file_jpg.c
+++ b/src/file_jpg.c
@@ -1449,7 +1449,7 @@ static uint64_t jpg_check_structure(file_recovery_t *file_recovery, const unsign
{
unsigned int offset;
file_recovery->offset_error=0;
- for(offset=file_recovery->blocksize; offset < nbytes && file_recovery->offset_error==0; offset+=file_recovery->blocksize)
+ for(offset=file_recovery->blocksize; offset + 30 < nbytes && file_recovery->offset_error==0; offset+=file_recovery->blocksize)
{
if(buffer[offset]==0xff && buffer[offset+1]==0xd8 && buffer[offset+2]==0xff &&
((buffer[offset+3]==0xe1 && memcmp(&buffer[offset+6], "http://ns.adobe.com/xap/", 24)!=0)
diff --git a/src/file_list.c b/src/file_list.c
index 61a1dd5..f706680 100644
--- a/src/file_list.c
+++ b/src/file_list.c
@@ -121,7 +121,9 @@ extern const file_hint_t file_hint_elf;
extern const file_hint_t file_hint_emf;
extern const file_hint_t file_hint_ess;
extern const file_hint_t file_hint_evt;
+extern const file_hint_t file_hint_evtx;
extern const file_hint_t file_hint_exe;
+extern const file_hint_t file_hint_exr;
extern const file_hint_t file_hint_exs;
extern const file_hint_t file_hint_ext2_sb;
extern const file_hint_t file_hint_ext2_fs;
@@ -458,7 +460,9 @@ file_enable_t list_file_enable[]=
{ .enable=0, .file_hint=&file_hint_emf },
{ .enable=0, .file_hint=&file_hint_ess },
{ .enable=0, .file_hint=&file_hint_evt },
+ { .enable=0, .file_hint=&file_hint_evtx },
{ .enable=0, .file_hint=&file_hint_exe },
+ { .enable=0, .file_hint=&file_hint_exr },
{ .enable=0, .file_hint=&file_hint_exs },
{ .enable=0, .file_hint=&file_hint_ext2_sb },
{ .enable=0, .file_hint=&file_hint_ext2_fs },
diff --git a/src/file_m2ts.c b/src/file_m2ts.c
index ca3a7bf..3a8a456 100644
--- a/src/file_m2ts.c
+++ b/src/file_m2ts.c
@@ -120,7 +120,7 @@ static int header_check_m2ts(const unsigned char *buffer, const unsigned int buf
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_m2ts &&
(file_recovery->data_check==&data_check_ts_192 ||
- file_recovery->blocksize < 5))
+ file_recovery_new->blocksize < 5))
{
header_ignored(file_recovery_new);
return 0;
diff --git a/src/file_mov.c b/src/file_mov.c
index dc9c138..6e71676 100644
--- a/src/file_mov.c
+++ b/src/file_mov.c
@@ -32,12 +32,12 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_mov(file_stat_t *file_stat);
static void register_header_check_mov_mdat(file_stat_t *file_stat);
-static int header_check_mov(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-static int header_check_mov_aux(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
const file_hint_t file_hint_mov= {
.extension="mov",
@@ -57,30 +57,13 @@ const file_hint_t file_hint_mov_mdat= {
.register_header_check=&register_header_check_mov_mdat
};
-static void register_header_check_mov_mdat(file_stat_t *file_stat)
-{
- register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov_aux, file_stat);
-}
-
-static void register_header_check_mov(file_stat_t *file_stat)
-{
- register_header_check(4, (const unsigned char*)"cmov",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"cmvd",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"dcom",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"free",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"ftyp",4, &header_check_mov_aux, file_stat);
- register_header_check(4, (const unsigned char*)"jp2h",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"mdia",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"moov",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"PICT",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"pnot",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"skip",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"stbl",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"trak",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"wide",4, &header_check_mov, file_stat);
- register_header_check(4, (const unsigned char*)"jP ",4, &header_check_mov, file_stat);
-}
+static const char *extension_mp4="mp4";
+static const char *extension_m4p="m4p";
+static const char *extension_3gp="3gp";
+static const char *extension_3g2="3g2";
+static const char *extension_heic="heic";
+static const char *extension_jp2="jp2";
+static const char *extension_cr3="cr3";
struct atom_struct
{
@@ -95,6 +78,10 @@ struct atom64_struct
uint64_t size;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_mov(file_recovery_t *file_recovery)
{
FILE *file;
@@ -107,29 +94,138 @@ static void file_rename_mov(file_recovery_t *file_recovery)
return ;
}
fclose(file);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
buffer[8]='\0';
file_rename(file_recovery, buffer, sizeof(buffer), 4, NULL, 1);
}
-static int header_check_mov(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires buffer_size >= 16;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_mov;
+ @ requires file_recovery->file_size == 0 || file_recovery->calculated_file_size > file_recovery->file_size - 16;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 16);
+ @*/
+static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- if(file_recovery->file_stat!=NULL &&
- file_recovery->file_stat->file_hint==&file_hint_mov &&
- (file_recovery->calculated_file_size == file_recovery->file_size ||
- file_recovery->blocksize < 16))
- { /* PhotoRec is already trying to recover this mov file */
- header_ignored(file_recovery_new);
- return 0;
+ while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
+ file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2)
+ {
+ const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert 0 <= i <= buffer_size - 8 ; */
+ const struct atom_struct *atom=(const struct atom_struct*)&buffer[i];
+ uint64_t atom_size=be32(atom->size);
+ if(atom_size==1)
+ {
+ const struct atom64_struct *atom64;
+ if(i + 16 > buffer_size)
+ {
+ /*@ assert file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size + 16 > buffer_size; */
+ /*@ assert file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 16; */
+ return DC_CONTINUE;
+ }
+ /*@ assert i + 16 <= buffer_size; */
+ atom64=(const struct atom64_struct*)&buffer[i];
+ atom_size=be64(atom64->size);
+ if(atom_size<16)
+ return DC_STOP;
+ }
+ else if(atom_size<8)
+ return DC_STOP;
+ if(atom_size >= 0x80000000)
+ return DC_STOP;
+#ifdef DEBUG_MOV
+ log_trace("file_mov.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n",
+ file_recovery->filename,
+ buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
+ buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
+ (long long unsigned)atom_size,
+ (long long unsigned)file_recovery->calculated_file_size);
+#endif
+ if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t')
+ {
+ file_recovery->calculated_file_size+=atom_size;
+#if 0
+ if(i+8 == buffer_size)
+ {
+ return -((atom_size + buffer_size/2 - 1)/ (buffer_size/2));
+ }
+#endif
+ }
+ else if( (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
+ (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='v' && buffer[i+7]=='d') ||
+ (buffer[i+4]=='d' && buffer[i+5]=='c' && buffer[i+6]=='o' && buffer[i+7]=='m') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='e') ||
+ (buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p') ||
+ (buffer[i+4]=='j' && buffer[i+5]=='p' && buffer[i+6]=='2' && buffer[i+7]=='h') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='i' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='e' && buffer[i+6]=='t' && buffer[i+7]=='a') ||
+ (buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
+ (buffer[i+4]=='P' && buffer[i+5]=='I' && buffer[i+6]=='C' && buffer[i+7]=='T') ||
+ (buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t') ||
+ (buffer[i+4]=='s' && buffer[i+5]=='k' && buffer[i+6]=='i' && buffer[i+7]=='p') ||
+ (buffer[i+4]=='s' && buffer[i+5]=='t' && buffer[i+6]=='b' && buffer[i+7]=='l') ||
+ (buffer[i+4]=='t' && buffer[i+5]=='h' && buffer[i+6]=='u' && buffer[i+7]=='m') ||
+ (buffer[i+4]=='t' && buffer[i+5]=='r' && buffer[i+6]=='a' && buffer[i+7]=='k') ||
+ (buffer[i+4]=='u' && buffer[i+5]=='u' && buffer[i+6]=='i' && buffer[i+7]=='d') ||
+ (buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e') )
+ {
+ file_recovery->calculated_file_size+=atom_size;
+ }
+ else
+ {
+ if(!(buffer[i+4]==0 && buffer[i+5]==0 && buffer[i+6]==0 && buffer[i+7]==0))
+ log_warning("file_mov.c: unknown atom 0x%02x%02x%02x%02x at %llu\n",
+ buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
+ (long long unsigned)file_recovery->calculated_file_size);
+ return DC_STOP;
+ }
}
- return header_check_mov_aux(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new);
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 8; */
+ /*@ assert file_recovery->calculated_file_size > file_recovery->file_size + buffer_size/2 - 8; */
+#ifdef DEBUG_MOV
+ log_trace("file_mov.c: new calculated_file_size %llu\n",
+ (long long unsigned)file_recovery->calculated_file_size);
+#endif
+ return DC_CONTINUE;
}
+/*@
+ @ requires buffer_size >= 16;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mov.extension ||
+ file_recovery_new->extension == extension_3g2 ||
+ file_recovery_new->extension == extension_3gp ||
+ file_recovery_new->extension == extension_cr3 ||
+ file_recovery_new->extension == extension_heic ||
+ file_recovery_new->extension == extension_jp2 ||
+ file_recovery_new->extension == extension_m4p ||
+ file_recovery_new->extension == extension_mp4);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_mov || file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1 && file_recovery_new->extension == file_hint_mov.extension) ==> (file_recovery_new->file_rename == file_rename_mov);
+ @ ensures (\result == 1 && file_recovery_new->extension != file_hint_mov.extension) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1 && (file_recovery_new->extension == extension_jp2 || file_recovery_new->blocksize < 16)) ==> (file_recovery_new->data_check == \null && file_recovery_new->file_check == \null && file_recovery_new->file_rename == \null && file_recovery_new->min_filesize > 0);
+ @ ensures (\result == 1 && file_recovery_new->extension != extension_jp2 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->calculated_file_size > 0 && file_recovery_new->file_check == &file_check_size && file_recovery_new->data_check == &data_check_mov);
+ @*/
static int header_check_mov_aux(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
uint64_t i=0;
- while(i<buffer_size-16)
+ while(i <= buffer_size-16)
{
+ /*@ assert i <= buffer_size - 16; */
const struct atom_struct *atom=(const struct atom_struct*)&buffer[i];
+ uint64_t calculated_file_size;
uint64_t atom_size=be32(atom->size);
if(atom_size==1)
{
@@ -137,47 +233,65 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
atom_size=be64(atom64->size);
if(atom_size<16)
return 0;
+ /*@ assert atom_size >= 16; */
}
else if(atom_size<8)
return 0;
+ /*@ assert 8 <= atom_size; */
+ if(atom_size >= 0x80000000)
+ return 0;
+ /*@ assert 8 <= atom_size < 0x80000000; */
+ calculated_file_size=atom_size+i;
/* check for commun atom type */
if(buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t')
{
if(atom_size != 20)
return 0;
+ /*@ assert atom_size == 20; */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_mov.extension;
file_recovery_new->file_rename=&file_rename_mov;
- if(file_recovery->blocksize < 16)
+ if(file_recovery_new->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
if(buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e')
{
if(atom_size != 8)
return 0;
+ /*@ assert atom_size == 8; */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_mov.extension;
file_recovery_new->file_rename=&file_rename_mov;
- if(file_recovery->blocksize < 16)
+ if(file_recovery_new->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
if(buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v')
{
if(atom_size > 256*256*256)
return 0;
+ /*@ assert atom_size <= 256*256*256; */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_mov.extension;
file_recovery_new->file_rename=&file_rename_mov;
- if(file_recovery->blocksize < 16)
+ if(file_recovery_new->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
/*
if(i==0 && buffer[12]=='m' && buffer[13]=='v' && buffer[14]=='h' && buffer[15]=='d')
{
@@ -188,13 +302,14 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
*/
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
if(buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p')
{
if(atom_size < 20 || (atom_size&3)!=0 || atom_size>256)
return 0;
+ /*@ assert 20 <= atom_size <= 256; */
if(memcmp(&buffer[i+8], "isom", 4)==0 ||
memcmp(&buffer[i+8], "mp41", 4)==0 ||
memcmp(&buffer[i+8], "mp42", 4)==0 ||
@@ -203,92 +318,117 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
memcmp(&buffer[i+8], "M4P", 3)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="mp4";
+ file_recovery_new->extension=extension_mp4;
if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "M4A ", 4)==0)
{
reset_file_recovery(file_recovery_new);
/* acc ? */
- file_recovery_new->extension="m4p";
+ file_recovery_new->extension=extension_m4p;
if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "3gp", 3)==0)
{
/* Video for 3G mobile phone (GSM) */
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="3gp";
+ file_recovery_new->extension=extension_3gp;
if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "3g2", 3)==0)
{
/* Video for 3G mobile phone (CDMA) */
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="3g2";
+ file_recovery_new->extension=extension_3g2;
+ if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
+ return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "heic", 4)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="heic";
+ file_recovery_new->extension=extension_heic;
+ if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
+ return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "jp2 ", 4)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="jp2";
+ file_recovery_new->extension=extension_jp2;
+ file_recovery_new->min_filesize=calculated_file_size;
/* jP + ftyp "jp2 " + jp2h + jp2c (atom_size=0) => no data check */
return 1;
}
else if(memcmp(&buffer[i+8], "qt ", 4)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="mov";
+ file_recovery_new->extension=file_hint_mov.extension;
file_recovery_new->file_rename=&file_rename_mov;
if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
else if(memcmp(&buffer[i+8], "crx ", 4)==0)
{
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="cr3";
- file_recovery_new->file_rename=&file_rename_mov;
+ file_recovery_new->extension=extension_cr3;
if(file_recovery->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
}
if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t')
{
- if(memcmp(buffer, "der.mdat\" anim=\"", 16)==0)
+ if(memcmp(&buffer[i], "der.mdat\" anim=\"", 16)==0)
return 0;
if(file_recovery->file_stat!=NULL &&
buffer[8]=='a' && isprint(buffer[0]) && isprint(buffer[1]) && isprint(buffer[2]) && isprint(buffer[3]))
@@ -299,88 +439,180 @@ static int header_check_mov_aux(const unsigned char *buffer, const unsigned int
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_mov.extension;
file_recovery_new->file_rename=&file_rename_mov;
- if(file_recovery->blocksize < 16)
+ if(file_recovery_new->blocksize < 16)
+ {
+ file_recovery_new->min_filesize=calculated_file_size;
return 1;
+ }
file_recovery_new->data_check=&data_check_mov;
file_recovery_new->file_check=&file_check_size;
- file_recovery_new->calculated_file_size=i+atom_size;
+ file_recovery_new->calculated_file_size=calculated_file_size;
return 1;
}
+ if(atom_size > buffer_size)
+ return 0;
i+=atom_size;
}
return 0;
}
-static data_check_t data_check_mov(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+/*@
+ @ requires buffer_size >= 16;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mov.extension ||
+ file_recovery_new->extension == extension_3g2 ||
+ file_recovery_new->extension == extension_3gp ||
+ file_recovery_new->extension == extension_cr3 ||
+ file_recovery_new->extension == extension_heic ||
+ file_recovery_new->extension == extension_jp2 ||
+ file_recovery_new->extension == extension_m4p ||
+ file_recovery_new->extension == extension_mp4);
+ @ ensures (\result == 1) ==> (valid_read_string(file_recovery_new->extension));
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_mov || file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1 && file_recovery_new->extension == file_hint_mov.extension) ==> (file_recovery_new->file_rename == file_rename_mov);
+ @ ensures (\result == 1 && file_recovery_new->extension != file_hint_mov.extension) ==> (file_recovery_new->file_rename == \null);
+ @ ensures (\result == 1 && (file_recovery_new->extension == extension_jp2 || file_recovery_new->blocksize < 16)) ==> (file_recovery_new->data_check == \null && file_recovery_new->file_check == \null && file_recovery_new->file_rename == \null && file_recovery_new->min_filesize > 0);
+ @ ensures (\result == 1 && file_recovery_new->extension != extension_jp2 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->calculated_file_size > 0 && file_recovery_new->file_check == &file_check_size && file_recovery_new->data_check == &data_check_mov);
+ @*/
+static int header_check_mov(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
- file_recovery->calculated_file_size + 8 <= file_recovery->file_size + buffer_size/2)
- {
- const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
- const struct atom_struct *atom=(const struct atom_struct*)&buffer[i];
- uint64_t atom_size=be32(atom->size);
- if(atom_size==1)
- {
- const struct atom64_struct *atom64=(const struct atom64_struct*)&buffer[i];
- if(file_recovery->calculated_file_size + 16 > file_recovery->file_size + buffer_size/2)
- return DC_CONTINUE;
- atom_size=be64(atom64->size);
- if(atom_size<16)
- return DC_STOP;
- }
- else if(atom_size<8)
- return DC_STOP;
-#ifdef DEBUG_MOV
- log_trace("file_mov.c: %s atom %c%c%c%c (0x%02x%02x%02x%02x) size %llu, calculated_file_size %llu\n",
- file_recovery->filename,
- buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
- buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
- (long long unsigned)atom_size,
- (long long unsigned)file_recovery->calculated_file_size);
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_mov &&
+ (file_recovery->calculated_file_size == file_recovery->file_size ||
+ file_recovery_new->blocksize < 16))
+ { /* PhotoRec is already trying to recover this mov file */
+ header_ignored(file_recovery_new);
+ return 0;
+ }
+ return header_check_mov_aux(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new);
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_mov_mdat(file_stat_t *file_stat)
+{
+ register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov_aux, file_stat);
+}
+
+/*@
+ @ requires \valid(file_stat);
+ @*/
+static void register_header_check_mov(file_stat_t *file_stat)
+{
+ register_header_check(4, (const unsigned char*)"cmov",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"cmvd",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"dcom",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"free",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"ftyp",4, &header_check_mov_aux, file_stat);
+ register_header_check(4, (const unsigned char*)"jp2h",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"mdat",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"mdia",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"moov",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"PICT",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"pnot",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"skip",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"stbl",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"trak",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"wide",4, &header_check_mov, file_stat);
+ register_header_check(4, (const unsigned char*)"jP ",4, &header_check_mov, file_stat);
+}
+
+#if defined(MAIN_mov)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.mov";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
#endif
- if(buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='a' && buffer[i+7]=='t')
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.offset_ok=0;
+ file_recovery_new.checkpoint_status=0;
+ file_recovery_new.location.start=0;
+ file_recovery_new.offset_error=0;
+
+ file_stats.file_hint=&file_hint_mov;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_mov(&file_stats);
+ /*@ assert file_recovery_new.blocksize >= 16; */
+ if(header_check_mov(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert file_recovery_new.blocksize >= 16; */
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.offset_ok == 0; */
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ /*@ assert file_recovery_new.offset_ok == 0; */
+ file_recovery_new.file_stat=&file_stats;
+ if(file_recovery_new.data_check != NULL)
+ {
+ /*@ assert file_recovery_new.data_check == &data_check_mov; */
+ /*@ assert file_recovery_new.file_check == file_check_size; */
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.file_size == 0; */;
+ res_data_check=data_check_mov(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
{
- file_recovery->calculated_file_size+=atom_size;
-#if 0
- if(i+8 == buffer_size)
- {
- return -((atom_size + buffer_size/2 - 1)/ (buffer_size/2));
- }
+ /*@ assert file_recovery_new.calculated_file_size > file_recovery_new.file_size - 16; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
#endif
+ data_check_mov(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
}
- else if( (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
- (buffer[i+4]=='c' && buffer[i+5]=='m' && buffer[i+6]=='v' && buffer[i+7]=='d') ||
- (buffer[i+4]=='d' && buffer[i+5]=='c' && buffer[i+6]=='o' && buffer[i+7]=='m') ||
- (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='a') ||
- (buffer[i+4]=='f' && buffer[i+5]=='r' && buffer[i+6]=='e' && buffer[i+7]=='e') ||
- (buffer[i+4]=='f' && buffer[i+5]=='t' && buffer[i+6]=='y' && buffer[i+7]=='p') ||
- (buffer[i+4]=='j' && buffer[i+5]=='p' && buffer[i+6]=='2' && buffer[i+7]=='h') ||
- (buffer[i+4]=='m' && buffer[i+5]=='d' && buffer[i+6]=='i' && buffer[i+7]=='a') ||
- (buffer[i+4]=='m' && buffer[i+5]=='e' && buffer[i+6]=='t' && buffer[i+7]=='a') ||
- (buffer[i+4]=='m' && buffer[i+5]=='o' && buffer[i+6]=='o' && buffer[i+7]=='v') ||
- (buffer[i+4]=='P' && buffer[i+5]=='I' && buffer[i+6]=='C' && buffer[i+7]=='T') ||
- (buffer[i+4]=='p' && buffer[i+5]=='n' && buffer[i+6]=='o' && buffer[i+7]=='t') ||
- (buffer[i+4]=='s' && buffer[i+5]=='k' && buffer[i+6]=='i' && buffer[i+7]=='p') ||
- (buffer[i+4]=='s' && buffer[i+5]=='t' && buffer[i+6]=='b' && buffer[i+7]=='l') ||
- (buffer[i+4]=='t' && buffer[i+5]=='h' && buffer[i+6]=='u' && buffer[i+7]=='m') ||
- (buffer[i+4]=='t' && buffer[i+5]=='r' && buffer[i+6]=='a' && buffer[i+7]=='k') ||
- (buffer[i+4]=='u' && buffer[i+5]=='u' && buffer[i+6]=='i' && buffer[i+7]=='d') ||
- (buffer[i+4]=='w' && buffer[i+5]=='i' && buffer[i+6]=='d' && buffer[i+7]=='e') )
- {
- file_recovery->calculated_file_size+=atom_size;
- }
- else
+ }
+ /*@ assert file_recovery_new.offset_ok == 0; */
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_mov(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert file_recovery_new.offset_ok == 0; */
+ if(file_recovery_new.file_check != NULL)
+ {
+ /*@ assert file_recovery_new.file_check == file_check_size; */
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
{
- if(!(buffer[i+4]==0 && buffer[i+5]==0 && buffer[i+6]==0 && buffer[i+7]==0))
- log_warning("file_mov.c: unknown atom 0x%02x%02x%02x%02x at %llu\n",
- buffer[i+4],buffer[i+5],buffer[i+6],buffer[i+7],
- (long long unsigned)file_recovery->calculated_file_size);
- return DC_STOP;
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
}
}
-#ifdef DEBUG_MOV
- log_trace("file_mov.c: new calculated_file_size %llu\n",
- (long long unsigned)file_recovery->calculated_file_size);
-#endif
- return DC_CONTINUE;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_mov(&file_recovery_new);
+ return 0;
}
+#endif
diff --git a/src/file_mp3.c b/src/file_mp3.c
index 9cde947..25d688a 100644
--- a/src/file_mp3.c
+++ b/src/file_mp3.c
@@ -31,9 +31,14 @@
#include "common.h"
#include "filegen.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
extern const file_hint_t file_hint_mkv;
extern const file_hint_t file_hint_tiff;
+#endif
static void register_header_check_mp3(file_stat_t *file_stat);
static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
@@ -112,6 +117,22 @@ static const unsigned int bit_rate_table[4][4][16]=
},
};
+#ifndef MAIN_mp3
+/*@
+ @ requires buffer_size >= 10;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check == &data_check_id3);
+ @*/
static int header_check_id3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
if(buffer[0]=='I' && buffer[1]=='D' && buffer[2]=='3' && (buffer[3]==2 || buffer[3]==3 || buffer[3]==4) && buffer[4]==0)
@@ -133,6 +154,7 @@ static int header_check_id3(const unsigned char *buffer, const unsigned int buff
*/
reset_file_recovery(file_recovery_new);
file_recovery_new->calculated_file_size=potential_frame_offset;
+ /*@ assert file_recovery_new->calculated_file_size > 0; */
file_recovery_new->min_filesize=287;
file_recovery_new->data_check=&data_check_id3;
file_recovery_new->extension=file_hint_mp3.extension;
@@ -141,7 +163,26 @@ static int header_check_id3(const unsigned char *buffer, const unsigned int buff
}
return 0;
}
+#endif
+#ifndef MAIN_id3
+/*@
+ @ requires buffer_size >= 6;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_mp3.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size > 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_size == 0);
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 287);
+ @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->file_check == &file_check_size);
+ @ ensures (\result == 1 && file_recovery_new->blocksize >= 16) ==> (file_recovery_new->data_check == &data_check_mp3);
+ @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->file_check == \null);
+ @ ensures (\result == 1 && file_recovery_new->blocksize < 16) ==> (file_recovery_new->data_check == \null);
+ @*/
static int header_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
unsigned int potential_frame_offset=0;
@@ -165,12 +206,16 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
return 0;
if(file_recovery->file_stat!=NULL)
{
- if(file_recovery->file_stat->file_hint==&file_hint_mp3 ||
- file_recovery->file_stat->file_hint==&file_hint_mkv)
+ if(file_recovery->file_stat->file_hint==&file_hint_mp3
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
+ || file_recovery->file_stat->file_hint==&file_hint_mkv
+#endif
+ )
{
header_ignored(file_recovery_new);
return 0;
}
+#if !defined(MAIN_mp3) && !defined(MAIN_id3)
/* RGV values from TIFF may be similar to the beginning of an mp3 */
if(file_recovery->file_stat->file_hint==&file_hint_tiff &&
buffer[0]==buffer[3] && buffer[1]==buffer[4] && buffer[2]==buffer[5])
@@ -178,7 +223,12 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
}
+ /*@ assert nbr == 0; */
+ /*@
+ @ loop invariant 0 <= nbr <= potential_frame_offset <= 2048 + 8065;
+ @*/
while(potential_frame_offset+1 < buffer_size &&
potential_frame_offset+1 < 2048)
{
@@ -195,6 +245,8 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
unsigned int frameLengthInBytes=0;
if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
return 0;
+ /*@ assert 8 <= bit_rate <= 448; */
+ /*@ assert 8000 <= sample_rate <= 48000; */
if(mpeg_layer==MPEG_L3)
{
if(mpeg_version==MPEG_V1)
@@ -212,17 +264,24 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
#endif
if(frameLengthInBytes==0)
return 0;
+ /*@ assert 0 < frameLengthInBytes <= 8065; */
potential_frame_offset+=frameLengthInBytes;
+ /*@ assert potential_frame_offset > 0; */
nbr++;
}
}
if(nbr>1)
{
+ /*@ assert nbr > 1; */
+ /*@ assert potential_frame_offset > 0; */
#ifdef DEBUG_MP3
log_info("header_check_mp3 mp3 found\n");
#endif
reset_file_recovery(file_recovery_new);
+ /*@ assert file_recovery_new->file_check == \null; */
+ /*@ assert file_recovery_new->data_check == \null; */
file_recovery_new->calculated_file_size=potential_frame_offset;
+ /*@ assert file_recovery_new->calculated_file_size > 0; */
file_recovery_new->min_filesize=287;
file_recovery_new->extension=file_hint_mp3.extension;
if(file_recovery_new->blocksize >= 16)
@@ -234,13 +293,25 @@ static int header_check_mp3(const unsigned char *buffer, const unsigned int buff
}
return 0;
}
+#endif
+#ifndef MAIN_mp3
+/*@
+ @ requires buffer_size >= 32;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_id3;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE && file_recovery->data_check==&data_check_id3 ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1);
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @*/
static data_check_t data_check_id3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
file_recovery->calculated_file_size + 1 < file_recovery->file_size + buffer_size/2)
{
- const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
+ const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert 0 <= i < buffer_size - 1 ; */
if(buffer[i]==0)
{ /* Padding is present */
file_recovery->calculated_file_size++;
@@ -249,12 +320,29 @@ static data_check_t data_check_id3(const unsigned char *buffer, const unsigned i
{ /* no more padding or no padding */
file_recovery->data_check=&data_check_mp3;
file_recovery->file_check=&file_check_size;
- return data_check_mp3(buffer, buffer_size, file_recovery);
+ if(data_check_mp3(buffer, buffer_size, file_recovery)!=DC_CONTINUE)
+ return DC_STOP;
+ /*@ assert file_recovery->data_check==&data_check_mp3; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
+ return DC_CONTINUE;
}
}
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 1; */
return DC_CONTINUE;
}
+#endif
+/*@
+ @ requires buffer_size >= 32;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ requires file_recovery->data_check==&data_check_mp3;
+ @ requires file_recovery->file_size == 0 || file_recovery->calculated_file_size >= file_recovery->file_size - 16;
+ @ ensures \result == DC_CONTINUE || \result == DC_STOP;
+ @ ensures \result == DC_CONTINUE ==> (file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16);
+ @*/
+ /* TODO: assigns file_recovery->calculated_file_size; */
static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
#ifdef DEBUG_MP3
@@ -265,7 +353,8 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2)
{
- const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
+ const unsigned int i=file_recovery->calculated_file_size + buffer_size/2 - file_recovery->file_size;
+ /*@ assert 0 <= i < buffer_size - 16 ; */
#ifdef DEBUG_MP3
log_info("data_check_mp3 start i=0x%x buffer_size=0x%x calculated_file_size=%lu file_size=%lu\n",
i, buffer_size,
@@ -290,6 +379,8 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
*/
if(sample_rate==0 || bit_rate==0 || mpeg_layer==MPEG_L1)
return DC_STOP;
+ /*@ assert 8 <= bit_rate <= 448; */
+ /*@ assert 8000 <= sample_rate <= 48000; */
if(mpeg_layer==MPEG_L3)
{
if(mpeg_version==MPEG_V1)
@@ -303,7 +394,9 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
frameLengthInBytes = (12000 * bit_rate / sample_rate + padding)*4;
if(frameLengthInBytes<3)
return DC_STOP;
+ /*@ assert 3 < frameLengthInBytes <= 8065; */
file_recovery->calculated_file_size+=frameLengthInBytes;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else if(buffer[i]=='L' && buffer[i+1]=='Y' && buffer[i+2]=='R' && buffer[i+3]=='I' && buffer[i+4]=='C' && buffer[i+5]=='S' && buffer[i+6]=='B' && buffer[i+7]=='E' && buffer[i+8]=='G' && buffer[i+9]=='I' && buffer[i+10]=='N')
{
@@ -318,16 +411,20 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
The maximum length of the lyrics is 5100 bytes for Lyrics3 and 4096 bytes for Lyrics3 v2.
*/
unsigned int pos_lyrics=0;
- /* FIXME */
- if(file_recovery->calculated_file_size + 5100 >= file_recovery->file_size + buffer_size/2)
- return DC_CONTINUE;
+ if(i + 5100 > buffer_size)
+ return DC_STOP;
+ /*@ assert i + 5100 <= buffer_size; */
if((pos_lyrics=pos_in_mem(&buffer[i], 4096, (const unsigned char*)"LYRICS200", 9)) != 0)
{
+ /*@ assert pos_lyrics > 0; */
file_recovery->calculated_file_size+=pos_lyrics;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else if((pos_lyrics=pos_in_mem(&buffer[i], 5100, (const unsigned char*)"LYRICSEND", 9)) != 0)
{
+ /*@ assert pos_lyrics > 0; */
file_recovery->calculated_file_size+=pos_lyrics;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else
{
@@ -339,42 +436,64 @@ static data_check_t data_check_mp3(const unsigned char *buffer, const unsigned i
}
else if(buffer[i]=='A' && buffer[i+1]=='P' && buffer[i+2]=='E' && buffer[i+3]=='T' && buffer[i+4]=='A' && buffer[i+5]=='G' && buffer[i+6]=='E' && buffer[i+7]=='X')
{ /* APE Tagv2 (APE Tagv1 has no header) http://wiki.hydrogenaudio.org/index.php?title=APE_Tags_Header */
- const unsigned int ape_tag_size = (buffer[i+12] + (buffer[i+13]<<8) + (buffer[i+14]<<16) + (buffer[i+15]<<24))+32;
+ const uint64_t ape_tag_size = (buffer[i+12] | (buffer[i+13]<<8) | (buffer[i+14]<<16) | ((uint64_t)buffer[i+15]<<24))+(uint64_t)32;
file_recovery->calculated_file_size+=ape_tag_size;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else if(buffer[i]=='T' && buffer[i+1]=='A' && buffer[i+2]=='G')
{ /* http://www.id3.org/ID3v1 TAGv1 size = 128 bytes with header "TAG" */
file_recovery->calculated_file_size+=128;
- }
- else if(file_recovery->calculated_file_size > file_recovery->file_size)
- {
- return DC_CONTINUE;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
else
{
const unsigned int MMT_size=search_MMT(buffer,i,buffer_size);
if(MMT_size==0)
return DC_STOP;
+ /*@ assert MMT_size > 0; */
/*
log_info("MusicMatch Tag found at offset 0x%x with size 0x%x \n", file_recovery->calculated_file_size, MMT_size);
*/
file_recovery->calculated_file_size+=MMT_size;
+ /*@ assert file_recovery->calculated_file_size > 0; */
}
}
+ /*@ assert file_recovery->calculated_file_size < file_recovery->file_size - buffer_size/2 || file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
+ /*@ assert file_recovery->calculated_file_size >= file_recovery->file_size + buffer_size/2 - 16; */
return DC_CONTINUE;
}
+/*@
+ @ requires needle_size > 0;
+ @ requires haystack_size > 0;
+ @ requires \valid_read(needle+(0..needle_size-1));
+ @ requires \valid_read(haystack+(0..haystack_size-1));
+ @ ensures \result == 0 || needle_size <= \result <= haystack_size;
+ @ assigns \nothing;
+ @*/
static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
{
unsigned int i;
if(haystack_size < needle_size)
return 0;
+ /*@ assert haystack_size >= needle_size; */
+ /*@
+ @ loop assigns i;
+ @ loop invariant 0 <= i <= haystack_size - needle_size + 1;
+ @ loop variant haystack_size - needle_size - i;
+ @*/
for(i=0; i <= haystack_size - needle_size; i++)
if(memcmp(&haystack[i],needle,needle_size)==0)
return (i+needle_size);
return 0;
}
+/*@
+ @ requires buffer_size > 0;
+ @ requires i <= buffer_size;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ assigns \nothing;
+ @*/
static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i, const unsigned int buffer_size)
{
/*
@@ -397,12 +516,12 @@ static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i
*/
const unsigned char mm_header[10]= {'1','8','2','7','3','6','4','5',0x00, 0x00};
const unsigned char mm_pad_version_info[14] = {0x00,0x00,0x00,0x00,'1','8','2','7','3','6','4','5',0x00,0x00};
- const char *mm_footer="Brava Software Inc.";
- const char *mm_footer_tag="TAG";
+ const char mm_footer[]="Brava Software Inc.";
+ const char mm_footer_tag[]="TAG";
unsigned int size=0;
- unsigned int image_size;
if(i+sizeof(mm_header)>buffer_size)
return 0;
+ /*@ assert i + sizeof(mm_header) <= buffer_size; */
if(memcmp(&buffer[i],mm_header,sizeof(mm_header))==0) // Optional Header
{
size=256;
@@ -412,61 +531,90 @@ static unsigned int search_MMT(const unsigned char *buffer, const unsigned int i
else
{
/* Check image extension */
- if( memcmp(&buffer[i+size]," ",4)!=0 &&
- memcmp(&buffer[i+size],"bmp ",4)!=0 &&
- memcmp(&buffer[i+size],"jpg ",4)!=0)
+ if( memcmp(&buffer[i]," ",4)!=0 &&
+ memcmp(&buffer[i],"bmp ",4)!=0 &&
+ memcmp(&buffer[i],"jpg ",4)!=0)
return 0;
/* log_info("search_MMT: image extension present\n"); */
}
-/* dump_log(&buffer[i+size], buffer_size-(i+size)); */
- /* Image binary */
- image_size = buffer[i+size+4]+(buffer[i+size+5]<<8)+(buffer[i+size+6]<<16)+(buffer[i+size+7]<<24);
- size+=8+image_size;
- /* check null padding + version_info */
- if(i+size+sizeof(mm_pad_version_info)>buffer_size)
- { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
- /* log_trace("search_MMT: partial MusicMatch Tag 1\n"); */
- return 0;
+ {
+ const unsigned int tmp=i+size;
+ const uint32_t *image_size_ptr;
+ uint32_t image_size;
+ if(tmp+8>buffer_size)
+ return 0;
+ /*@ assert tmp + 8 <= buffer_size; */
+ image_size_ptr = (const uint32_t *)&buffer[tmp+4];
+ image_size = le32(*image_size_ptr);
+ /* Check if the image size */
+ if(image_size > 10 * 1024 * 1024)
+ return 0;
+ /*@ assert image_size <= 10 * 1024 * 1024; */
+ /* Image binary */
+ size+=8+image_size;
}
- if(memcmp(&buffer[i+size], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
{
- /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
- return 0;
+ const unsigned int tmp=i+size;
+ /* check null padding + version_info */
+ if(tmp+sizeof(mm_pad_version_info)>buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch Tag 1\n"); */
+ return 0;
+ }
+ /*@ assert tmp + sizeof(mm_pad_version_info) <= buffer_size; */
+ if(memcmp(&buffer[tmp], mm_pad_version_info, sizeof(mm_pad_version_info))!=0)
+ {
+ /* log_trace("search_MMT: mm_pad_version_info not present\n"); */
+ return 0;
+ }
}
size+=4+256; /* padding + version_info */
size+=20; /* data offset */
- /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */
- if(i+size+8132+sizeof(*mm_footer)>buffer_size)
- { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
- /* log_trace("search_MMT: partial MusicMatch 2\n"); */
- return 0;
+ {
+ const unsigned int tmp=i+size;
+ /* check footer for various audio meta-data size: 7868, 7936, 8004, 8132 */
+ if(tmp+8132+sizeof(mm_footer) > buffer_size)
+ { /* FIXME: Is it better to have a partial MusicMatch Tag or none ? */
+ /* log_trace("search_MMT: partial MusicMatch 2\n"); */
+ return 0;
+ }
+ /*@ assert tmp + 8132 + sizeof(mm_footer) <= buffer_size; */
+ if( memcmp(&buffer[tmp+7868], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7868], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7868;
+ else if(memcmp(&buffer[tmp+7936], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+7936], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=7936;
+ else if(memcmp(&buffer[tmp+8004], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8004], mm_footer_tag, sizeof(mm_footer_tag) - 1)==0)
+ size+=8004;
+ else if(memcmp(&buffer[tmp+8132], mm_footer, sizeof(mm_footer)-1)==0 ||
+ memcmp(&buffer[tmp+8132], mm_footer_tag, sizeof(mm_footer_tag)-1)==0)
+ size+=8132;
+ else
+ {
+ /* log_trace("search_MMT: no mm_footer present\n"); */
+ return 0;
+ }
}
- if(memcmp(&buffer[i+size+7868],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+7868],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=7868;
- else if(memcmp(&buffer[i+size+7936],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+7936],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=7936;
- else if(memcmp(&buffer[i+size+8004],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+8004],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=8004;
- else if(memcmp(&buffer[i+size+8132],mm_footer,strlen(mm_footer))==0 ||
- memcmp(&buffer[i+size+8132],mm_footer_tag,strlen(mm_footer_tag))==0)
- size+=8132;
- else
{
- /* log_trace("search_MMT: no mm_footer present\n"); */
- return 0;
+ const unsigned int tmp=i+size;
+ if(tmp + sizeof(mm_footer) > buffer_size)
+ return 0;
+ /*@ assert tmp + sizeof(mm_footer) <= buffer_size; */
+ /* dump_log(&buffer[tmp], 16); */
+ if(memcmp(&buffer[tmp],mm_footer, sizeof(mm_footer)-1)==0)
+ size+=48; /* footer */
+ else
+ size+=0x80; /* TAG footer */
}
- /* dump_log(&buffer[i+size], 16); */
- if(memcmp(&buffer[i+size],mm_footer,strlen(mm_footer))==0)
- size+=48; /* footer */
- else
- size+=0x80; /* TAG footer */
/* log_trace("search_MMT: MMT found size=%u (0x%x)\n", size, size); */
return(size);
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_mp3(file_stat_t *file_stat)
{
static const unsigned char mpeg1_L3_header1[2]= {0xFF, 0xFA};
@@ -475,11 +623,197 @@ static void register_header_check_mp3(file_stat_t *file_stat)
static const unsigned char mpeg2_L3_header2[2]= {0xFF, 0xF3};
static const unsigned char mpeg25_L3_header1[2]={0xFF, 0xE2};
static const unsigned char mpeg25_L3_header2[2]={0xFF, 0xE3};
+#ifndef MAIN_mp3
register_header_check(0, "ID3", 3, &header_check_id3, file_stat);
+#endif
+#ifndef MAIN_id3
register_header_check(0, mpeg1_L3_header1, sizeof(mpeg1_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg1_L3_header2, sizeof(mpeg1_L3_header2), &header_check_mp3, file_stat);
register_header_check(0, mpeg2_L3_header1, sizeof(mpeg2_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg2_L3_header2, sizeof(mpeg2_L3_header2), &header_check_mp3, file_stat);
register_header_check(0, mpeg25_L3_header1, sizeof(mpeg25_L3_header1), &header_check_mp3, file_stat);
register_header_check(0, mpeg25_L3_header2, sizeof(mpeg25_L3_header2), &header_check_mp3, file_stat);
+#endif
+}
+
+#ifdef MAIN_id3
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.mp3";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_mp3;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_mp3(&file_stats);
+ if(header_check_id3(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new) != 1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.extension == file_hint_mp3.extension; */
+ /*@ assert file_recovery_new.calculated_file_size > 0; */
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.min_filesize == 287; */
+ /*@ assert file_recovery_new.data_check == &data_check_id3; */
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_id3(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ /*@ assert file_recovery_new.data_check == &data_check_id3 || file_recovery_new.data_check == &data_check_mp3; */
+ /*@ assert res_data_check == DC_CONTINUE && file_recovery_new.data_check == &data_check_mp3 ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */
+ /*@ assert res_data_check == DC_CONTINUE && file_recovery_new.data_check == &data_check_id3 ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 1); */
+ /*@ assert res_data_check == DC_CONTINUE ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.calculated_file_size >= file_recovery_new.file_size - 16; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ file_recovery_new.data_check(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ if(file_recovery_new.file_stat!=NULL)
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_id3(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ if(file_recovery_new.file_check!=NULL)
+ {
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ (file_recovery_new.file_check)(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&file_recovery_new);
+ }
+ return 0;
}
+#elif defined(MAIN_mp3)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.mp3";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_mp3;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ file_hint_mp3.register_header_check(&file_stats);
+ if(header_check_mp3(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.min_filesize == 287; */
+ /*@ assert file_recovery_new.extension == file_hint_mp3.extension; */
+ /*@ assert file_recovery_new.calculated_file_size > 0; */
+ file_recovery_new.file_stat=&file_stats;
+ if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL &&
+ file_recovery_new.data_check!=NULL)
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_mp3; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ /*@ assert file_recovery_new.file_size <= file_recovery_new.calculated_file_size; */;
+ res_data_check=data_check_mp3(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ /*@ assert res_data_check == DC_CONTINUE ==> (file_recovery_new.calculated_file_size >= file_recovery_new.file_size + BLOCKSIZE - 16); */
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ /*@ assert file_recovery_new.calculated_file_size >= file_recovery_new.file_size - 16; */
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ file_recovery_new.data_check(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ if(file_recovery_new.file_stat!=NULL)
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ header_check_mp3(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ if(file_recovery_new.file_check!=NULL)
+ {
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ (file_recovery_new.file_check)(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert valid_read_string((char *)&file_recovery_new.filename); */
+ (file_recovery_new.file_rename)(&file_recovery_new);
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_orf.c b/src/file_orf.c
index bf3f5b1..71895e8 100644
--- a/src/file_orf.c
+++ b/src/file_orf.c
@@ -54,7 +54,7 @@ static int header_check_orf_IIRO(const unsigned char *buffer, const unsigned int
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_orf.extension;
file_recovery_new->time=get_date_from_tiff_header((const TIFFHeader *)buffer, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
diff --git a/src/file_pf.c b/src/file_pf.c
index 8aab2f1..787a8a6 100644
--- a/src/file_pf.c
+++ b/src/file_pf.c
@@ -31,6 +31,9 @@
#include "types.h"
#include "filegen.h"
#include "common.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_pf(file_stat_t *file_stat);
@@ -54,6 +57,10 @@ struct pf_header
uint32_t unknown2;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
static void file_rename_pf(file_recovery_t *file_recovery)
{
FILE *file;
@@ -69,20 +76,129 @@ static void file_rename_pf(file_recovery_t *file_recovery)
file_rename_unicode(file_recovery, &hdr.name, sizeof(hdr.name), 0, "pf", 0);
}
+/*@
+ @ requires buffer_size >= sizeof(struct pf_header);
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_pf.extension);
+ @ ensures (\result == 1) ==> (file_recovery_new->calculated_file_size >= sizeof(struct pf_header));
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename==&file_rename_pf);
+ @ ensures (\result == 1) ==> (file_recovery_new->data_check==&data_check_size);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check==&file_check_size);
+ @*/
static int header_check_pf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const struct pf_header *pf=(const struct pf_header *)buffer;
+ const unsigned int size=le32(pf->size);
+ if(size < sizeof(struct pf_header))
+ return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_pf.extension;
- file_recovery_new->calculated_file_size=(uint64_t)le32(pf->size);
+ file_recovery_new->calculated_file_size=size;
file_recovery_new->file_rename=&file_rename_pf;
file_recovery_new->data_check=&data_check_size;
file_recovery_new->file_check=&file_check_size;
return 1;
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_pf(file_stat_t *file_stat)
{
static const unsigned char pf_header[7] = {0x00, 0x00, 0x00, 'S', 'C', 'C', 'A'};
register_header_check(1, pf_header,sizeof(pf_header), &header_check_pf, file_stat);
}
+
+#if defined(MAIN_pf)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.pf";
+ unsigned char buffer[BLOCKSIZE];
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_pf;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_pf(&file_stats);
+ if(header_check_pf(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert file_recovery_new.file_size == 0; */
+ /*@ assert file_recovery_new.extension == file_hint_pf.extension; */
+ /*@ assert file_recovery_new.file_rename==&file_rename_pf; */
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ if(file_recovery_new.file_stat!=NULL && file_recovery_new.file_stat->file_hint!=NULL &&
+ file_recovery_new.data_check!=NULL)
+ {
+ unsigned char big_buffer[2*BLOCKSIZE];
+ data_check_t res_data_check=DC_CONTINUE;
+ memset(big_buffer, 0, BLOCKSIZE);
+ memcpy(big_buffer + BLOCKSIZE, buffer, BLOCKSIZE);
+ /*@ assert file_recovery_new.data_check == &data_check_size; */
+ /*@ assert file_recovery_new.file_size == 0; */;
+ res_data_check=data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ file_recovery_new.file_size+=BLOCKSIZE;
+ if(res_data_check == DC_CONTINUE)
+ {
+ memcpy(big_buffer, big_buffer + BLOCKSIZE, BLOCKSIZE);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)big_buffer + BLOCKSIZE, BLOCKSIZE);
+#endif
+ data_check_size(big_buffer, 2*BLOCKSIZE, &file_recovery_new);
+ }
+ }
+ {
+ file_recovery_t file_recovery_new2;
+ /* Test when another file of the same is detected in the next block */
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ #if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_pf(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ file_recovery_new.handle=fopen(fn, "rb");
+ /*@ assert file_recovery_new.file_check == &file_check_size; */
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_size(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ /*@ assert file_recovery_new.file_rename==&file_rename_pf; */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_pf(&file_recovery_new);
+ return 0;
+}
+#endif
diff --git a/src/file_raf.c b/src/file_raf.c
index 7912485..e171c9e 100644
--- a/src/file_raf.c
+++ b/src/file_raf.c
@@ -42,7 +42,7 @@ const file_hint_t file_hint_raf= {
.register_header_check=&register_header_check_raf
};
-/* Documentation source: http://libopenraw.freedesktop.org/wiki/Fuji_RAF/ */
+/* Documentation source: https://libopenraw.pages.freedesktop.org/formats/raf/ */
struct header_raf
{
char magic[16];
@@ -83,16 +83,8 @@ static int header_check_raf(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_raf.extension;
file_recovery_new->calculated_file_size=size;
- if(raf->dir_version[0]=='0' && raf->dir_version[1]=='1')
- {
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- }
- else
- {
- /* The size is bigger than calculated_file_size */
- file_recovery_new->file_check=&file_check_size_min;
- }
+ /* The size is bigger than calculated_file_size */
+ file_recovery_new->file_check=&file_check_size_min;
return 1;
}
diff --git a/src/file_rw2.c b/src/file_rw2.c
index 1310561..4e2cd4f 100644
--- a/src/file_rw2.c
+++ b/src/file_rw2.c
@@ -53,7 +53,7 @@ static int header_check_rw2(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="rw2";
file_recovery_new->time=get_date_from_tiff_header(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
diff --git a/src/file_sig.c b/src/file_sig.c
index 7908d3c..e75a2e8 100644
--- a/src/file_sig.c
+++ b/src/file_sig.c
@@ -42,7 +42,6 @@
#include "log.h"
static void register_header_check_sig(file_stat_t *file_stat);
-static int header_check_sig(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_sig= {
.extension="custom",
@@ -60,14 +59,45 @@ const file_hint_t file_hint_sig= {
typedef struct signature_s signature_t;
struct signature_s
{
+ struct td_list_head list;
const char *extension;
unsigned char *sig;
unsigned int sig_size;
unsigned int offset;
- signature_t *next;
};
-static signature_t *signatures=NULL;
+static signature_t signatures={
+ .list = TD_LIST_HEAD_INIT(signatures.list)
+};
+
+static int signature_cmp(const struct td_list_head *a, const struct td_list_head *b)
+{
+ const signature_t *sig_a=td_list_entry_const(a, const signature_t, list);
+ const signature_t *sig_b=td_list_entry_const(b, const signature_t, list);
+ int res;
+ if(sig_a->sig_size==0 && sig_b->sig_size!=0)
+ return -1;
+ if(sig_a->sig_size!=0 && sig_b->sig_size==0)
+ return 1;
+ res=sig_a->offset-sig_b->offset;
+ if(res!=0)
+ return res;
+ if(sig_a->sig_size<=sig_b->sig_size)
+ {
+ res=memcmp(sig_a->sig,sig_b->sig, sig_a->sig_size);
+ if(res!=0)
+ return res;
+ return 1;
+ }
+ else
+ {
+ res=memcmp(sig_a->sig,sig_b->sig, sig_b->sig_size);
+ if(res!=0)
+ return res;
+ return -1;
+ }
+}
+
static void signature_insert(const char *extension, unsigned int offset, unsigned char *sig, unsigned int sig_size)
{
/* FIXME: small memory leak */
@@ -76,15 +106,15 @@ static void signature_insert(const char *extension, unsigned int offset, unsigne
newsig->sig=sig;
newsig->sig_size=sig_size;
newsig->offset=offset;
- newsig->next=signatures;
- signatures=newsig;
+ td_list_add_sorted(&newsig->list, &signatures.list, signature_cmp);
}
static int header_check_sig(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- signature_t *sig;
- for(sig=signatures; sig!=NULL; sig=sig->next)
+ struct td_list_head *pos;
+ td_list_for_each(pos, &signatures.list)
{
+ const signature_t *sig = td_list_entry(pos, signature_t, list);
if(memcmp(&buffer[sig->offset], sig->sig, sig->sig_size)==0)
{
reset_file_recovery(file_recovery_new);
@@ -179,11 +209,11 @@ static char *str_uint(char *src, unsigned int *resptr)
*resptr=res;
return src;
}
-
}
static char *parse_signature_file(file_stat_t *file_stat, char *pos)
{
+ const unsigned int signatures_empty=td_list_empty(&signatures.list);
while(*pos!='\0')
{
/* skip comments */
@@ -371,7 +401,8 @@ static char *parse_signature_file(file_stat_t *file_stat, char *pos)
log_info("register a signature for %s\n", extension);
memcpy(signature, tmp, signature_size);
register_header_check(offset, signature, signature_size, &header_check_sig, file_stat);
- signature_insert(extension, offset, signature, signature_size);
+ if(signatures_empty)
+ signature_insert(extension, offset, signature, signature_size);
}
else
{
@@ -416,5 +447,3 @@ static void register_header_check_sig(file_stat_t *file_stat)
}
free(buffer);
}
-
-
diff --git a/src/file_tiff.c b/src/file_tiff.c
index 02d0bf7..7599856 100644
--- a/src/file_tiff.c
+++ b/src/file_tiff.c
@@ -38,6 +38,9 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
static void register_header_check_tiff(file_stat_t *file_stat);
@@ -50,6 +53,8 @@ const file_hint_t file_hint_tiff= {
.register_header_check=&register_header_check_tiff
};
+/* @ ensures \result == 1 || \result == 2 || \result == 4 || \result == 8;
+ */
unsigned int tiff_type2size(const unsigned int type)
{
switch(type)
@@ -134,10 +139,16 @@ const char *tag_name(unsigned int tag)
const char *find_tag_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char **potential_error)
{
+ if(tiff_size < sizeof(TIFFHeader))
+ return NULL;
+#ifndef MAIN_tiff_le
if(tiff->tiff_magic==TIFF_BIGENDIAN)
return find_tag_from_tiff_header_be(tiff, tiff_size, tag, potential_error);
- else if(tiff->tiff_magic==TIFF_LITTLEENDIAN)
+#endif
+#ifndef MAIN_tiff_be
+ if(tiff->tiff_magic==TIFF_LITTLEENDIAN)
return find_tag_from_tiff_header_le(tiff, tiff_size, tag, potential_error);
+#endif
return NULL;
}
@@ -161,43 +172,10 @@ static void register_header_check_tiff(file_stat_t *file_stat)
{
static const unsigned char tiff_header_be[4]= { 'M','M',0x00, 0x2a};
static const unsigned char tiff_header_le[4]= { 'I','I',0x2a, 0x00};
- register_header_check(0, tiff_header_be, sizeof(tiff_header_be), &header_check_tiff_be_new, file_stat);
- register_header_check(0, tiff_header_le, sizeof(tiff_header_le), &header_check_tiff_le_new, file_stat);
-}
-
-void file_check_tiff(file_recovery_t *fr)
-{
- static uint64_t calculated_file_size=0;
- TIFFHeader header;
- calculated_file_size = 0;
- if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
- fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
- {
- fr->file_size=0;
- return;
- }
- if(header.tiff_magic==TIFF_LITTLEENDIAN)
- calculated_file_size=header_check_tiff_le(fr, le32(header.tiff_diroff), 0, 0);
- else if(header.tiff_magic==TIFF_BIGENDIAN)
- calculated_file_size=header_check_tiff_be(fr, be32(header.tiff_diroff), 0, 0);
-#ifdef DEBUG_TIFF
- log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size);
- log_info("TIFF Estimated %llu %llx\n", (unsigned long long)calculated_file_size, (unsigned long long)calculated_file_size);
+#ifndef MAIN_tiff_le
+ register_header_check(0, tiff_header_be, sizeof(tiff_header_be), &header_check_tiff_be, file_stat);
+#endif
+#ifndef MAIN_tiff_be
+ register_header_check(0, tiff_header_le, sizeof(tiff_header_le), &header_check_tiff_le, file_stat);
#endif
- if(fr->file_size < calculated_file_size || calculated_file_size==0)
- fr->file_size=0;
- /* PhotoRec isn't yet capable to find the correct filesize for
- * Sony arw and dng,
- * Panasonic raw/rw2,
- * Minolta tif
- * Sony sr2
- * so don't truncate them */
- else if(strcmp(fr->extension,"cr2")==0 ||
- strcmp(fr->extension,"dcr")==0 ||
- strcmp(fr->extension,"nef")==0 ||
- strcmp(fr->extension,"orf")==0 ||
- strcmp(fr->extension,"pef")==0 ||
- (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) ||
- strcmp(fr->extension,"wdp")==0)
- fr->file_size=calculated_file_size;
}
diff --git a/src/file_tiff.h b/src/file_tiff.h
index ed2f86c..aaac994 100644
--- a/src/file_tiff.h
+++ b/src/file_tiff.h
@@ -23,6 +23,8 @@
extern "C" {
#endif
+#define TIFF_ERROR 0xffffffffffffffffull
+
#define TIFF_BIGENDIAN 0x4d4d
#define TIFF_LITTLEENDIAN 0x4949
#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */
@@ -66,16 +68,69 @@ struct ifd_header {
TIFFDirEntry ifd;
} __attribute__ ((gcc_struct, __packed__));
+/*@
+ @ requires tiff_size >= sizeof(TIFFHeader);
+ @ requires \valid_read((const unsigned char *)tiff+(0..tiff_size-1));
+ @*/
time_t get_date_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size);
+
+/*@
+ @ requires \valid_read((const unsigned char *)tiff+(0..tiff_size-1));
+ @*/
const char *find_tag_from_tiff_header(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char **potential_error);
-void file_check_tiff(file_recovery_t *file_recovery);
-const char *find_tag_from_tiff_header_be(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error);
+#ifndef MAIN_tiff_be
+/*@
+ @ requires tiff_size >= sizeof(TIFFHeader);
+ @ requires \valid_read((const unsigned char *)tiff+(0..tiff_size-1));
+ @ requires \valid(potential_error);
+ @*/
const char *find_tag_from_tiff_header_le(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error);
-uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
-uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
-int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
-int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @*/
+void file_check_tiff_le(file_recovery_t *fr);
+
+/*@
+ @ requires buffer_size >= 15;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_le);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @*/
+int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+#endif
+
+#ifndef MAIN_tiff_le
+/*@
+ @ requires tiff_size >= sizeof(TIFFHeader);
+ @ requires \valid_read((const unsigned char *)tiff+(0..tiff_size-1));
+ @ requires \valid(potential_error);
+ @*/
+const char *find_tag_from_tiff_header_be(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error);
+
+/*@
+ @ requires buffer_size >= 15;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_tiff_be);
+ @ ensures (\result == 1) ==> (file_recovery_new->extension != \null);
+ @ ensures (\result == 1) ==> valid_read_string(file_recovery_new->extension);
+ @*/
+int header_check_tiff_be(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+#endif
+
unsigned int tiff_type2size(const unsigned int type);
#ifdef DEBUG_TIFF
const char *tag_name(unsigned int tag);
diff --git a/src/file_tiff_be.c b/src/file_tiff_be.c
index e0b4390..fb4eebc 100644
--- a/src/file_tiff_be.c
+++ b/src/file_tiff_be.c
@@ -38,9 +38,26 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)
extern const file_hint_t file_hint_jpg;
+#endif
+extern const file_hint_t file_hint_tiff;
+static const char *extension_dcr="dcr";
+static const char *extension_dng="dng";
+static const char *extension_nef="nef";
+static const char *extension_pef="pef";
+#ifndef MAIN_tiff_le
+/*@
+ @ requires \valid_read((const unsigned char*)tiff+(0..tiff_size-1));
+ @ requires \valid(potential_error);
+ @ requires \valid_read(hdr);
+ @
+ */
static const char *find_tag_from_tiff_header_be_aux(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error, const struct ifd_header *hdr)
{
const TIFFDirEntry *tmp;
@@ -50,6 +67,7 @@ static const char *find_tag_from_tiff_header_be_aux(const TIFFHeader *tiff, cons
if((const char*)(hdr) <= (const char*)tiff ||
(const char*)(hdr+1) > (const char*)tiff+tiff_size)
return NULL;
+ /*@ assert \valid_read(hdr); */
nbr_fields=be16(hdr->nbr_fields);
for(i=0, tmp=&hdr->ifd;
i < nbr_fields && (const char*)(tmp+1) <= (const char*)tiff+tiff_size;
@@ -76,34 +94,47 @@ const char *find_tag_from_tiff_header_be(const TIFFHeader *tiff, const unsigned
return NULL;
ifd0=(const struct ifd_header *)((const char*)tiff + be32(tiff->tiff_diroff));
/* Bound checking */
- if((const char*)ifd0 < (const char*)tiff ||
- (const char*)(ifd0+1) > (const char*)tiff + tiff_size)
+ if((const char *)ifd0 <= (const char *)tiff ||
+ (const char *)(ifd0 + 1) > (const char *)tiff + tiff_size)
return NULL;
+ /*@ assert \valid_read(ifd0); */
{
const char *tmp=find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, ifd0);
if(tmp)
return tmp;
}
exififd=(const struct ifd_header *)find_tag_from_tiff_header_be_aux(tiff, tiff_size, TIFFTAG_EXIFIFD, potential_error, ifd0);
- if(exififd!=NULL)
+ if((const char *)exififd > (const char *)tiff &&
+ (const char *)(exififd + 1) <= (const char *)tiff + tiff_size)
{
/* Exif */
+ /*@ assert \valid_read(exififd); */
const char *tmp=find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, exififd);
if(tmp)
return tmp;
}
tiff_next_diroff=(const uint32_t *)(&ifd0->ifd + be16(ifd0->nbr_fields));
- if( (const char *)tiff_next_diroff >= (const char *)tiff &&
- (const char *)(tiff_next_diroff + 1) < (const char*)tiff + tiff_size &&
+ if( (const char *)tiff_next_diroff > (const char *)tiff &&
+ (const char *)(tiff_next_diroff + 1) <= (const char*)tiff + tiff_size &&
be32(*tiff_next_diroff)>0)
{
/* IFD1 */
const struct ifd_header *ifd1=(const struct ifd_header*)((const char *)tiff+be32(*tiff_next_diroff));
- return find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ if((const char *)ifd1 > (const char *)tiff &&
+ (const char *)(ifd1 + 1) <= (const char *)tiff + tiff_size)
+ {
+ /*@ assert \valid_read(ifd1); */
+ return find_tag_from_tiff_header_be_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ }
}
return NULL;
}
+/*@
+ @ requires \valid(handle);
+ @ requires \valid_read(entry_strip_offsets);
+ @ requires \valid_read(entry_strip_bytecounts);
+ @*/
static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_offsets, const TIFFDirEntry *entry_strip_bytecounts)
{
const unsigned int nbr=(be32(entry_strip_offsets->tdir_count)<2048?
@@ -114,29 +145,42 @@ static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_off
uint32_t *sizep;
uint64_t max_offset=0;
if(be32(entry_strip_offsets->tdir_count) != be32(entry_strip_bytecounts->tdir_count))
- return -1;
+ return TIFF_ERROR;
if(be32(entry_strip_offsets->tdir_count)==0 ||
be16(entry_strip_offsets->tdir_type)!=4 ||
be16(entry_strip_bytecounts->tdir_type)!=4)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert 0 < nbr <= 2048; */
+#ifdef __FRAMAC__
+ offsetp=(uint32_t *)MALLOC(2048*sizeof(*offsetp));
+#else
offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp));
+#endif
if(fseek(handle, be32(entry_strip_offsets->tdir_offset), SEEK_SET) < 0 ||
fread(offsetp, sizeof(*offsetp), nbr, handle) != nbr)
{
free(offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#ifdef __FRAMAC__
+ sizep=(uint32_t *)MALLOC(2048*sizeof(*sizep));
+#else
sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep));
+#endif
if(fseek(handle, be32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 ||
fread(sizep, sizeof(*sizep), nbr, handle) != nbr)
{
free(offsetp);
free(sizep);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)offsetp, nbr*sizeof(*offsetp));
+ Frama_C_make_unknown((char *)sizep, nbr*sizeof(*sizep));
+#endif
for(i=0; i<nbr; i++)
{
- const uint64_t tmp=be32(offsetp[i]) + be32(sizep[i]);
+ const uint64_t tmp=(uint64_t)be32(offsetp[i]) + be32(sizep[i]);
if(max_offset < tmp)
max_offset=tmp;
}
@@ -145,6 +189,11 @@ static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_off
return max_offset;
}
+/*@
+ @ requires type != 1 || \valid_read((const char *)val);
+ @ requires type != 3 || \valid_read((const char *)val + ( 0 .. 2));
+ @ requires type != 4 || \valid_read((const char *)val + ( 0 .. 4));
+ @*/
static unsigned int tiff_be_read(const void *val, const unsigned int type)
{
switch(type)
@@ -182,12 +231,16 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
if( memcmp(buffer, sign_nikon1, sizeof(sign_nikon1))==0 ||
memcmp(buffer, sign_nikon2, sizeof(sign_nikon2))==0 ||
memcmp(buffer, sign_pentax, sizeof(sign_pentax))==0 )
@@ -198,10 +251,10 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
log_info("tiff_be_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n);
#endif
//sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
+ if(n > (unsigned int)(data_read-2)/12)
n=(data_read-2)/12;
if(n==0)
- return -1;
+ return TIFF_ERROR;
for(i=0;i<n;i++)
{
const uint64_t val=(uint64_t)be32(entry->tdir_count) * tiff_type2size(be16(entry->tdir_type));
@@ -220,7 +273,7 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
{
const uint64_t new_offset=be32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -259,12 +312,19 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
}
#endif
-uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+#ifndef MAIN_tiff_le
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @
+ */
+static uint64_t file_check_tiff_be_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
{
unsigned char buffer[8192];
unsigned int i,n;
int data_read;
- const uint32_t *tiff_next_diroff;
uint64_t max_offset=0;
uint64_t alphaoffset=0;
uint64_t alphabytecount=0;
@@ -278,38 +338,50 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
uint64_t tile_bytecounts=0;
unsigned int tdir_tag_old=0;
unsigned int sorted_tag_error=0;
- const TIFFDirEntry *entry=(const TIFFDirEntry *)&buffer[2];
+ const TIFFDirEntry *entries=(const TIFFDirEntry *)&buffer[2];
const TIFFDirEntry *entry_strip_offsets=NULL;
const TIFFDirEntry *entry_strip_bytecounts=NULL;
const TIFFDirEntry *entry_tile_offsets=NULL;
const TIFFDirEntry *entry_tile_bytecounts=NULL;
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_be(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
+ log_info("file_check_tiff_be_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
#endif
if(depth>4)
- return -1;
+ return TIFF_ERROR;
if(count>16)
- return -1;
+ return TIFF_ERROR;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), fr->handle);
+#if defined(__FRAMAC__)
+ data_read = Frama_C_interval(0, sizeof(buffer));
+ /*@ assert 0 <= data_read <= sizeof(buffer); */
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
n=(buffer[0]<<8)+buffer[1];
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_be(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+ log_info("file_check_tiff_be_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
#endif
- //sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
- n=(data_read-2)/12;
if(n==0)
- return -1;
- for(i=0;i<n;i++)
+ return TIFF_ERROR;
+ /*@ assert sizeof(TIFFDirEntry)==12; */
+ /*@
+ @ loop invariant 0 <= i <=n && i <= (data_read-2)/12;
+ @ loop variant n-i;
+ @*/
+ for(i=0; i < n && i < (unsigned int)(data_read-2)/12; i++)
{
+ const TIFFDirEntry *entry=&entries[i];
+ /*@ assert 0 <= i < n; */
+ /*@ assert \valid_read(entry); */
+ const unsigned int tdir_count=be32(entry->tdir_count);
const unsigned int tdir_tag=be16(entry->tdir_tag);
- const uint64_t val=(uint64_t)be32(entry->tdir_count) * tiff_type2size(be16(entry->tdir_type));
+ const uint64_t val=(uint64_t)tdir_count * tiff_type2size(be16(entry->tdir_type));
#ifdef DEBUG_TIFF
log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx) val=%lu\n",
i,
@@ -317,26 +389,29 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
tdir_tag,
tag_name(tdir_tag),
be16(entry->tdir_type),
- (long unsigned)be32(entry->tdir_count),
+ (long unsigned)tdir_count,
(long unsigned)be32(entry->tdir_offset),
(long unsigned)be32(entry->tdir_offset),
(long unsigned)val);
#endif
if(tdir_tag_old > tdir_tag)
{ /* Entries must be sorted by tag */
- sorted_tag_error++;
- if(sorted_tag_error > 1)
- return -1;
+ if(sorted_tag_error > 0)
+ {
+ return TIFF_ERROR;
+ }
+ else
+ sorted_tag_error=1;
}
if(val>4)
{
const uint64_t new_offset=be32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
- if(be32(entry->tdir_count)==1 && val<=4)
+ if(tdir_count==1 && val<=4)
{
const unsigned int tmp=tiff_be_read(&entry->tdir_offset, be16(entry->tdir_type));
switch(tdir_tag)
@@ -353,29 +428,33 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break;
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
case TIFFTAG_SUBIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
#ifdef ENABLE_TIFF_MAKERNOTE
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_be_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -383,8 +462,9 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
#endif
}
}
- else if(be32(entry->tdir_count) > 1)
+ else if(tdir_count > 1)
{
+ /*@ assert tdir_count > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -392,31 +472,37 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_SUBIFD:
if(be16(entry->tdir_type)==4)
{
- const unsigned int nbr=(be32(entry->tdir_count)<32?be32(entry->tdir_count):32);
+ const unsigned int nbr=(tdir_count<32?tdir_count:32);
+ /*@ assert 2 <= nbr <= 32; */
+ uint32_t subifd_offsetp[32];
unsigned int j;
- uint32_t *subifd_offsetp;
if(fseek(fr->handle, be32(entry->tdir_offset), SEEK_SET) < 0)
{
- return -1;
+ return TIFF_ERROR;
}
- subifd_offsetp=(uint32_t *)MALLOC(nbr*sizeof(*subifd_offsetp));
- if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, fr->handle) != nbr)
+ if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp));
+#endif
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= j <= nbr <=32;
+ @ loop variant nbr-j;
+ @*/
for(j=0; j<nbr; j++)
{
- const uint64_t new_offset=header_check_tiff_be(fr, be32(subifd_offsetp[j]), depth+1, 0);
- if(new_offset==-1)
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, be32(subifd_offsetp[j]), depth+1, 0);
+ if(new_offset==TIFF_ERROR)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
if(max_offset < new_offset)
max_offset = new_offset;
}
- free(subifd_offsetp);
+#endif
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -434,7 +520,6 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
}
tdir_tag_old=tdir_tag;
- entry++;
}
if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount)
max_offset = alphaoffset + alphabytecount;
@@ -451,47 +536,107 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_be(fr->handle, entry_strip_offsets, entry_strip_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_be(fr->handle, entry_tile_offsets, entry_tile_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(be32(*tiff_next_diroff) > 0)
+#ifndef __FRAMAC__
+ if ( 2 + n*12 + 4 <= (unsigned int)data_read)
{
- const uint64_t new_offset=header_check_tiff_be(fr, be32(*tiff_next_diroff), depth+1, count+1);
- if(new_offset != -1 && max_offset < new_offset)
- max_offset=new_offset;
+ /*@ assert n <= (data_read - 6) /12; */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)&entries[n];
+ if(be32(*tiff_next_diroff) > 0)
+ {
+ const uint64_t new_offset=file_check_tiff_be_aux(fr, be32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
+#endif
return max_offset;
}
-int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @*/
+static void file_check_tiff_be(file_recovery_t *fr)
+{
+ static uint64_t calculated_file_size=0;
+ TIFFHeader header;
+ calculated_file_size = 0;
+ if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
+ fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
+ {
+ fr->file_size=0;
+ return;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, sizeof(TIFFHeader));
+#endif
+ if(header.tiff_magic==TIFF_BIGENDIAN)
+ calculated_file_size=file_check_tiff_be_aux(fr, be32(header.tiff_diroff), 0, 0);
+#ifdef DEBUG_TIFF
+ log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size);
+ log_info("TIFF Estimated %llu %llx\n", (unsigned long long)calculated_file_size, (unsigned long long)calculated_file_size);
+#endif
+ if(fr->file_size < calculated_file_size || calculated_file_size==0 || calculated_file_size==TIFF_ERROR)
+ fr->file_size=0;
+ /* PhotoRec isn't yet capable to find the correct filesize for
+ * Sony arw and dng,
+ * Panasonic raw/rw2,
+ * Minolta tif
+ * Sony sr2
+ * so don't truncate them */
+ else if(strcmp(fr->extension,"cr2")==0 ||
+ strcmp(fr->extension,"dcr")==0 ||
+ strcmp(fr->extension,"nef")==0 ||
+ strcmp(fr->extension,"orf")==0 ||
+ strcmp(fr->extension,"pef")==0 ||
+ (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) ||
+ strcmp(fr->extension,"wdp")==0)
+ fr->file_size=calculated_file_size;
+}
+#endif
+
+/*@
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_tiff.extension ||
+ file_recovery_new->extension == extension_dcr ||
+ file_recovery_new->extension == extension_dng ||
+ file_recovery_new->extension == extension_nef ||
+ file_recovery_new->extension == extension_pef);
+ @*/
+int header_check_tiff_be(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const char *potential_error=NULL;
const TIFFHeader *header=(const TIFFHeader *)buffer;
if((uint32_t)be32(header->tiff_diroff) < sizeof(TIFFHeader))
return 0;
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_jpg)
{
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="tif";
+ file_recovery_new->extension=file_hint_tiff.extension;
if(find_tag_from_tiff_header_be(header, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=NULL)
{
/* Adobe Digital Negative, ie. PENTAX K-30 */
- file_recovery_new->extension="dng";
+ file_recovery_new->extension=extension_dng;
}
else
{
@@ -501,14 +646,15 @@ int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buf
{
if( memcmp(tag_make, "PENTAX Corporation ", 20)==0 ||
memcmp(tag_make, "PENTAX ", 20)==0)
- file_recovery_new->extension="pef";
+ file_recovery_new->extension=extension_pef;
else if(memcmp(tag_make, "NIKON CORPORATION", 18)==0)
- file_recovery_new->extension="nef";
+ file_recovery_new->extension=extension_nef;
else if(memcmp(tag_make, "Kodak", 6)==0)
- file_recovery_new->extension="dcr";
+ file_recovery_new->extension=extension_dcr;
}
}
file_recovery_new->time=get_date_from_tiff_header(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->file_check=&file_check_tiff_be;
return 1;
}
+#endif
diff --git a/src/file_tiff_le.c b/src/file_tiff_le.c
index 2a4aa92..899e342 100644
--- a/src/file_tiff_le.c
+++ b/src/file_tiff_le.c
@@ -38,10 +38,29 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)
extern const file_hint_t file_hint_raf;
extern const file_hint_t file_hint_jpg;
+#endif
+extern const file_hint_t file_hint_tiff;
+static const char *extension_arw="arw";
+static const char *extension_cr2="cr2";
+static const char *extension_dng="dng";
+static const char *extension_nef="nef";
+static const char *extension_sr2="sr2";
+
+#ifndef MAIN_tiff_be
+/*@
+ @ requires \valid_read((const unsigned char*)tiff+(0..tiff_size-1));
+ @ requires \valid(potential_error);
+ @ requires \valid_read(hdr);
+ @
+ */
static const char *find_tag_from_tiff_header_le_aux(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error, const struct ifd_header *hdr)
{
const TIFFDirEntry *tmp;
@@ -51,6 +70,7 @@ static const char *find_tag_from_tiff_header_le_aux(const TIFFHeader *tiff, cons
if((const char*)(hdr) <= (const char*)tiff ||
(const char*)(hdr+1) > (const char*)tiff+tiff_size)
return NULL;
+ /*@ assert \valid_read(hdr); */
nbr_fields=le16(hdr->nbr_fields);
for(i=0, tmp=&hdr->ifd;
i < nbr_fields && (const char*)(tmp+1) <= (const char*)tiff+tiff_size;
@@ -77,34 +97,47 @@ const char *find_tag_from_tiff_header_le(const TIFFHeader *tiff, const unsigned
return NULL;
ifd0=(const struct ifd_header *)((const char*)tiff + le32(tiff->tiff_diroff));
/* Bound checking */
- if((const char*)ifd0 < (const char*)tiff ||
- (const char*)(ifd0+1) > (const char*)tiff + tiff_size)
+ if((const char *)ifd0 <= (const char *)tiff ||
+ (const char *)(ifd0 + 1) > (const char *)tiff + tiff_size)
return NULL;
+ /*@ assert \valid_read(ifd0); */
{
const char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd0);
if(tmp)
return tmp;
}
exififd=(const struct ifd_header *)find_tag_from_tiff_header_le_aux(tiff, tiff_size, TIFFTAG_EXIFIFD, potential_error, ifd0);
- if(exififd!=NULL)
+ if((const char *)exififd > (const char *)tiff &&
+ (const char *)(exififd + 1) <= (const char *)tiff + tiff_size)
{
/* Exif */
+ /*@ assert \valid_read(exififd); */
const char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, exififd);
if(tmp)
return tmp;
}
tiff_next_diroff=(const uint32_t *)(&ifd0->ifd + le16(ifd0->nbr_fields));
- if( (const char *)tiff_next_diroff >= (const char *)tiff &&
- (const char *)(tiff_next_diroff + 1) < (const char*)tiff + tiff_size &&
+ if( (const char *)tiff_next_diroff > (const char *)tiff &&
+ (const char *)(tiff_next_diroff + 1) <= (const char*)tiff + tiff_size &&
le32(*tiff_next_diroff)>0)
{
/* IFD1 */
const struct ifd_header *ifd1=(const struct ifd_header*)((const char *)tiff+le32(*tiff_next_diroff));
- return find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ if((const char *)ifd1 > (const char *)tiff &&
+ (const char *)(ifd1 + 1) <= (const char *)tiff + tiff_size)
+ {
+ /*@ assert \valid_read(ifd1); */
+ return find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd1);
+ }
}
return NULL;
}
+/*@
+ @ requires \valid(handle);
+ @ requires \valid_read(entry_strip_offsets);
+ @ requires \valid_read(entry_strip_bytecounts);
+ @*/
static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_offsets, const TIFFDirEntry *entry_strip_bytecounts)
{
const unsigned int nbr=(le32(entry_strip_offsets->tdir_count)<2048?
@@ -115,29 +148,42 @@ static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_off
uint32_t *sizep;
uint64_t max_offset=0;
if(le32(entry_strip_offsets->tdir_count) != le32(entry_strip_bytecounts->tdir_count))
- return -1;
+ return TIFF_ERROR;
if(le32(entry_strip_offsets->tdir_count)==0 ||
le16(entry_strip_offsets->tdir_type)!=4 ||
le16(entry_strip_bytecounts->tdir_type)!=4)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert 0 < nbr <= 2048; */
+#ifdef __FRAMAC__
+ offsetp=(uint32_t *)MALLOC(2048*sizeof(*offsetp));
+#else
offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp));
+#endif
if(fseek(handle, le32(entry_strip_offsets->tdir_offset), SEEK_SET) < 0 ||
fread(offsetp, sizeof(*offsetp), nbr, handle) != nbr)
{
free(offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#ifdef __FRAMAC__
+ sizep=(uint32_t *)MALLOC(2048*sizeof(*sizep));
+#else
sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep));
+#endif
if(fseek(handle, le32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 ||
fread(sizep, sizeof(*sizep), nbr, handle) != nbr)
{
free(offsetp);
free(sizep);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)offsetp, nbr*sizeof(*offsetp));
+ Frama_C_make_unknown((char *)sizep, nbr*sizeof(*sizep));
+#endif
for(i=0; i<nbr; i++)
{
- const uint64_t tmp=le32(offsetp[i]) + le32(sizep[i]);
+ const uint64_t tmp=(uint64_t)le32(offsetp[i]) + le32(sizep[i]);
if(max_offset < tmp)
max_offset=tmp;
}
@@ -146,6 +192,11 @@ static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_off
return max_offset;
}
+/*@
+ @ requires type != 1 || \valid_read((const char *)val);
+ @ requires type != 3 || \valid_read((const char *)val + ( 0 .. 2));
+ @ requires type != 4 || \valid_read((const char *)val + ( 0 .. 4));
+ @*/
static unsigned int tiff_le_read(const void *val, const unsigned int type)
{
switch(type)
@@ -183,12 +234,16 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
if( memcmp(buffer, sign_nikon1, sizeof(sign_nikon1))==0 ||
memcmp(buffer, sign_nikon2, sizeof(sign_nikon2))==0 ||
memcmp(buffer, sign_pentax, sizeof(sign_pentax))==0 )
@@ -199,10 +254,10 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
log_info("tiff_le_makernote(%lu) => %u entries\n", (long unsigned)tiff_diroff, n);
#endif
//sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
+ if(n > (unsigned int)(data_read-2)/12)
n=(data_read-2)/12;
if(n==0)
- return -1;
+ return TIFF_ERROR;
for(i=0;i<n;i++)
{
const uint64_t val=(uint64_t)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type));
@@ -221,7 +276,7 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
{
const uint64_t new_offset=le32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -260,12 +315,19 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
}
#endif
-uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
+#ifndef MAIN_tiff_be
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires valid_read_string(fr->extension);
+ @
+ */
+static uint64_t file_check_tiff_le_aux(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count)
{
unsigned char buffer[8192];
unsigned int i,n;
int data_read;
- const uint32_t *tiff_next_diroff;
uint64_t max_offset=0;
uint64_t alphaoffset=0;
uint64_t alphabytecount=0;
@@ -279,38 +341,50 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
uint64_t tile_bytecounts=0;
unsigned int tdir_tag_old=0;
unsigned int sorted_tag_error=0;
- const TIFFDirEntry *entry=(const TIFFDirEntry *)&buffer[2];
+ const TIFFDirEntry *entries=(const TIFFDirEntry *)&buffer[2];
const TIFFDirEntry *entry_strip_offsets=NULL;
const TIFFDirEntry *entry_strip_bytecounts=NULL;
const TIFFDirEntry *entry_tile_offsets=NULL;
const TIFFDirEntry *entry_tile_bytecounts=NULL;
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_le(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
+ log_info("file_check_tiff_le_aux(fr, %lu, %u, %u)\n", (long unsigned)tiff_diroff, depth, count);
#endif
if(depth>4)
- return -1;
+ return TIFF_ERROR;
if(count>16)
- return -1;
+ return TIFF_ERROR;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(fr->handle, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), fr->handle);
+#if defined(__FRAMAC__)
+ data_read = Frama_C_interval(0, sizeof(buffer));
+ /*@ assert 0 <= data_read <= sizeof(buffer); */
+ Frama_C_make_unknown((char *)buffer, sizeof(buffer));
+#endif
if(data_read<2)
- return -1;
- n=buffer[0]+(buffer[1]<<8);
+ return TIFF_ERROR;
+ /*@ assert 2 <= data_read <= sizeof(buffer); */
+ n=buffer[0] | (buffer[1]<<8);
#ifdef DEBUG_TIFF
- log_info("header_check_tiff_le(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
+ log_info("file_check_tiff_le_aux(fr, %lu, %u, %u) => %u entries\n", (long unsigned)tiff_diroff, depth, count, n);
#endif
- //sizeof(TIFFDirEntry)=12;
- if(n > (unsigned)(data_read-2)/12)
- n=(data_read-2)/12;
if(n==0)
- return -1;
- for(i=0;i<n;i++)
+ return TIFF_ERROR;
+ /*@ assert sizeof(TIFFDirEntry)==12; */
+ /*@
+ @ loop invariant 0 <= i <=n && i <= (data_read-2)/12;
+ @ loop variant n-i;
+ @*/
+ for(i=0; i < n && i < (unsigned int)(data_read-2)/12; i++)
{
+ const TIFFDirEntry *entry=&entries[i];
+ /*@ assert 0 <= i < n; */
+ /*@ assert \valid_read(entry); */
+ const unsigned int tdir_count=le32(entry->tdir_count);
const unsigned int tdir_tag=le16(entry->tdir_tag);
- const uint64_t val=(uint64_t)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type));
+ const uint64_t val=(uint64_t)tdir_count * tiff_type2size(le16(entry->tdir_type));
#ifdef DEBUG_TIFF
log_info("%u tag=%u(0x%x) %s type=%u count=%lu offset=%lu(0x%lx) val=%lu\n",
i,
@@ -318,26 +392,30 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
tdir_tag,
tag_name(tdir_tag),
le16(entry->tdir_type),
- (long unsigned)le32(entry->tdir_count),
+ (long unsigned)tdir_count,
(long unsigned)le32(entry->tdir_offset),
(long unsigned)le32(entry->tdir_offset),
(long unsigned)val);
#endif
if(tdir_tag_old > tdir_tag)
- { /* Entries must be sorted by tag, some SR2 file doesn't respected this rule */
- sorted_tag_error++;
- if(sorted_tag_error > 1 && strcmp(fr->extension,"sr2")!=0)
- return -1;
+ { /* Entries must be sorted by tag, some SR2 files don't respect this rule */
+ if(sorted_tag_error > 0)
+ {
+ if(fr->extension != extension_sr2)
+ return TIFF_ERROR;
+ }
+ else
+ sorted_tag_error=1;
}
if(val>4)
{
const uint64_t new_offset=le32(entry->tdir_offset)+val;
if(new_offset==0)
- return -1;
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
- if(le32(entry->tdir_count)==1 && val<=4)
+ if(tdir_count==1 && val<=4)
{
const unsigned int tmp=tiff_le_read(&entry->tdir_offset, le16(entry->tdir_type));
switch(tdir_tag)
@@ -354,36 +432,40 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_TILEOFFSETS: tile_offsets=tmp; break;
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
+#ifndef __FRAMAC__
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
case TIFFTAG_SUBIFD:
- if(fr->extension!=NULL && strcmp(fr->extension, "arw")==0)
+ if(fr->extension == extension_arw)
{
/* DSLR-A100 is boggus, may be A100DataOffset */
if(max_offset < tmp)
max_offset=tmp;
}
+#ifndef __FRAMAC__
else
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
+#endif
break;
#ifdef ENABLE_TIFF_MAKERNOTE
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_le_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -391,8 +473,9 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
#endif
}
}
- else if(le32(entry->tdir_count) > 1)
+ else if(tdir_count > 1)
{
+ /*@ assert tdir_count > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -400,31 +483,37 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_SUBIFD:
if(le16(entry->tdir_type)==4)
{
- const unsigned int nbr=(le32(entry->tdir_count)<32?le32(entry->tdir_count):32);
+ const unsigned int nbr=(tdir_count<32?tdir_count:32);
+ /*@ assert 2 <= nbr <= 32; */
+ uint32_t subifd_offsetp[32];
unsigned int j;
- uint32_t *subifd_offsetp;
if(fseek(fr->handle, le32(entry->tdir_offset), SEEK_SET) < 0)
{
- return -1;
+ return TIFF_ERROR;
}
- subifd_offsetp=(uint32_t *)MALLOC(nbr*sizeof(*subifd_offsetp));
- if(fread(subifd_offsetp, sizeof(*subifd_offsetp), nbr, fr->handle) != nbr)
+ if(fread(subifd_offsetp, sizeof(uint32_t), nbr, fr->handle) != nbr)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&subifd_offsetp, sizeof(subifd_offsetp));
+#endif
+#ifndef __FRAMAC__
+ /*@
+ @ loop invariant 0 <= j <= nbr <=32;
+ @ loop variant nbr-j;
+ @*/
for(j=0; j<nbr; j++)
{
- const uint64_t new_offset=header_check_tiff_le(fr, le32(subifd_offsetp[j]), depth+1, 0);
- if(new_offset==-1)
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, le32(subifd_offsetp[j]), depth+1, 0);
+ if(new_offset==TIFF_ERROR)
{
- free(subifd_offsetp);
- return -1;
+ return TIFF_ERROR;
}
if(max_offset < new_offset)
max_offset = new_offset;
}
- free(subifd_offsetp);
+#endif
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -442,7 +531,6 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
}
tdir_tag_old=tdir_tag;
- entry++;
}
if(alphabytecount > 0 && max_offset < alphaoffset + alphabytecount)
max_offset = alphaoffset + alphabytecount;
@@ -459,59 +547,116 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_le(fr->handle, entry_strip_offsets, entry_strip_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_le(fr->handle, entry_tile_offsets, entry_tile_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(le32(*tiff_next_diroff) > 0)
+#ifndef __FRAMAC__
+ if ( 2 + n*12 + 4 <= (unsigned int)data_read)
{
- const uint64_t new_offset=header_check_tiff_le(fr, le32(*tiff_next_diroff), depth+1, count+1);
- if(new_offset != -1 && max_offset < new_offset)
- max_offset=new_offset;
+ /*@ assert n <= (data_read - 6) /12; */
+ const uint32_t *tiff_next_diroff=(const uint32_t *)&entries[n];
+ if(le32(*tiff_next_diroff) > 0)
+ {
+ const uint64_t new_offset=file_check_tiff_le_aux(fr, le32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
+#endif
return max_offset;
}
-int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+void file_check_tiff_le(file_recovery_t *fr)
{
- const char raf_fp[15]={0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x00, 0x01};
+ static uint64_t calculated_file_size=0;
+ TIFFHeader header;
+ calculated_file_size = 0;
+ if(fseek(fr->handle, 0, SEEK_SET) < 0 ||
+ fread(&header, sizeof(TIFFHeader), 1, fr->handle) != 1)
+ {
+ fr->file_size=0;
+ return;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, sizeof(TIFFHeader));
+#endif
+ if(header.tiff_magic==TIFF_LITTLEENDIAN)
+ calculated_file_size=file_check_tiff_le_aux(fr, le32(header.tiff_diroff), 0, 0);
+#ifdef DEBUG_TIFF
+ log_info("TIFF Current %llu\n", (unsigned long long)fr->file_size);
+ log_info("TIFF Estimated %llu %llx\n", (unsigned long long)calculated_file_size, (unsigned long long)calculated_file_size);
+#endif
+ if(fr->file_size < calculated_file_size || calculated_file_size==0 || calculated_file_size==TIFF_ERROR)
+ fr->file_size=0;
+ /* PhotoRec isn't yet capable to find the correct filesize for
+ * Sony arw and dng,
+ * Panasonic raw/rw2,
+ * Minolta tif
+ * Sony sr2
+ * so don't truncate them */
+ else if(strcmp(fr->extension,"cr2")==0 ||
+ strcmp(fr->extension,"dcr")==0 ||
+ strcmp(fr->extension,"nef")==0 ||
+ strcmp(fr->extension,"orf")==0 ||
+ strcmp(fr->extension,"pef")==0 ||
+ (strcmp(fr->extension,"tif")==0 && calculated_file_size>1024*1024*1024) ||
+ strcmp(fr->extension,"wdp")==0)
+ fr->file_size=calculated_file_size;
+}
+#endif
+
+/*@
+ @ ensures (\result == 1) ==> (file_recovery_new->extension == file_hint_tiff.extension ||
+ file_recovery_new->extension == extension_arw ||
+ file_recovery_new->extension == extension_cr2 ||
+ file_recovery_new->extension == extension_dng ||
+ file_recovery_new->extension == extension_nef ||
+ file_recovery_new->extension == extension_sr2);
+ @*/
+int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const unsigned char raf_fp[15]={0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x00, 0x01};
const char *potential_error=NULL;
const TIFFHeader *header=(const TIFFHeader *)buffer;
if((uint32_t)le32(header->tiff_diroff) < sizeof(TIFFHeader))
return 0;
/* Avoid a false positiv with some RAF files */
if(file_recovery->file_stat!=NULL &&
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)
file_recovery->file_stat->file_hint==&file_hint_raf &&
+#endif
memcmp(buffer, raf_fp, 15)==0)
{
header_ignored(file_recovery_new);
return 0;
}
+#if !defined(MAIN_tiff_be) && !defined(MAIN_tiff_le)
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_jpg)
{
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="tif";
+ file_recovery_new->extension=file_hint_tiff.extension;
/* Canon RAW */
if(buffer[8]=='C' && buffer[9]=='R' && buffer[10]==2)
- file_recovery_new->extension="cr2";
+ file_recovery_new->extension=extension_cr2;
else if(find_tag_from_tiff_header_le(header, buffer_size, TIFFTAG_DNGVERSION, &potential_error)!=NULL)
{
/* Adobe Digital Negative, ie. NIKON D50 */
- file_recovery_new->extension="dng";
+ file_recovery_new->extension=extension_dng;
}
else
{
@@ -523,14 +668,91 @@ int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buf
* sr2 if Sony::FileFormat begins by 1
* arw otherwise */
if(memcmp(tag_make, "SONY", 5)==0)
- file_recovery_new->extension="sr2";
+ file_recovery_new->extension=extension_sr2;
else if(strncmp(tag_make, "SONY ",5)==0)
- file_recovery_new->extension="arw";
- else if(memcmp(tag_make, "NIKON CORPORATION", 18)==0)
- file_recovery_new->extension="nef";
+ file_recovery_new->extension=extension_arw;
+ else if(tag_make < (const char *)buffer + buffer_size - 18 && memcmp(tag_make, "NIKON CORPORATION", 18)==0)
+ file_recovery_new->extension=extension_nef;
}
}
file_recovery_new->time=get_date_from_tiff_header(header, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
+#endif
+
+#if defined(MAIN_tiff_le)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.tif";
+ unsigned char buffer[BLOCKSIZE];
+ int res;
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.extension=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_tiff;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ file_hint_tiff.register_header_check(&file_stats);
+ if(header_check_tiff_le(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert file_recovery_new.file_check == &file_check_tiff_le; */
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert file_recovery_new.extension == file_hint_tiff.extension ||
+ file_recovery_new.extension == extension_arw ||
+ file_recovery_new.extension == extension_cr2 ||
+ file_recovery_new.extension == extension_dng ||
+ file_recovery_new.extension == extension_nef ||
+ file_recovery_new.extension == extension_sr2; */
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.data_check == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */
+ {
+ /*@ assert valid_read_string(file_recovery_new.extension); */
+ file_recovery_t file_recovery_new2;
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ header_check_tiff_le(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert file_recovery_new.file_check == &file_check_tiff_le; */
+ {
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL)
+ {
+ file_check_tiff_le(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/src/file_txt.c b/src/file_txt.c
index f1e7336..19ea286 100644
--- a/src/file_txt.c
+++ b/src/file_txt.c
@@ -33,6 +33,7 @@
#include <time.h>
#endif
#include <ctype.h> /* tolower */
+#include <assert.h>
#include <stdio.h>
#include "types.h"
#include "common.h"
@@ -118,6 +119,11 @@ static const txt_header_t fasttxt_headers[] = {
{ "#! /bin/bash", 12, "sh"},
{ "#! /bin/ksh", 11, "sh"},
{ "#! /bin/sh", 10, "sh"},
+ { "#!/usr/bin/env groovy", 21, "groovy"},
+ { "#!/usr/bin/env perl", 19, "pl"},
+ { "#!/usr/bin/env php", 18, "php"},
+ { "#!/usr/bin/env python", 21, "py"},
+ { "#!/usr/bin/env ruby", 19, "rb"},
/* Opera Hotlist bookmark/contact list/notes */
{ "Opera Hotlist version 2.0", 25, "adr"},
/* Microsoft VB Class module */
@@ -771,10 +777,31 @@ static data_check_t data_check_xml_utf8(const unsigned char *buffer, const unsig
static int header_check_xml_utf8(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
+ const char *tmp;
+ /* buffer may not be null-terminated */
+ char *buf=(char *)MALLOC(buffer_size+1);
+ memcpy(buf, buffer, buffer_size);
+ buf[buffer_size]='\0';
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_xml_utf8;
- file_recovery_new->extension="xml";
+ file_recovery_new->extension=NULL;
+ tmp=strchr(buf,'<');
+ while(tmp!=NULL && file_recovery_new->extension==NULL)
+ {
+ if(strncasecmp(tmp, "<Archive name=\"Root\">", 8)==0)
+ {
+ /* Grasshopper archive */
+ file_recovery_new->extension="ghx";
+ }
+ tmp++;
+ tmp=strchr(tmp,'<');
+ }
+ if(file_recovery_new->extension==NULL)
+ {
+ file_recovery_new->extension="xml";
+ }
file_recovery_new->file_check=&file_check_xml;
+ free(buf);
return 1;
}
@@ -1090,7 +1117,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- /* Dos/Windows bath */
+ /* Dos/Windows batch */
file_recovery_new->extension="bat";
return 1;
}
@@ -1135,6 +1162,15 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
res=(const unsigned char *)memchr(haystack,'\n',ll);
if(res!=NULL)
ll=res-haystack;
+ if(td_memmem(haystack, ll, "groovy", 6) != NULL)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /* Groovy script */
+ file_recovery_new->extension="groovy";
+ return 1;
+ }
if(td_memmem(haystack, ll, "perl", 4) != NULL)
{
reset_file_recovery(file_recovery_new);
@@ -1144,6 +1180,15 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
file_recovery_new->extension="pl";
return 1;
}
+ if(td_memmem(haystack, ll, "php", 3) != NULL)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->data_check=&data_check_txt;
+ file_recovery_new->file_check=&file_check_size;
+ /* PHP script */
+ file_recovery_new->extension="php";
+ return 1;
+ }
if(td_memmem(haystack, ll, "python", 6) != NULL)
{
reset_file_recovery(file_recovery_new);
@@ -1209,7 +1254,7 @@ static int header_check_txt(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->data_check=&data_check_txt;
file_recovery_new->file_check=&file_check_size;
- /* Dos/Windows bath */
+ /* Dos/Windows batch */
file_recovery_new->extension="bat";
return 1;
}
@@ -1470,6 +1515,7 @@ static void register_header_check_fasttxt(file_stat_t *file_stat)
const txt_header_t *header=&fasttxt_headers[0];
while(header->len > 0)
{
+ assert(strlen(header->string) == header->len);
register_header_check(0, header->string, header->len, &header_check_fasttxt, file_stat);
header++;
}
diff --git a/src/file_wdp.c b/src/file_wdp.c
index 7948cc6..f70dd56 100644
--- a/src/file_wdp.c
+++ b/src/file_wdp.c
@@ -52,7 +52,7 @@ static int header_check_wdp(const unsigned char *buffer, const unsigned int buff
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="wdp";
file_recovery_new->time=get_date_from_tiff_header((const TIFFHeader *)buffer, buffer_size);
- file_recovery_new->file_check=&file_check_tiff;
+ file_recovery_new->file_check=&file_check_tiff_le;
return 1;
}
diff --git a/src/file_x3f.c b/src/file_x3f.c
index 896ac1a..0cba13f 100644
--- a/src/file_x3f.c
+++ b/src/file_x3f.c
@@ -31,6 +31,7 @@
#include "filegen.h"
#include "common.h"
+extern const file_hint_t file_hint_x3i;
static void register_header_check_x3f(file_stat_t *file_stat);
static int header_check_x3f(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
@@ -63,8 +64,15 @@ static int header_check_x3f(const unsigned char *buffer, const unsigned int buff
return 0;
if(rotation!=0 && rotation!=90 && rotation!=180 && rotation!=270)
return 0;
+ if(file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_x3i &&
+ safe_header_only==0)
+ {
+ return 0;
+ }
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_x3f.extension;
+ file_recovery_new->min_filesize=1024;
return 1;
}
diff --git a/src/file_x3i.c b/src/file_x3i.c
index b4b9b93..c1a001f 100644
--- a/src/file_x3i.c
+++ b/src/file_x3i.c
@@ -45,6 +45,7 @@ static int header_check_x3i(const unsigned char *buffer, const unsigned int buff
{
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_x3i.extension;
+ file_recovery_new->min_filesize=1024;
return 1;
}
diff --git a/src/file_zip.c b/src/file_zip.c
index ab25947..417bd3d 100644
--- a/src/file_zip.c
+++ b/src/file_zip.c
@@ -22,9 +22,6 @@
Information about ZIP file format: http://www.info-zip.org/doc/appnote-iz-latest.zip
*/
-/* Abolutely required for the zip64 stuff */
-/* #define _FILE_OFFSET_BITS 64 */
-
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -39,10 +36,15 @@
#include "filegen.h"
#include "common.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
/* #define DEBUG_ZIP */
+#ifndef MAIN_zip
extern const file_hint_t file_hint_doc;
+#endif
static void register_header_check_zip(file_stat_t *file_stat);
static int header_check_zip(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
static void file_check_zip(file_recovery_t *file_recovery);
@@ -106,8 +108,13 @@ struct zip64_extra_entry
typedef struct zip_file_entry zip_file_entry_t;
typedef struct zip64_extra_entry zip64_extra_entry_t;
-static uint32_t expected_compressed_size=0;
+static uint64_t expected_compressed_size=0;
+/*@
+ @ requires \valid(f);
+ @ requires 0 < size <= 4096;
+ @ requires \valid_read((const char *)needle + (0 .. size-1));
+ @*/
static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size)
{
char *buffer =(char *)MALLOC(4096);
@@ -118,26 +125,39 @@ static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size
while (!feof(f))
{
- int count = 0;
- unsigned int left;
- const unsigned int read_size= fread(buffer, 1, 4096, f);
- left = read_size;
-
- while (left>=size)
+ const size_t read_size=fread(buffer, 1, 4096, f);
+ if(read_size <= 0 || total > (0x7fffffffffffffff - 4096))
+ {
+ free(buffer);
+ return -1;
+ }
+ /*@ assert 0 < read_size <= 4096; */
+ /*@ assert total <= 0x8000000000000000 - 4096; */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(buffer, 4096);
+#endif
+ if(read_size >= size)
{
- if (buffer[count]==*(const char *)needle && memcmp(buffer+count, needle, size)==0)
+ /*@ assert read_size >= size; */
+ unsigned int count = 0;
+ /*@
+ @ loop invariant 0 <= count <= read_size - size + 1;
+ @ loop variant read_size - size - count;
+ @*/
+ for(count=0; count <= read_size - size; count++)
{
- free(buffer);
- if(my_fseek(f, (off_t)count-read_size, SEEK_CUR)<0)
+ if (buffer[count]==*(const char *)needle && memcmp(buffer+count, needle, size)==0)
{
- log_trace("zip: file_get_pos count-read failed\n");
- return -1;
+ free(buffer);
+ if(my_fseek(f, (off_t)count-(off_t)read_size, SEEK_CUR)<0)
+ {
+ log_trace("zip: file_get_pos count-read failed\n");
+ return -1;
+ }
+ return total+count;
}
- return total;
}
- count++;
- total++;
- left--;
+ total+=count;
}
if(feof(f) || my_fseek(f, (off_t)1-size, SEEK_CUR)<0)
{
@@ -150,6 +170,173 @@ static int64_t file_get_pos(FILE *f, const void* needle, const unsigned int size
return -1;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid(ext);
+ @ requires \valid(krita);
+ @ requires fr->file_size < 0x8000000000000000 - 65535;
+ @ requires 0 < len <= 65535;
+ @ ensures fr->file_size < 0x8000000000000000;
+ @ ensures \result == -1 || \result == 0;
+ @ ensures *krita==0 || *krita==19;
+ @*/
+static int zip_parse_file_entry_fn(file_recovery_t *fr, const char **ext, const unsigned int file_nbr, const zip_file_entry_t file, const uint64_t len, unsigned int *krita)
+{
+#ifdef __FRAMAC__
+ char *filename=(char *)MALLOC(65535+1);
+#else
+ char *filename=(char *)MALLOC(len+1);
+#endif
+ *krita=0;
+ if (fread(filename, len, 1, fr->handle) != 1)
+ {
+#ifdef DEBUG_ZIP
+ log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
+#endif
+ free(filename);
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(filename, len);
+#endif
+ fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
+ filename[len]='\0';
+ if(first_filename[0]=='\0')
+ {
+ const unsigned int len_tmp=(len<255?len:255);
+ strncpy(first_filename, filename, len_tmp);
+ first_filename[len_tmp]='\0';
+ }
+#ifdef DEBUG_ZIP
+ log_info("%s\n", filename);
+#endif
+ if(*ext==NULL)
+ {
+ static int msoffice=0;
+ static int sh3d=0;
+ static const char *ext_msoffice=NULL;
+ if(file_nbr==0)
+ {
+ msoffice=0;
+ sh3d=0;
+ ext_msoffice=NULL;
+ }
+ if(len==19 && memcmp(filename, "[Content_Types].xml", 19)==0)
+ msoffice=1;
+ else if(file_nbr==0)
+ {
+ if(len==8 && memcmp(filename, "mimetype", 8)==0 && le16(file.extra_length)==0)
+ {
+ unsigned char buffer[128];
+ const unsigned int compressed_size=le32(file.compressed_size);
+ const int to_read=(compressed_size < 128 ? compressed_size: 128);
+ if( fread(buffer, to_read, 1, fr->handle)!=1)
+ {
+#ifdef DEBUG_ZIP
+ log_trace("zip: Unexpected EOF in file_entry data: %u bytes expected\n",
+ compressed_size);
+#endif
+ free(filename);
+ return -1;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(buffer, 128);
+#endif
+ if (my_fseek(fr->handle, -to_read, SEEK_CUR) < 0)
+ {
+ log_info("fseek failed\n");
+ free(filename);
+ return -1;
+ }
+ if(compressed_size==16 && memcmp(buffer,"image/openraster",16)==0)
+ *ext="ora";
+ else if(compressed_size==20 && memcmp(buffer,"application/epub+zip",20)==0)
+ *ext="epub";
+ else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.calc",28)==0)
+ *ext="sxc";
+ else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.draw",28)==0)
+ *ext="sxd";
+ else if(compressed_size==31 && memcmp(buffer,"application/vnd.sun.xml.impress",31)==0)
+ *ext="sxi";
+ else if(compressed_size==30 && memcmp(buffer,"application/vnd.sun.xml.writer",30)==0)
+ *ext="sxw";
+ else if(compressed_size==39 && memcmp(buffer,"application/vnd.oasis.opendocument.text",39)==0)
+ *ext="odt";
+ else if(compressed_size==43 && memcmp(buffer,"application/vnd.oasis.opendocument.graphics",43)==0)
+ *ext="odg";
+ else if(compressed_size==46 && memcmp(buffer,"application/vnd.oasis.opendocument.spreadsheet",46)==0)
+ *ext="ods";
+ else if(compressed_size==47 && memcmp(buffer,"application/vnd.oasis.opendocument.presentation",47)==0)
+ *ext="odp";
+ else if(memcmp(buffer,"application/x-krita",19)==0)
+ {
+ *ext="kra";
+ *krita=19;
+ }
+ else
+ { /* default to writer */
+ *ext="sxw";
+ }
+ }
+ /* Zipped Keyhole Markup Language (KML) used by Google Earth */
+ else if(len==7 && memcmp(filename, "doc.kml", 7)==0)
+ *ext="kmz";
+ else if(len==4 && memcmp(filename, "Home", 4)==0)
+ sh3d=1;
+ /* Celtx, Screenwriting & Media Pre-production file */
+ else if(len==9 && memcmp(filename, "local.rdf", 9)==0)
+ *ext="celtx";
+ else if(len==13 && memcmp(filename, "document.json", 13)==0)
+ *ext="sketch";
+ }
+ else if(file_nbr==1 && sh3d==1)
+ {
+ if(len==1 && filename[0]=='0')
+ *ext="sh3d";
+ }
+ if(strncmp(filename, "word/", 5)==0)
+ ext_msoffice="docx";
+ else if(strncmp(filename, "xl/", 3)==0)
+ ext_msoffice="xlsx";
+ else if(strncmp(filename, "ppt/", 4)==0)
+ ext_msoffice="pptx";
+ else if(strncmp(filename, "visio/", 6)==0)
+ ext_msoffice="vsdx";
+ if(msoffice && ext_msoffice!=NULL)
+ *ext=ext_msoffice;
+ }
+ if(*ext==NULL)
+ {
+ /* iWork */
+ if(len==23 && memcmp(filename, "QuickLook/Thumbnail.jpg", 23)==0)
+ *ext="pages";
+ else if(len==20 && strncasecmp(filename, "META-INF/MANIFEST.MF", 20)==0)
+ *ext="jar";
+ else if(len==15 && strncasecmp(filename, "chrome.manifest", 15)==0)
+ *ext="xpi";
+ /* SMART Notebook */
+ else if(len==15 && memcmp(filename, "imsmanifest.xml", 15)==0)
+ *ext="notebook";
+ /* Apple Numbers */
+ else if(len==18 && memcmp(filename, "Index/Document.iwa", 18)==0)
+ *ext="numbers";
+ else if(len==19 && memcmp(filename, "AndroidManifest.xml", 19)==0)
+ *ext="apk";
+ else if(len==30 && memcmp(filename, "xsd/MindManagerApplication.xsd", 30)==0)
+ *ext="mmap";
+ }
+ free(filename);
+ return 0;
+}
+
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid(ext);
+ @ requires fr->file_size < 0x8000000000000000 + 4;
+ @*/
static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const unsigned int file_nbr)
{
zip_file_entry_t file;
@@ -163,6 +350,9 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&file, sizeof(file));
+#endif
fr->file_size += sizeof(file);
#ifdef DEBUG_ZIP
log_info("%u Comp=%u %u CRC32=0x%08X extra_length=%u ",
@@ -180,140 +370,20 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
if(fr->time < tmp)
fr->time=tmp;
}
+ if(fr->file_size + 65535 >= 0x8000000000000000)
+ {
+ return -1;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 65535; */
len = le16(file.filename_length);
if (len)
{
- char *filename=(char *)MALLOC(len+1);
- if (fread(filename, len, 1, fr->handle) != 1)
- {
-#ifdef DEBUG_ZIP
- log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
-#endif
- free(filename);
+ /*@ assert 0 < len <= 65535; */
+ if(zip_parse_file_entry_fn(fr, ext, file_nbr, file, len, &krita) < 0)
return -1;
- }
- fr->file_size += len;
- filename[len]='\0';
- if(first_filename[0]=='\0')
- {
- const unsigned int len_tmp=(len<255?len:255);
- strncpy(first_filename, filename, len_tmp);
- first_filename[len_tmp]='\0';
- }
-#ifdef DEBUG_ZIP
- log_info("%s\n", filename);
-#endif
- if(*ext==NULL)
- {
- static int msoffice=0;
- static int sh3d=0;
- static const char *ext_msoffice=NULL;
- if(file_nbr==0)
- {
- msoffice=0;
- sh3d=0;
- ext_msoffice=NULL;
- }
- if(len==19 && memcmp(filename, "[Content_Types].xml", 19)==0)
- msoffice=1;
- else if(file_nbr==0)
- {
- if(len==8 && memcmp(filename, "mimetype", 8)==0 && le16(file.extra_length)==0)
- {
- unsigned char buffer[128];
- const unsigned int compressed_size=le32(file.compressed_size);
- const int to_read=(compressed_size < 128 ? compressed_size: 128);
- if( fread(buffer, to_read, 1, fr->handle)!=1)
- {
-#ifdef DEBUG_ZIP
- log_trace("zip: Unexpected EOF in file_entry data: %u bytes expected\n",
- compressed_size);
-#endif
- free(filename);
- return -1;
- }
- if (my_fseek(fr->handle, -to_read, SEEK_CUR) < 0)
- {
- log_info("fseek failed\n");
- free(filename);
- return -1;
- }
- if(compressed_size==16 && memcmp(buffer,"image/openraster",16)==0)
- *ext="ora";
- else if(compressed_size==20 && memcmp(buffer,"application/epub+zip",20)==0)
- *ext="epub";
- else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.calc",28)==0)
- *ext="sxc";
- else if(compressed_size==28 && memcmp(buffer,"application/vnd.sun.xml.draw",28)==0)
- *ext="sxd";
- else if(compressed_size==31 && memcmp(buffer,"application/vnd.sun.xml.impress",31)==0)
- *ext="sxi";
- else if(compressed_size==30 && memcmp(buffer,"application/vnd.sun.xml.writer",30)==0)
- *ext="sxw";
- else if(compressed_size==39 && memcmp(buffer,"application/vnd.oasis.opendocument.text",39)==0)
- *ext="odt";
- else if(compressed_size==43 && memcmp(buffer,"application/vnd.oasis.opendocument.graphics",43)==0)
- *ext="odg";
- else if(compressed_size==46 && memcmp(buffer,"application/vnd.oasis.opendocument.spreadsheet",46)==0)
- *ext="ods";
- else if(compressed_size==47 && memcmp(buffer,"application/vnd.oasis.opendocument.presentation",47)==0)
- *ext="odp";
- else if(memcmp(buffer,"application/x-krita",19)==0)
- {
- *ext="kra";
- krita=19;
- }
- else
- { /* default to writer */
- *ext="sxw";
- }
- }
- /* Zipped Keyhole Markup Language (KML) used by Google Earth */
- else if(len==7 && memcmp(filename, "doc.kml", 7)==0)
- *ext="kmz";
- else if(len==4 && memcmp(filename, "Home", 4)==0)
- sh3d=1;
- /* Celtx, Screenwriting & Media Pre-production file */
- else if(len==9 && memcmp(filename, "local.rdf", 9)==0)
- *ext="celtx";
- else if(len==13 && memcmp(filename, "document.json", 13)==0)
- *ext="sketch";
- }
- else if(file_nbr==1 && sh3d==1)
- {
- if(len==1 && filename[0]=='0')
- *ext="sh3d";
- }
- if(strncmp(filename, "word/", 5)==0)
- ext_msoffice="docx";
- else if(strncmp(filename, "xl/", 3)==0)
- ext_msoffice="xlsx";
- else if(strncmp(filename, "ppt/", 4)==0)
- ext_msoffice="pptx";
- else if(strncmp(filename, "visio/", 6)==0)
- ext_msoffice="vsdx";
- if(msoffice && ext_msoffice!=NULL)
- *ext=ext_msoffice;
- }
- if(*ext==NULL)
- {
- /* iWork */
- if(len==23 && memcmp(filename, "QuickLook/Thumbnail.jpg", 23)==0)
- *ext="pages";
- else if(len==20 && strncasecmp(filename, "META-INF/MANIFEST.MF", 20)==0)
- *ext="jar";
- else if(len==15 && strncasecmp(filename, "chrome.manifest", 15)==0)
- *ext="xpi";
- /* SMART Notebook */
- else if(len==15 && memcmp(filename, "imsmanifest.xml", 15)==0)
- *ext="notebook";
- else if(len==19 && memcmp(filename, "AndroidManifest.xml", 19)==0)
- *ext="apk";
- else if(len==30 && memcmp(filename, "xsd/MindManagerApplication.xsd", 30)==0)
- *ext="mmap";
- }
- free(filename);
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
#ifdef DEBUG_ZIP
log_info("\n");
#endif
@@ -321,12 +391,21 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
memset(&extra, 0, sizeof(extra));
if (len>0)
{
+ /*@ assert 0 < len <= 65535; */
+ if(fr->file_size + 65535 >= 0x8000000000000000)
+ {
+ return -1;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 65535; */
if (fread(&extra, sizeof(extra), 1, fr->handle) != 1)
{
#ifdef DEBUG_ZIP
log_trace("zip: Unexpected EOF in file_entry header: %lu bytes expected\n", len);
#endif
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&extra, sizeof(extra));
+#endif
if (my_fseek(fr->handle, fr->file_size, SEEK_SET) == -1 ||
my_fseek(fr->handle, len, SEEK_CUR) == -1)
{
@@ -336,11 +415,15 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
return -1;
}
fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
len = le32(file.compressed_size);
if(len==0xffffffff && le16(extra.tag)==1)
{
len = le64(extra.compressed_size);
+ if(len >= 0x8000000000000000)
+ return -1;
/* Avoid endless loop */
if( fr->file_size + len < fr->file_size)
return -1;
@@ -349,6 +432,10 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
len=krita;
if (len>0)
{
+ /*@ assert len < 0x8000000000000000; */
+ if(fr->file_size + len >= 0x8000000000000000)
+ return -1;
+ /*@ assert fr->file_size + len < 0x8000000000000000; */
if (my_fseek(fr->handle, len, SEEK_CUR) == -1)
{
#ifdef DEBUG_ZIP
@@ -359,8 +446,11 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
#ifdef DEBUG_ZIP
log_trace("zip: Data of length %lu\n", len);
#endif
+ /*@ assert fr->file_size + len < 0x8000000000000000; */
fr->file_size += len;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
expected_compressed_size=len;
if (file.has_descriptor && (le16(file.compression)==8 || le16(file.compression)==9))
{
@@ -379,13 +469,22 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
return -1;
if (pos > 0)
{
+ if(fr->file_size + pos > 0x7fffffffffffffff)
+ return -1;
fr->file_size += pos;
expected_compressed_size=pos;
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_central_dir(file_recovery_t *fr)
{
zip_file_entry_t file;
@@ -414,6 +513,9 @@ static int zip_parse_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&file, sizeof(file));
+#endif
fr->file_size += sizeof(file);
#ifdef DEBUG_ZIP
log_trace("zip: Central dir with CRC 0x%08X\n", file.crc32);
@@ -426,6 +528,9 @@ static int zip_parse_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
/* Rest of the block - could attempt CRC check */
@@ -444,6 +549,12 @@ static int zip_parse_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires fr->file_size < 0x8000000000000000;
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip64_parse_end_central_dir(file_recovery_t *fr)
{
struct {
@@ -465,11 +576,16 @@ static int zip64_parse_end_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
if (dir.end_size > 0)
{
const uint64_t len = le64(dir.end_size);
+ if(len >= 0x8000000000000000 - sizeof(dir) - 4)
+ return -1;
/* Avoid endless loop */
if( fr->file_size + len <= fr->file_size)
return -1;
@@ -489,6 +605,11 @@ static int zip64_parse_end_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_end_central_dir(file_recovery_t *fr)
{
struct {
@@ -508,6 +629,9 @@ static int zip_parse_end_central_dir(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&dir, sizeof(dir));
+#endif
fr->file_size += sizeof(dir);
if (dir.comment_length)
@@ -528,6 +652,11 @@ static int zip_parse_end_central_dir(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_data_desc(file_recovery_t *fr)
{
struct {
@@ -543,6 +672,9 @@ static int zip_parse_data_desc(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&desc, sizeof(desc));
+#endif
fr->file_size += sizeof(desc);
#ifdef DEBUG_ZIP
log_info("compressed_size=%u/%u uncompressed_size=%u CRC32=0x%08X\n",
@@ -556,6 +688,11 @@ static int zip_parse_data_desc(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip_parse_signature(file_recovery_t *fr)
{
uint16_t len;
@@ -567,6 +704,9 @@ static int zip_parse_signature(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&len, 2);
+#endif
fr->file_size += 2;
if (len)
@@ -585,6 +725,11 @@ static int zip_parse_signature(file_recovery_t *fr)
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ ensures \result == -1 || \result == 0;
+ @*/
static int zip64_parse_end_central_dir_locator(file_recovery_t *fr)
{
struct {
@@ -600,10 +745,17 @@ static int zip64_parse_end_central_dir_locator(file_recovery_t *fr)
#endif
return -1;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&loc, sizeof(loc));
+#endif
fr->file_size += sizeof(loc);
return 0;
}
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @*/
static void file_check_zip(file_recovery_t *fr)
{
const char *ext=NULL;
@@ -619,7 +771,13 @@ static void file_check_zip(file_recovery_t *fr)
uint64_t file_size_old;
uint32_t header;
int status;
-
+ if(file_nbr>=0xffffffff || fr->file_size >= 0x8000000000000000 - 4)
+ {
+ fr->offset_error = fr->file_size;
+ fr->file_size = 0;
+ return;
+ }
+ /*@ assert fr->file_size < 0x8000000000000000 - 4; */
if (fread(&header, 4, 1, fr->handle)!=1)
{
#ifdef DEBUG_ZIP
@@ -629,7 +787,9 @@ static void file_check_zip(file_recovery_t *fr)
fr->file_size=0;
return;
}
-
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 4);
+#endif
header = le32(header);
#ifdef DEBUG_ZIP
log_trace("Header 0x%08X at 0x%llx\n", header, (long long unsigned int)fr->file_size);
@@ -637,6 +797,7 @@ static void file_check_zip(file_recovery_t *fr)
#endif
fr->file_size += 4;
file_size_old=fr->file_size;
+ /*@ assert fr->file_size < 0x8000000000000000; */
switch (header)
{
@@ -687,6 +848,10 @@ static void file_check_zip(file_recovery_t *fr)
}
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)file_recovery->filename);
+ @*/
static void file_rename_zip(file_recovery_t *file_recovery)
{
const char *ext=NULL;
@@ -707,6 +872,12 @@ static void file_rename_zip(file_recovery_t *file_recovery)
{
uint32_t header;
int status;
+ if(file_nbr>=0xffffffff || fr.file_size >= 0x8000000000000000 - 4)
+ {
+ fclose(fr.handle);
+ return;
+ }
+ /*@ assert fr.file_size < 0x8000000000000000 - 4; */
if (fread(&header, 4, 1, fr.handle)!=1)
{
@@ -716,6 +887,9 @@ static void file_rename_zip(file_recovery_t *file_recovery)
fclose(fr.handle);
return;
}
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)&header, 4);
+#endif
header = le32(header);
#ifdef DEBUG_ZIP
@@ -788,6 +962,19 @@ static void file_rename_zip(file_recovery_t *file_recovery)
}
}
+/*@
+ @ requires buffer_size >= 85;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 0 || \result == 1;
+ @ ensures (\result == 1) ==> (file_recovery_new->min_filesize == 21);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_check == &file_check_zip || file_recovery_new->file_check == \null);
+ @ ensures (\result == 1) ==> (file_recovery_new->file_rename == &file_rename_zip || file_recovery_new->file_rename == \null);
+ @*/
static int header_check_zip(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
const zip_file_entry_t *file=(const zip_file_entry_t *)&buffer[4];
@@ -795,12 +982,14 @@ static int header_check_zip(const unsigned char *buffer, const unsigned int buff
#ifdef DEBUG_ZIP
log_trace("header_check_zip\n");
#endif
+#ifndef MAIN_zip
if(file_recovery->file_stat!=NULL &&
file_recovery->file_stat->file_hint==&file_hint_doc)
{
if(header_ignored_adv(file_recovery, file_recovery_new)==0)
return 0;
}
+#endif
/* A zip file begins by ZIP_FILE_ENTRY, this signature can also be
* found for each compressed file */
if(file_recovery->file_stat!=NULL &&
@@ -876,6 +1065,18 @@ static int header_check_zip(const unsigned char *buffer, const unsigned int buff
return 1;
}
+/*@
+ @ requires buffer_size >= 85;
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @ requires \valid_read(file_recovery);
+ @ requires file_recovery->file_stat==\null || valid_read_string((char*)file_recovery->filename);
+ @ requires \valid(file_recovery_new);
+ @ requires file_recovery_new->blocksize > 0;
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ ensures \result == 1;
+ @ ensures file_recovery_new->file_check == &file_check_zip;
+ @ ensures file_recovery_new->extension == file_hint_zip.extension;
+ @*/
static int header_check_winzip(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
reset_file_recovery(file_recovery_new);
@@ -884,20 +1085,109 @@ static int header_check_winzip(const unsigned char *buffer, const unsigned int b
return 1;
}
+/*@
+ @ requires haystack_size > 0;
+ @ requires needle_size > 0;
+ @ requires \valid_read(haystack + (0 .. haystack_size-1));
+ @ requires \valid_read(needle + (0 .. needle_size-1));
+ @ assigns \nothing;
+ @ ensures \result <= haystack_size;
+ @*/
static unsigned int pos_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
{
unsigned int i;
if(haystack_size < needle_size)
return 0;
+ /*@
+ @ loop invariant 0 <= i <= haystack_size - needle_size + 1;
+ @ loop assigns i;
+ @ loop variant haystack_size - needle_size - i;
+ @*/
for(i=0; i <= haystack_size - needle_size; i++)
if(memcmp(&haystack[i],needle,needle_size)==0)
return (i+needle_size);
return 0;
}
+/*@
+ @ requires \valid(file_stat);
+ @*/
static void register_header_check_zip(file_stat_t *file_stat)
{
static const unsigned char zip_header2[8] = { 'P', 'K', '0', '0', 'P', 'K', 0x03, 0x04}; /* WinZIPv8-compressed files. */
register_header_check(0, zip_header,sizeof(zip_header), &header_check_zip, file_stat);
register_header_check(0, zip_header2,sizeof(zip_header2), &header_check_winzip, file_stat);
}
+
+#if defined(MAIN_zip)
+#define BLOCKSIZE 65536u
+int main()
+{
+ const char fn[] = "recup_dir.1/f0000000.zip";
+ unsigned char buffer[BLOCKSIZE];
+ int res;
+ file_recovery_t file_recovery_new;
+ file_recovery_t file_recovery;
+ file_stat_t file_stats;
+
+ /*@ assert \valid(buffer + (0 .. (BLOCKSIZE - 1))); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+
+ reset_file_recovery(&file_recovery);
+ /*@ assert file_recovery.file_stat == \null; */
+ file_recovery.blocksize=BLOCKSIZE;
+ file_recovery_new.blocksize=BLOCKSIZE;
+ file_recovery_new.data_check=NULL;
+ file_recovery_new.file_stat=NULL;
+ file_recovery_new.file_check=NULL;
+ file_recovery_new.file_rename=NULL;
+ file_recovery_new.calculated_file_size=0;
+ file_recovery_new.file_size=0;
+ file_recovery_new.location.start=0;
+
+ file_stats.file_hint=&file_hint_zip;
+ file_stats.not_recovered=0;
+ file_stats.recovered=0;
+ register_header_check_zip(&file_stats);
+ if(header_check_zip(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ /*@ assert valid_read_string((char *)&fn); */
+ memcpy(file_recovery_new.filename, fn, sizeof(fn));
+ file_recovery_new.file_stat=&file_stats;
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ /*@ assert file_recovery_new.min_filesize == 21; */
+ /*@ assert file_recovery_new.file_check == &file_check_zip || file_recovery_new.file_check == \null; */
+ /*@ assert file_recovery_new.file_stat->file_hint!=NULL; */
+ {
+ file_recovery_t file_recovery_new2;
+ file_recovery_new2.blocksize=BLOCKSIZE;
+ file_recovery_new2.file_stat=NULL;
+ file_recovery_new2.file_check=NULL;
+ file_recovery_new2.location.start=BLOCKSIZE;
+ file_recovery_new.handle=NULL; /* In theory should be not null */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buffer, BLOCKSIZE);
+#endif
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ header_check_zip(buffer, BLOCKSIZE, 0, &file_recovery_new, &file_recovery_new2);
+ }
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_recovery_new.handle=fopen(fn, "rb");
+ if(file_recovery_new.handle!=NULL && file_recovery_new.file_check !=NULL)
+ {
+ /*@ assert file_recovery_new.file_check == &file_check_zip; */
+ file_check_zip(&file_recovery_new);
+ fclose(file_recovery_new.handle);
+ }
+ if(file_recovery_new.file_rename!=NULL)
+ {
+ /*@ assert file_recovery_new.file_rename == &file_rename_zip; */
+ /*@ assert valid_read_string((char *)file_recovery_new.filename); */
+ file_rename_zip(&file_recovery_new);
+ }
+ return 0;
+}
+#endif
diff --git a/src/filegen.c b/src/filegen.c
index f48f21d..dc12987 100644
--- a/src/filegen.c
+++ b/src/filegen.c
@@ -38,7 +38,6 @@
#include "types.h"
#include "common.h"
#include "filegen.h"
-#include "photorec.h"
#include "log.h"
static file_check_t file_check_plist={
@@ -66,7 +65,7 @@ static int file_check_cmp(const struct td_list_head *a, const struct td_list_hea
res=memcmp(fc_a->value,fc_b->value, (fc_a->length<=fc_b->length?fc_a->length:fc_b->length));
if(res!=0)
return res;
- return fc_b->length-fc_a->length;
+ return (int)fc_b->length-(int)fc_a->length;
}
static void file_check_add_tail(file_check_t *file_check_new, file_check_list_t *pos)
@@ -98,12 +97,12 @@ void register_header_check(const unsigned int offset, const void *value, const u
static void index_header_check_aux(file_check_t *file_check_new)
{
- struct td_list_head *tmp;
- td_list_for_each(tmp, &file_check_list.list)
+ if(file_check_new->length>0)
{
- file_check_list_t *pos=td_list_entry(tmp, file_check_list_t, list);
- if(file_check_new->length>0)
+ struct td_list_head *tmp;
+ td_list_for_each(tmp, &file_check_list.list)
{
+ file_check_list_t *pos=td_list_entry(tmp, file_check_list_t, list);
if(pos->offset >= file_check_new->offset &&
pos->offset < file_check_new->offset+file_check_new->length)
{
@@ -237,7 +236,12 @@ void file_search_footer(file_recovery_t *file_recovery, const void*footer, const
}
#if 0
-void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
+static void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length)
{
const unsigned int read_size=4096;
unsigned char*buffer;
@@ -317,7 +321,6 @@ void reset_file_recovery(file_recovery_t *file_recovery)
file_recovery->file_size=0;
file_recovery->location.list.prev=&file_recovery->location.list;
file_recovery->location.list.next=&file_recovery->location.list;
- file_recovery->location.start=0;
file_recovery->location.end=0;
file_recovery->location.data=0;
file_recovery->extension=NULL;
@@ -330,7 +333,6 @@ void reset_file_recovery(file_recovery_t *file_recovery)
file_recovery->offset_ok=0;
file_recovery->checkpoint_status=0;
file_recovery->checkpoint_offset=0;
-// file_recovery->blocksize=512;
file_recovery->flags=0;
file_recovery->extra=0;
}
@@ -368,9 +370,77 @@ file_stat_t * init_file_stats(file_enable_t *files_enable)
return file_stats;
}
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ /* new_filename is large enough to avoid a buffer overflow */
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=NULL;
+ char *dst;
+ char *directory_sep;
+ int len;
+ len=strlen(src)+1;
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ new_filename=(char*)MALLOC(len);
+ dst=new_filename;
+ directory_sep=new_filename;
+ while(*src!='\0')
+ {
+ if(*src=='/')
+ {
+ directory_sep=dst;
+ ext=NULL;
+ }
+ if(*src=='.')
+ ext=src;
+ *dst++ = *src++;
+ }
+ *dst='\0';
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ if(ext!=NULL)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ }
+ *dst='\0';
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ if(strlen(new_filename)<sizeof(file_recovery->filename))
+ {
+ strcpy(file_recovery->filename, new_filename);
+ }
+ free(new_filename);
+ return 0;
+}
+
/* The original filename begins at offset in buffer and is null terminated */
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
+ /* TODO: make the code from frama-c friendly */
+#ifndef __FRAMAC__
/* new_filename is large enough to avoid a buffer overflow */
char *new_filename;
const char *src=file_recovery->filename;
@@ -475,19 +545,75 @@ int file_rename(file_recovery_t *file_recovery, const void *buffer, const int bu
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
strcpy(file_recovery->filename, new_filename);
}
free(new_filename);
+#endif
+ return 0;
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((const char*)&file_recovery->filename);
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
+static int file_rename_unicode_aux(file_recovery_t *file_recovery, const char *new_ext, const int append_original_ext)
+{
+ char *new_filename;
+ const char *src=file_recovery->filename;
+ const char *ext=src;
+ char *dst;
+ char *directory_sep;
+ unsigned int len=strlen(file_recovery->filename)+1;
+ /*@ assert len < sizeof(file_recovery->filename); */
+ if(new_ext!=NULL)
+ len+=strlen(new_ext);
+ if(len > sizeof(file_recovery->filename))
+ return -1;
+ new_filename=(char*)MALLOC(len);
+ strcpy(new_filename, (char *)&file_recovery->filename);
+ directory_sep=strrchr(file_recovery->filename, '/');
+ ext=strrchr(file_recovery->filename, '.');
+ /*@ assert directory_sep != \null; */
+#if 1
+ dst=directory_sep;
+ while(*dst!='.' && *dst!='\0')
+ dst++;
+ /* Add extension */
+ if(new_ext!=NULL)
+ {
+ src=new_ext;
+ *dst++ = '.';
+ while(*src!='\0')
+ *dst++ = *src++;
+ }
+ else if(append_original_ext>0)
+ {
+ while(*ext!='\0')
+ *dst++ = *ext++;
+ }
+ *dst='\0';
+#endif
+ if(rename(file_recovery->filename, new_filename)<0)
+ {
+ /* Rename has failed */
+ free(new_filename);
+ return -1;
+ }
+ strcpy(file_recovery->filename, new_filename);
+ free(new_filename);
return 0;
}
/* The original filename begins at offset in buffer and is null terminated */
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
+ /* TODO: make the code from frama-c friendly */
+#ifndef __FRAMAC__
/* new_filename is large enough to avoid a buffer overflow */
char *new_filename;
const char *src=file_recovery->filename;
@@ -585,18 +711,25 @@ int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, cons
if(buffer==NULL)
return -1;
/* Try without the original filename */
- return file_rename_unicode(file_recovery, NULL, 0, 0, new_ext, append_original_ext);
+ return file_rename_unicode_aux(file_recovery, new_ext, append_original_ext);
}
if(strlen(new_filename)<sizeof(file_recovery->filename))
{
strcpy(file_recovery->filename, new_filename);
}
free(new_filename);
+#endif
return 0;
}
static uint64_t offset_skipped_header=0;
+void header_ignored_cond_reset(uint64_t start, uint64_t end)
+{
+ if(start <= offset_skipped_header && offset_skipped_header <= end)
+ offset_skipped_header=0;
+}
+
/* 0: file_recovery is bad *
* 1: file_recovery is ok */
int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new)
@@ -612,13 +745,15 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
}
if(file_recovery->handle==NULL)
{
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
+ {
offset_skipped_header=file_recovery_new->location.start;
+ }
return 0;
}
memcpy(&fr_test, file_recovery, sizeof(fr_test));
-#ifdef HAVE_FTELLO
+#if defined(HAVE_FTELLO) && !defined(__FRAMAC__)
if((offset=ftello(file_recovery->handle)) < 0)
offset=ftell(file_recovery->handle);
#else
@@ -626,15 +761,17 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
#endif
assert(offset >= 0);
file_recovery->file_check(&fr_test);
- if(fr_test.file_size>0)
- return 1;
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0)
{
log_error("BUG in header_ignored_adv: my_fseek() failed\n");
return 1;
}
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(fr_test.file_size>0)
+ return 1;
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
+ {
offset_skipped_header=file_recovery_new->location.start;
+ }
return 0;
}
@@ -645,7 +782,7 @@ void header_ignored(const file_recovery_t *file_recovery_new)
offset_skipped_header=0;
return ;
}
- if(file_recovery_new->location.start==0 || offset_skipped_header==0)
+ if(file_recovery_new->location.start < offset_skipped_header || offset_skipped_header==0)
offset_skipped_header=file_recovery_new->location.start;
}
@@ -669,7 +806,7 @@ void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **cur
if(file_space->start < prev_location)
break;
}
-#ifdef DEBUG_HEADER_CHECK
+#ifdef DEBUG_PREV_LOCATION
log_info("get_prev_location_smart: reset offset_skipped_header=%llu, offset=%llu\n",
(long long unsigned)(offset_skipped_header/512),
(long long unsigned)(*offset/512));
@@ -682,24 +819,25 @@ void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **cur
offset_skipped_header=0;
return;
}
+ *current_search_space=file_space;
if(file_space->start < prev_location || file_space->start < offset_skipped_header)
{
-#ifdef DEBUG_HEADER_CHECK
+#ifdef DEBUG_PREV_LOCATION
log_info("get_prev_location_smart: file_space->start < prev_location=%llu (in 512-bytes sectors), offset=%llu\n",
(long long unsigned)(prev_location/512),
(long long unsigned)(*offset/512));
#endif
+ *offset=offset_skipped_header;
offset_skipped_header=0;
return ;
}
- *current_search_space=file_space;
*offset=file_space->start;
}
}
int my_fseek(FILE *stream, off_t offset, int whence)
{
-#if defined(HAVE_FSEEKO) && !defined(__MINGW32__) && !defined(__ARM_EABI__)
+#if defined(HAVE_FSEEKO) && !defined(__MINGW32__) && !defined(__ARM_EABI__) && !defined(__FRAMAC__)
{
int res;
if((res=fseeko(stream, offset, whence))>=0)
diff --git a/src/filegen.h b/src/filegen.h
index af8e793..70cbee4 100644
--- a/src/filegen.h
+++ b/src/filegen.h
@@ -119,30 +119,180 @@ typedef struct
#define NL_BARECR (1 << 2)
void free_header_check(void);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode);
+
+/*@
+ @ requires \valid(handle);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const unsigned int footer_length);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires footer_length > 0;
+ @ requires \valid_read((char *)footer+(0..footer_length-1));
+ @*/
void file_search_footer(file_recovery_t *file_recovery, const void*footer, const unsigned int footer_length, const unsigned int extra_length);
-void file_search_lc_footer(file_recovery_t *file_recovery, const unsigned char*footer, const unsigned int footer_length);
-void del_search_space(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end);
+
+/*@
+ @ requires buffer_size > 0;
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires \valid(file_recovery);
+ @ assigns \nothing;
+ @ ensures \result == DC_STOP || \result == DC_CONTINUE;
+ @*/
data_check_t data_check_size(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size(file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size_min(file_recovery_t *file_recovery);
+
+/*@
+ @ requires \valid(file_recovery);
+ @*/
void file_check_size_max(file_recovery_t *file_recovery);
+
+/*@
+ requires \valid(file_recovery);
+ ensures file_recovery->filename[0]=='\0';
+ ensures file_recovery->time==0;
+ ensures file_recovery->file_stat==\null;
+ ensures file_recovery->handle==\null;
+ ensures file_recovery->file_size==0;
+ ensures file_recovery->location.list.prev==&file_recovery->location.list;
+ ensures file_recovery->location.list.next==&file_recovery->location.list;
+ ensures file_recovery->location.end==0;
+ ensures file_recovery->location.data==0;
+ ensures file_recovery->extension==\null;
+ ensures file_recovery->min_filesize==0;
+ ensures file_recovery->calculated_file_size==0;
+ ensures file_recovery->data_check==\null;
+ ensures file_recovery->file_check==\null;
+ ensures file_recovery->file_rename==\null;
+ ensures file_recovery->offset_error==0;
+ ensures file_recovery->offset_ok==0;
+ ensures file_recovery->checkpoint_status==0;
+ ensures file_recovery->checkpoint_offset==0;
+ ensures file_recovery->flags==0;
+ ensures file_recovery->extra==0;
+ assigns file_recovery->filename[0];
+ assigns file_recovery->time;
+ assigns file_recovery->file_stat;
+ assigns file_recovery->handle;
+ assigns file_recovery->file_size;
+ assigns file_recovery->location.list.prev;
+ assigns file_recovery->location.list.next;
+ assigns file_recovery->location.end;
+ assigns file_recovery->location.data;
+ assigns file_recovery->extension;
+ assigns file_recovery->min_filesize;
+ assigns file_recovery->calculated_file_size;
+ assigns file_recovery->data_check;
+ assigns file_recovery->file_check;
+ assigns file_recovery->file_rename;
+ assigns file_recovery->offset_error;
+ assigns file_recovery->offset_ok;
+ assigns file_recovery->checkpoint_status;
+ assigns file_recovery->checkpoint_offset;
+ assigns file_recovery->flags;
+ assigns file_recovery->extra;
+*/
void reset_file_recovery(file_recovery_t *file_recovery);
+
+/*@
+ @ requires 0 < length <= 4096;
+ @ requires \valid_read((char *)value+(0..length-1));
+ @ requires \valid_function(header_check);
+ @ requires \valid(file_stat);
+ @*/
void register_header_check(const unsigned int offset, const void *value, const unsigned int length, int (*header_check)(const unsigned char *buffer, const unsigned int buffer_size,
const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new),
file_stat_t *file_stat);
+
+/*@
+ @ requires \valid(files_enable);
+ @*/
file_stat_t * init_file_stats(file_enable_t *files_enable);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires \valid_read((char *)buffer+(0..buffer_size-1));
+ @ requires new_ext==\null || valid_read_string(new_ext);
+ @*/
int file_rename_unicode(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
+
+void header_ignored_cond_reset(uint64_t start, uint64_t end);
+
+/*@
+ @ requires file_recovery_new==\null || \valid_read(file_recovery_new);
+ @*/
void header_ignored(const file_recovery_t *file_recovery_new);
+
+/*@
+ @ requires \valid_read(file_recovery);
+ @ requires \valid_read(file_recovery_new);
+ @ requires separation: \separated(file_recovery, file_recovery_new);
+ @ requires \initialized(&file_recovery->file_check);
+ @ requires \initialized(&file_recovery->handle);
+ @ ensures \result == 0 || \result == 1;
+ @*/
int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery_t *file_recovery_new);
+
+/*@
+ requires valid_stream: \valid(stream);
+ requires whence_enum: whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END;
+ assigns *stream \from *stream, indirect:offset, indirect:whence;
+ assigns \result, __fc_errno \from indirect:*stream, indirect:offset,
+ indirect:whence;
+*/
int my_fseek(FILE *stream, off_t offset, int whence);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 11));
+ @*/
time_t get_time_from_YYMMDDHHMMSS(const char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 18));
+ @*/
time_t get_time_from_YYYY_MM_DD_HH_MM_SS(const char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 16));
+ @*/
time_t get_time_from_YYYY_MM_DD_HHMMSS(const char *date_asc);
+
+/*@
+ @ requires \valid_read(date_asc + (0 .. 14));
+ @*/
time_t get_time_from_YYYYMMDD_HHMMSS(const char *date_asc);
+/*@
+ @ requires \valid(list_search_space);
+ @ requires \valid(current_search_space);
+ @ requires \valid(offset);
+ @*/
+void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset, const uint64_t prev_location);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/godmode.c b/src/godmode.c
index ca3d333..0b41b0e 100644
--- a/src/godmode.c
+++ b/src/godmode.c
@@ -602,7 +602,7 @@ static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_o
old_cylinder=start.cylinder;
wmove(stdscr,ANALYSE_Y,ANALYSE_X);
wclrtoeol(stdscr);
- wprintw(stdscr,"Analyse cylinder %5u/%u: %02u%%",
+ wprintw(stdscr, "Analyse cylinder %5lu/%lu: %02u%%",
start.cylinder, disk_car->geom.cylinders-1,
(unsigned int)(search_location*100/disk_car->disk_size));
wrefresh(stdscr);
@@ -846,7 +846,7 @@ static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_o
#ifdef HAVE_NCURSES
wmove(stdscr,ANALYSE_Y+1,ANALYSE_X);
wclrtoeol(stdscr);
- wprintw(stdscr,msg_READ_ERROR_AT, start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size));
+ wprintw(stdscr, "Read error at %lu/%u/%u (lba=%lu)\n", start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size));
#endif
/* Stop reading after the end of the disk */
if(search_location >= disk_car->disk_real_size)
diff --git a/src/icon_ph.rc b/src/icon_ph.rc
index 4987614..d65fe73 100644
--- a/src/icon_ph.rc
+++ b/src/icon_ph.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/photorec.ico"
1 24 "../win/photorec_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "PhotoRec"
VALUE "OriginalFilename", "photorec_win.exe"
VALUE "Comments", "Signature based file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/icon_qph.rc b/src/icon_qph.rc
index 391828e..057ff52 100644
--- a/src/icon_qph.rc
+++ b/src/icon_qph.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/photorec.ico"
1 24 "../win/qphotorec_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "PhotoRec"
VALUE "OriginalFilename", "qphotorec_win.exe"
VALUE "Comments", "Signature based file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/icon_tst.rc b/src/icon_tst.rc
index 67b041d..63d5da3 100644
--- a/src/icon_tst.rc
+++ b/src/icon_tst.rc
@@ -4,8 +4,8 @@ app ICON DISCARDABLE "../icons/testdisk.ico"
1 24 MOVEABLE PURE "../win/testdisk_win.exe.manifest"
1 VERSIONINFO
-FILEVERSION 7, 1, 0, 0
-PRODUCTVERSION 7, 1, 0, 0
+FILEVERSION 7, 2, 0, 0
+PRODUCTVERSION 7, 2, 0, 0
FILEFLAGSMASK 0x3f
FILEOS 0x4
FILETYPE 0x1
@@ -20,9 +20,9 @@ BEGIN
VALUE "InternalName", "TestDisk"
VALUE "OriginalFilename", "testdisk_win.exe"
VALUE "Comments", "Partition and file recovery utility"
- VALUE "FileVersion", "7.1"
- VALUE "ProductVersion", "7.1"
- VALUE "LegalCopyright", "Copyright (C) 1998-2015 Christophe GRENIER, et al."
+ VALUE "FileVersion", "7.2"
+ VALUE "ProductVersion", "7.2"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2019 Christophe GRENIER, et al."
END
END
BLOCK "VarFileInfo"
diff --git a/src/lang.h b/src/lang.h
index f20dce7..3f43d48 100644
--- a/src/lang.h
+++ b/src/lang.h
@@ -21,7 +21,6 @@
*/
#define msg_DUMP_HEXA "Dump Hexa\n"
-#define msg_READ_ERROR_AT "Read error at %u/%u/%u (lba=%lu)\n"
#define c_YES 'Y'
#define c_NO 'N'
#define msg_TBL_NMARK "\nPartition sector doesn't have the endmark 0xAA55\n"
diff --git a/src/lang/qphotorec.ca.ts b/src/lang/qphotorec.ca.ts
index dbdcd5c..1e26ea8 100644
--- a/src/lang/qphotorec.ca.ts
+++ b/src/lang/qphotorec.ca.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Seleccioneu la destinació on guardar els fitxers recuperats.</translation>
</message>
@@ -61,22 +61,22 @@ Heu de ser usuari root per utilitzar el PhotoRec.</translation>
<translation>No hi ha disc</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Afegeix una imatge de disc en brut...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>El PhotoRec és programari lliure i ve SENSE CAP TIPUS DE GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Seleccioneu un mitjà des d&apos;on recuperar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Si algun dels discs llistats a sobre té una mida incorrecta, comproveu la confi
detecció a la BIOS, i instal·leu la última versió dels controladors del disc.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Indicadors</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipus</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistema de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Mida</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipus de sistema de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>sistema de fitxers ext2/ext3/ext4 </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Lliure: Explora només l&apos;espai no assignat</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Sencer: Extreu fitxers de la partició sencera</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Navega</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Cerca</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Quant a</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Format dels fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destinació:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperació completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Força bruta %1 sectors restants (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passa %1 - Llegint sector %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 capçaleres trobades</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 fitxers trobats</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Surt</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Família de fitxers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Surt</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Nombre de fitxers recuperats</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: No s&apos;ha pogut crear el fitxer</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>No s&apos;ha pogut crear el fitxer. Trieu una altra destinació</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: No hi ha espai suficient</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>No hi ha prou espai disponible. Heu d&apos;alliberar espai de disc i/o escollir una altra destinació</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,25 +234,25 @@ El QPhotoRec es distribueix amb l&apos;esperança que serà útil, però SENSE C
Hauríeu d&apos;haver rebut una còpia de la Llicència Pública General GNU juntament amb el QPhotoRec. En cas contrari, consulteu &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Quant a</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formats de fitxer</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Reinicialitzar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>
Res&amp;taura</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.cs.ts b/src/lang/qphotorec.cs.ts
new file mode 100644
index 0000000..57c630e
--- /dev/null
+++ b/src/lang/qphotorec.cs.ts
@@ -0,0 +1,256 @@
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs" version="2.1">
+<context>
+ <name>QPhotorec</name>
+ <message>
+ <location filename="src/qphotorec.cpp" line="125"/>
+ <source>QPhotoRec</source>
+ <translation>QPhotoRec</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="156"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
+ <source>Please select a destination to save the recovered files to.</source>
+ <translation>Vyberte umístění do kterého ukládat obnovené soubory.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="170"/>
+ <source>Please select a raw file</source>
+ <translation>Vyberte soubor s daty pro zpracování</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="172"/>
+ <source>Raw Files (*.dd *.raw *.img)</source>
+ <translation>Soubory s daty pro zpracování (*.dd *.raw *.img)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="259"/>
+ <source>Sys=</source>
+ <translation>Sys=</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="261"/>
+ <source>Unknown</source>
+ <translation>Neznámé</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="377"/>
+ <source>No harddisk found</source>
+ <translation>Nenalezeno žádné datové úložiště</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="379"/>
+ <source>No harddisk found
+You need to be administrator to use this program.
+Under Win9x, use the DOS version instead.
+Under Vista or later, select this program, right-click and choose &quot;Run as administrator&quot;.</source>
+ <translation>Nenalezen žádný pevný disk
+Tento program je třeba spouštět s oprávněními pro správu systému.
+V systému Windows 9x použijte namísto toho verzi pro DOS.
+Pro Vista a novější vyberte tento program, klikněte na něj pravým tlačítkem a zvolte „Spustit jako správce“.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="388"/>
+ <source>No harddisk found
+You need to be root to use PhotoRec.</source>
+ <translation>Nenalezen žádný pevný disk
+PhotoRec je třeba spouštět s oprávněními pro správu systému.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="393"/>
+ <source>No Disk!</source>
+ <translation>Žádné datové úložiště!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="455"/>
+ <source>Add a raw disk image...</source>
+ <translation>Přidat obraz disku pro zpracování…</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="461"/>
+ <source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
+ <translation>PhotoRec je svobodný (libre) software a NEJSOU NA NĚJ POSKYTOVÁNY ŽÁDNÉ ZÁRUKY.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="462"/>
+ <source>Please select a media to recover from</source>
+ <translation>Vyberte médium ze kterého obnovit</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="465"/>
+ <source>Disk capacity must be correctly detected for a successful recovery.
+If a disk listed above has an incorrect size, check HD jumper settings and BIOS
+detection, and install the latest OS patches and disk drivers.</source>
+ <translation>Pro úspěšné obnovení je třeba, aby byla správně zjištěna velikost datového úložiště.
+Pokud má výše uvedený disk nesprávnou velikost, zkontrolujte pozici příslušné zkratovací propojky (jumper) a detekci v BIOS a nainstalujte nejnovější opravy pro operační systém a ovladače disků. </translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="472"/>
+ <source>Flags</source>
+ <translation>Příznaky</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="473"/>
+ <source>Type</source>
+ <translation>Typ</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="474"/>
+ <source>File System</source>
+ <translation>Souborový systém</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="475"/>
+ <source>Size</source>
+ <translation>Velikost</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="476"/>
+ <source>Label</source>
+ <translation>Štítek</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="491"/>
+ <source>File System type</source>
+ <translation>Typ souborového systému</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="492"/>
+ <source>ext2/ext3/ext4 filesystem</source>
+ <translation>Souborový systém ext2/ext3/ext4</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="493"/>
+ <source>FAT/NTFS/HFS+/ReiserFS/...</source>
+ <translation>FAT/NTFS/HFS+/ReiserFS/…</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="497"/>
+ <source>Free: Scan for file from unallocated space only</source>
+ <translation>Volné: hledat soubory pouze na nepřiděleném prostoru</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="498"/>
+ <source>Whole: Extract files from whole partition</source>
+ <translation>Celé: vytáhnout soubory z celého oddílu</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="525"/>
+ <source>&amp;Browse</source>
+ <translation>&amp;Procházet</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="541"/>
+ <source>&amp;Search</source>
+ <translation>&amp;Hledat</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="544"/>
+ <source>&amp;About</source>
+ <translation>O &amp;aplikaci</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="545"/>
+ <source>&amp;File Formats</source>
+ <translation>Souborové &amp;formáty</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="645"/>
+ <source>Destination:</source>
+ <translation>Cíl:</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="650"/>
+ <source>Recovery completed</source>
+ <translation>Obnovení dokončeno</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="655"/>
+ <source>Bruteforce %1 sectors remaining (test %2)</source>
+ <translation>Zbývá %1 sektorů pro zkoušení hrubou silou (test %2)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="663"/>
+ <source>Pass %1 - Reading sector %2/%3</source>
+ <translation>Průchod %1 – čtení sektoru %2/%3</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="668"/>
+ <source>%1/10 headers found</source>
+ <translation>Nalezeno %1/10 hlaviček</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="670"/>
+ <source>%1 files found</source>
+ <translation>Nalezeno %1 souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="753"/>
+ <source>File family</source>
+ <translation>Kategorie souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Ukončit</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
+ <source>Number of files recovered</source>
+ <translation>Počet obnovených souborů</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="837"/>
+ <source>QPhotoRec: Failed to create file!</source>
+ <translation>QPhotoRec: Nepodařilo se vytvořit soubor!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="838"/>
+ <source>Failed to create file! Please choose another destination</source>
+ <translation>Soubor se nepodařilo vytvořit! Zvolte jiný cíl</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="857"/>
+ <source>QPhotoRec: Not enough space!</source>
+ <translation>QPhotoRec: Nedostatek dostupného prostoru!</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="858"/>
+ <source>There is not enough space left! Please free disk space and/or choose another destination</source>
+ <translation>Nezbývá dostatek volného prostoru! Uvolněte nějaký a/nebo zvolte jiný cíl</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="927"/>
+ <source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
+
+QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with QPhotoRec. If not, see &lt;http://www.gnu.org/licenses/&gt;.</source>
+ <translation>QPhotoRec je svobodný (libre) software: můžete ho šířit a/nebo upravovat za podmínek licence GNU General Public License, vydané nadací Free Software Foundation, buď verze 2 této licence, nebo (dle své volby) libovolné novější.
+
+QPhotoRec je šířen v naději, že bude užitečný, ale BEZ JAKÝCHKOLI ZÁRUK; dokonce bez předpokládané záruky PRODEJNOSTI nebo VHODNOSTI PRO KONKRÉTNÍ ÚČEL. Podrobnosti viz text GNU General Public License.
+
+Společně s QPhotoRec byste měli obdržet text znění GNU General Public License. Pokud ne, naleznete ho na &lt;http://www.gnu.org/licenses/&gt;.</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="928"/>
+ <source>QPhotoRec: About</source>
+ <translation>QPhotoRec: O aplikaci</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="957"/>
+ <source>File Formats</source>
+ <translation>Souborové formáty</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="960"/>
+ <source>&amp;Reset</source>
+ <translation>V&amp;rátit na výchozí</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="961"/>
+ <source>Res&amp;tore</source>
+ <translation>Obnovi&amp;t</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.es.ts b/src/lang/qphotorec.es.ts
index d82bf94..3f35b77 100644
--- a/src/lang/qphotorec.es.ts
+++ b/src/lang/qphotorec.es.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Por favor escoje un directorio para grabar los archivos recuperados.</translation>
</message>
@@ -43,13 +43,16 @@
You need to be administrator to use this program.
Under Win9x, use the DOS version instead.
Under Vista or later, select this program, right-click and choose &quot;Run as administrator&quot;.</source>
- <translation type="unfinished"/>
+ <translation>No se encontró ningún disco duro
+Necesitas ser Administrador par usar este programa
+Si estas en Win9x, usa la versión DOS
+Si estas en Vista o posterior, botón derecho y selecciona &quot;Ejecutar como Administrador&quot;</translation>
</message>
<message>
<location filename="src/qphotorec.cpp" line="388"/>
<source>No harddisk found
You need to be root to use PhotoRec.</source>
- <translation>No se pudo encontrar los discos duros
+ <translation>No se pudo encontrar ningún disco duro
Necesitas ser root para usar PhotoRec.</translation>
</message>
<message>
@@ -58,189 +61,195 @@ Necesitas ser root para usar PhotoRec.</translation>
<translation>Sin disco</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
- <translation>Añade imagen de disco raw</translation>
+ <translation>Añade un imagen raw de disco</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
- <translation>Photorec es un program gatis y no TIENE NINGUNA GARANTIA.</translation>
+ <translation>Photorec es un program gratuito y no TIENE NINGUNA GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Por favor escoje un medio para recuperarse de </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
- <translation type="unfinished"/>
+ <translation>El tamaño del disco debe ser correctamente detectado
+Si el tamaño de alguno de los disco listados es incorrecto, comprueba la Bios
+y los jumpers y/o Instala los los controladadores más recientes</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Bandera</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistem de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
- <translation>tamaño</translation>
+ <translation>Tamaño</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo de sistema de archivo </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>sistema de archivos ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
- <translation>Libre: Escanea por un archivo en el espacio que no es usado solamente.</translation>
+ <translation>Libre: Escanear por un archivo solamente en el espacio que no esta usado.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
- <translation>Todo: Sacar los archivos de toda la directoria</translation>
+ <translation>Todo: Extraer los archivos de toda la partición</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
- <translation>&amp;Mirar</translation>
+ <translation>&amp;Explorar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Buscar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Acerca de</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
- <translation>&amp;Formatos de el archivo</translation>
+ <translation>&amp;Formatos de archivo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
- <translation>destinación:</translation>
+ <translation>Destino:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperación completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
- <translation>Bruteforce quedan 1% sectores (testiar %2)</translation>
+ <translation>Bruteforce quedan 1% sectores (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Pass %1 - Leyendo el sector %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 headers encontrado</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 de archivos encontrado</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;abandonar</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familia de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Abandonar</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
- <translation>El numero de archivos recuperados</translation>
+ <translation>Archivos recuperados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
- <translation>QPhotoRec: fallo en crear un archivo!</translation>
+ <translation>QPhotoRec: No pudo crear un archivo!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
- <translation>No se pudo crear un achivo! Por favor escoje otro directorio</translation>
+ <translation>No se pudo crear un archivo! Por favor escoje otro directorio</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: No hay suficiente espacio </translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
- <translation>No quedan bastante espacio! Por favor escoje otro disco duro con espacio o otro directorio</translation>
+ <translation> No hay suficiente espacio! Por favor libera espacio o escoje otro disco duro</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with QPhotoRec. If not, see &lt;http://www.gnu.org/licenses/&gt;.</source>
- <translation>QPhotoRect is es un programa gratis: Tu puedes redistribuirlo o modificarlo bajo el contrato de GNU General Public License como publicado por Free Software Foundation usando version 2 de la licensia o tu opcion de una de las ultima versiones.</translation>
+ <translation>QPhotoRect is es software libre: Tu puedes redistribuirlo y/o modificarlo bajo el contrato de GNU General Public License publicado por la Free Software Foundation usando la version 2 de la licencia o ( a tu elección) cualquier versión posterior.
+
+QPhotoRec se distribuye con la esperanza de que será útil, pero SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de comerciabilidad o aptitud para un propósito en particular. Vea la Licencia Pública General de GNU para más detalles.
+
+Debería haber recibido una copia de la Licencia Pública General de GNU junto con QPhotoRec. Si no es así, consulte &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
- <translation>QPhotoRec: Sobre</translation>
+ <translation>QPhotoRec: Acerca de</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
- <translation>EL formato de los archivos</translation>
+ <translation>Tipos de archivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
- <translation>&amp;Empesar</translation>
+ <translation>&amp;Reiniciar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Res&amp;tore</translation>
</message>
diff --git a/src/lang/qphotorec.fr.ts b/src/lang/qphotorec.fr.ts
index bff0426..17ce6fa 100644
--- a/src/lang/qphotorec.fr.ts
+++ b/src/lang/qphotorec.fr.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Merci de sélectionner une destination pour sauvegarder les fichiers récupérés.</translation>
</message>
@@ -61,22 +61,22 @@ Il faut être root pour utiliser ce programme.</translation>
<translation>Pas de disque!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Ajouter une image disque...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec est un logiciel libre, il vient avec ABSOLUMENT AUCUNE GARANTIE.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Merci de sélectionner un média à partir duquel récupérer les données</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -84,143 +84,143 @@ detection, and install the latest OS patches and disk drivers.</source>
Si un disque listé ci dessus a une taille incorrecte, vérifier le paramétrage des cavaliers du disque et la détection au niveau du BIOS, installer les derniers correctifs au niveau de votre système d&apos;exploitation et des gestionnaires de disques.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Drapeaux</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Type</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Système de fichiers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Taille</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Label</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Type de système de fichiers</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Système de fichier ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Free: Rechercher des fichiers depuis l&apos;espace non alloué uniquement</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Whole: Extraire les fichiers depuis la totalité de la partition</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Parcourir</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Rechercher</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;A propos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formats de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destination:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Récupération de données terminée</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Force brute %1 secteurs restants (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passe %1 - Lecture du secteur %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 entêtes trouvés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 fichiers trouvés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Quitter</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familles de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Quitter</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Nombre de fichiers récupérés</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Échec de création de fichier!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Impossible de créer un fichier! Merci de sélectionner une autre destination</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Pas assez d&apos;espace!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Il n&apos;y a pas assez d&apos;espace disponible! Merci de libérer de l&apos;espace disque et/ou de choisir une autre destination</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -233,24 +233,24 @@ QPhotoRec est distribué dans l&apos;espoir qu&apos;il sera utile, mais SANS AUC
Vous avez du recevoir un exemplaire de la Licence Publique Générale GNU avec ce programme ; si ce n&apos;est pas le cas, consulter &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: A propos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formats de fichier</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Réinitialiser</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Res&amp;taurer</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.it.ts b/src/lang/qphotorec.it.ts
index 2e4d7b6..55a87f0 100644
--- a/src/lang/qphotorec.it.ts
+++ b/src/lang/qphotorec.it.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Scegliere la destinazione in cui si desidera salvare i documenti recuperati.</translation>
</message>
@@ -61,22 +61,22 @@ Si deve disporre di privilegi di root per usare PhotoRec.</translation>
<translation>Nessun Disco!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Aggiungere un&apos;immagine raw del disco...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec è un software libero e viene fornito ASSOLUTAMENTE SENZA ALCUNA GARANZIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Selezionare un supporto dal quale eseguire l&apos;operazione di recupero</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -86,143 +86,143 @@ detection, e installare gli aggiornamenti del sistema operativo e i driver del d
</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Flag</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>File System</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Dimensione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etichetta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo di File System</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>File system ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Libero: ricerca di documenti unicamente nello spazio non allocato</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Completo: Estrazione dei documenti da tutta la partizione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Naviga</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Cerca</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Info</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formati dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destinazione:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recupero terminato</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Esaustiva %1 settori rimanenti (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Iterazione %1 - Lettura del settore %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 intestazioni trovate</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 documenti trovati</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Uscire</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>famiglia dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Uscire</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>numero dei file recuperati</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Impossibile creare il file!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Impossibile creare il file! Selezionare un&apos;altra destinazione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Spazio insufficiente!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Spazio disponibile insufficiente. Liberare spazio su disco e/o scegliere un&apos;altra destinazione</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -235,24 +235,24 @@ QPhotoRec viene distribuito con la speranza che possa essere utile ma SENZA ALCU
Una copia della GNU General Public License è distribuita con QPhotoRec. In caso contrario se ne può ottenere una all&apos;indirizzo &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: A proposito</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formati dei file</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Resettare</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>Ripri&amp;stinare</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.ja.ts b/src/lang/qphotorec.ja.ts
index dd222e1..4258334 100644
--- a/src/lang/qphotorec.ja.ts
+++ b/src/lang/qphotorec.ja.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>復元したファイルの保存先を選択してください。</translation>
</message>
@@ -61,22 +61,22 @@ PhotoRecを使うにはrootユーザになる必要があります。</translati
<translation>ディスクがありません!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>復元元ディスクイメージを追加</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRecは無料のソフトウェアで、一切の保証はありません。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>復元元のメディアを選択してください</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -84,143 +84,143 @@ detection, and install the latest OS patches and disk drivers.</source>
上に列挙されたディスクに正しくない容量が表示されていたら、ハードディスクのジャンパ設定とBIOSで検知されている内容を確認し、最新のOSパッチとディスクドライバをインストールしてください。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>フラグ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>タイプ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>ファイルシステム</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>サイズ</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>ラベル</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>ファイルシステムの種類</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 ファイルシステム</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>すべて: すべてのパーティションからファイルを抽出する</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;参照</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;検索</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;ファイルフォーマット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>復元先</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>復元完了</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 ヘッダーが見つかりました</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 個のファイルが見つかりました。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;終了</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;終了</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>復元したファイルの数</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: ファイル作成に失敗しました!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>ファイルの作成に失敗しました! 別の保存先を選んでください。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: 十分な空き容量がありません!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>十分な空き容量がありません! ディスクの空き容量を増やすかまたは別の復元先を指定してください</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -229,24 +229,24 @@ You should have received a copy of the GNU General Public License along with QPh
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation type="unfinished"/>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>ファイルフォーマット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;リセット</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation type="unfinished"/>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.pt.ts b/src/lang/qphotorec.pt.ts
index c6af4fd..cddfb18 100644
--- a/src/lang/qphotorec.pt.ts
+++ b/src/lang/qphotorec.pt.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Por favor selecionar o destino para salvar os arquivos recuperados.</translation>
</message>
@@ -61,22 +61,22 @@ Você precisa ser root para usar PhotoRec.</translation>
<translation>Sem disco!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Adicionar imagem de disco raw...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec é um software livre, e não vem com ABSOLUTAMENTE NENHUMA GARANTIA.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Por favor selecionar a midia para recuperar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Se o disco listado abaixo não tem o tamanho certo, verificar o jumper do HD nas
detecar, e instalar o ultimo patch do SO e drivers do disco.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Flags</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Sistema de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Tamanho</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiqueta</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Tipo de sistema de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Sistemas de arquivos ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Livre: Esconear por arquivos de espaços não alocados somente.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Inteiro: Extrair arquivos da partição inteira</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Browse</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Pesquisar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Sobre</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Formatos de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Destino:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Recuperação completada</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Bruteforce %1 setores restantes (teste %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Passar %1 - Lendo setor %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 headers encontrados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 arquivos encontrados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Sair</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Familia do arquivo</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Sair</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Número de arquivos recuperados</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Falha ao criar o arquivo!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Falha ao criar o arquivo! Por favor selecionar outro destino</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Sem espaço suficiente!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Não tem espaço suficiente! Por favor mais espaço em disco e/ou selecione outro destino</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ QPhotoRec é distribuido na esperança de ser util, porém sem qualquer garantia
Você deve receber uma cópia do licença GNU durante o uso de QPhotoRec. Se não, visite &lt;https://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Sobre</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Formatos de arquivos</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Reconfigurar</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Restaurar</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.ru.ts b/src/lang/qphotorec.ru.ts
index 3f0f709..ba2d4cd 100644
--- a/src/lang/qphotorec.ru.ts
+++ b/src/lang/qphotorec.ru.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Выберите назначение для сохранения восстановленных файлов.</translation>
</message>
@@ -61,22 +61,22 @@ You need to be root to use PhotoRec.</source>
<translation>Нет диска!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Добавить образ raw диска...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec является свободным программным обеспечением и поставляется с БЕЗ ВСЯКИХ ГАРАНТИЙ.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Выберите носитель для восстановления из</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ detection, and install the latest OS patches and disk drivers.</source>
и обнаружение BIOS, и установите последние обновления операционной системы и дисковых накопителей.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>Флаги</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Тип</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Файловая система</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Размер</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Метка</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Тип файловой системы</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>Файловая система ext2/ext3/ext4</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>Файловая система FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Свободное: Сканирование файла только из незанятого пространства</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Весь: Извлечение файлов из всего раздела</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>О&amp;бзор</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Поиск</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;О программе</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Форматы файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Назначение:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Восстановление завершено</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Полный перебор %1 оставшихся секторов (тест %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Проход %1 - Чтение сектора %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>Найдено %1/10 заголовков</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>Найдено %1 файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>В&amp;ыход</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Семейство файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>В&amp;ыход</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Количество восстановленных</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Не удалось создать файл!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Не удалось создать файл! Выберите другое назначение</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>PhotoRec: Не хватает места!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Там не осталось свободного места! Освободите место на диске или выберите другое место назначения</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ PhotoRec распространяется в надежде, что она бу
Вы должны были получить копию GNU General Public License вместе с PhotoRec. Если нет, смотрите &lt;http://www.gnu.org/licenses/&gt;.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>О программе QPhotoRec</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Форматы файлов</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>Сб&amp;росить</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Вернуть</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.tr.ts b/src/lang/qphotorec.tr.ts
index 9b49693..0b226be 100644
--- a/src/lang/qphotorec.tr.ts
+++ b/src/lang/qphotorec.tr.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>Lütfen kurtarılan dosyaların kaydedeceği konumu seçin.</translation>
</message>
@@ -61,22 +61,22 @@ PhotoRec&apos;i kullanmanız için &quot;root&quot; kullanıcısı olmalısını
<translation>Disk yok</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>Ham (Raw) disk imajı ekleyin</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec ücresiz bir yazılımdır ve verilerin kurtarılması konusunda herhangi bir garanti vermez.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>Lütfen kurtarılmasını istediğiniz ortamı seçin</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ Eğer aşağıdaki listedeki bir disk yanlış boyutta belirlenmişse disk jumpe
</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>İşareti</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>Tipi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>Dosya Sistemi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>Boyutu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>Etiketi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>Dosya Sistemi türü</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 dosya sistemleri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>Boş alan: Sadece bir disk olarak tanımlanmamış alanı tara</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>Tamamı: Tüm bölümden dosyaları çıkart</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>&amp;Gözat</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>&amp;Ara</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>&amp;Hakkında</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>&amp;Dosya Formatları</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>Hedef:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>Kurtarma tamamlandı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>Bruteforce %1 sektör kaldı (test %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>Tamamlanan %1 - Okunan sektör %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>%1/10 kafa bulundu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>%1 dosya bulundu</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>&amp;Çıkış</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>Dosya ailesi</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>&amp;Çıkış</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>Kurtarılan dosya sayısı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: Dosya oluşturulamadı</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>Dosya oluşturulamadı! Lütfen başka bir konum seçin.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: Yeterli alan yok!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>Diskte yeterli alan kalmadı! Lütfen diskte boş alan açın ve/veya başka bir hedef disk seçin.</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ QPhotoRec işe yarayacağı öngörüsü ile dağıtılmıştır fakat; TİCAR
QPhotoRec ile birlikte GNU Genel Kamu Lisansı&apos;nın bir kopyasını almış olmalısınız. Eğer yoksa &lt;http://www.gnu.org/licenses/&gt; .</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: Hakkında</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>Dosya Türleri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>&amp;Hiçbiri</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>&amp;Tümü</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/lang/qphotorec.zh_TW.ts b/src/lang/qphotorec.zh_TW.ts
index ab7468d..e8c00df 100644
--- a/src/lang/qphotorec.zh_TW.ts
+++ b/src/lang/qphotorec.zh_TW.ts
@@ -8,7 +8,7 @@
</message>
<message>
<location filename="src/qphotorec.cpp" line="156"/>
- <location filename="src/qphotorec.cpp" line="518"/>
+ <location filename="src/qphotorec.cpp" line="521"/>
<source>Please select a destination to save the recovered files to.</source>
<translation>請選擇要儲存還原檔案的目的地。</translation>
</message>
@@ -61,22 +61,22 @@ You need to be root to use PhotoRec.</source>
<translation>沒有磁碟!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="452"/>
+ <location filename="src/qphotorec.cpp" line="455"/>
<source>Add a raw disk image...</source>
<translation>加入一個原始磁碟影像...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="458"/>
+ <location filename="src/qphotorec.cpp" line="461"/>
<source>PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY.</source>
<translation>PhotoRec 是自由軟體,並不提供任何擔保。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="459"/>
+ <location filename="src/qphotorec.cpp" line="462"/>
<source>Please select a media to recover from</source>
<translation>請選擇需要還原的媒體</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="462"/>
+ <location filename="src/qphotorec.cpp" line="465"/>
<source>Disk capacity must be correctly detected for a successful recovery.
If a disk listed above has an incorrect size, check HD jumper settings and BIOS
detection, and install the latest OS patches and disk drivers.</source>
@@ -85,143 +85,143 @@ detection, and install the latest OS patches and disk drivers.</source>
並請安裝最近更新的作業系統修補包以及磁碟驅動程式。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="469"/>
+ <location filename="src/qphotorec.cpp" line="472"/>
<source>Flags</source>
<translation>旗標</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="470"/>
+ <location filename="src/qphotorec.cpp" line="473"/>
<source>Type</source>
<translation>類型</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="471"/>
+ <location filename="src/qphotorec.cpp" line="474"/>
<source>File System</source>
<translation>檔案系統</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="472"/>
+ <location filename="src/qphotorec.cpp" line="475"/>
<source>Size</source>
<translation>大小</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="473"/>
+ <location filename="src/qphotorec.cpp" line="476"/>
<source>Label</source>
<translation>標籤</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="488"/>
+ <location filename="src/qphotorec.cpp" line="491"/>
<source>File System type</source>
<translation>檔案系統類型</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="489"/>
+ <location filename="src/qphotorec.cpp" line="492"/>
<source>ext2/ext3/ext4 filesystem</source>
<translation>ext2/ext3/ext4 檔案系統</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="490"/>
+ <location filename="src/qphotorec.cpp" line="493"/>
<source>FAT/NTFS/HFS+/ReiserFS/...</source>
<translation>FAT/NTFS/HFS+/ReiserFS/...</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="494"/>
+ <location filename="src/qphotorec.cpp" line="497"/>
<source>Free: Scan for file from unallocated space only</source>
<translation>空間:僅掃瞄未分配空間裡的檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="495"/>
+ <location filename="src/qphotorec.cpp" line="498"/>
<source>Whole: Extract files from whole partition</source>
<translation>完整:從整個分割區內提取檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="522"/>
+ <location filename="src/qphotorec.cpp" line="525"/>
<source>&amp;Browse</source>
<translation>瀏覽(&amp;B)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="538"/>
+ <location filename="src/qphotorec.cpp" line="541"/>
<source>&amp;Search</source>
<translation>搜尋(&amp;S)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="541"/>
+ <location filename="src/qphotorec.cpp" line="544"/>
<source>&amp;About</source>
<translation>關於(&amp;A)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="542"/>
+ <location filename="src/qphotorec.cpp" line="545"/>
<source>&amp;File Formats</source>
<translation>檔案系統(&amp;F)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="642"/>
+ <location filename="src/qphotorec.cpp" line="645"/>
<source>Destination:</source>
<translation>目的地:</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="647"/>
+ <location filename="src/qphotorec.cpp" line="650"/>
<source>Recovery completed</source>
<translation>完成還原</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="652"/>
+ <location filename="src/qphotorec.cpp" line="655"/>
<source>Bruteforce %1 sectors remaining (test %2)</source>
<translation>尚餘強力破解 %1 個磁區 (測試 %2)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="660"/>
+ <location filename="src/qphotorec.cpp" line="663"/>
<source>Pass %1 - Reading sector %2/%3</source>
<translation>通過 %1 - 正在選取磁區 %2/%3</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="665"/>
+ <location filename="src/qphotorec.cpp" line="668"/>
<source>%1/10 headers found</source>
<translation>找到標願 %1/10</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="667"/>
+ <location filename="src/qphotorec.cpp" line="670"/>
<source>%1 files found</source>
<translation>找到 %1 個檔案</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="540"/>
- <location filename="src/qphotorec.cpp" line="762"/>
- <source>&amp;Quit</source>
- <translation>離開(&amp;Q)</translation>
- </message>
- <message>
- <location filename="src/qphotorec.cpp" line="750"/>
+ <location filename="src/qphotorec.cpp" line="753"/>
<source>File family</source>
<translation>檔案家族</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="751"/>
+ <location filename="src/qphotorec.cpp" line="543"/>
+ <location filename="src/qphotorec.cpp" line="765"/>
+ <source>&amp;Quit</source>
+ <translation>離開(&amp;Q)</translation>
+ </message>
+ <message>
+ <location filename="src/qphotorec.cpp" line="754"/>
<source>Number of files recovered</source>
<translation>完成還原的檔案數目</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="834"/>
+ <location filename="src/qphotorec.cpp" line="837"/>
<source>QPhotoRec: Failed to create file!</source>
<translation>QPhotoRec: 建立檔案失敗!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="835"/>
+ <location filename="src/qphotorec.cpp" line="838"/>
<source>Failed to create file! Please choose another destination</source>
<translation>建立檔案失敗!請選取另一目的地</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="854"/>
+ <location filename="src/qphotorec.cpp" line="857"/>
<source>QPhotoRec: Not enough space!</source>
<translation>QPhotoRec: 空間不足!</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="855"/>
+ <location filename="src/qphotorec.cpp" line="858"/>
<source>There is not enough space left! Please free disk space and/or choose another destination</source>
<translation>磁碟空間不足!請騰出空間並/或選取另一目的地</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="924"/>
+ <location filename="src/qphotorec.cpp" line="927"/>
<source>QPhotoRec is is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
QPhotoRec is is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
@@ -234,24 +234,24 @@ You should have received a copy of the GNU General Public License along with QPh
您應該連同 QPhotoRec 取得 GNU 通用公共許可證 (GPL) 的複本,否則您可以參見&lt;http://www.gnu.org/licenses/&gt;。</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="925"/>
+ <location filename="src/qphotorec.cpp" line="928"/>
<source>QPhotoRec: About</source>
<translation>QPhotoRec: 關於</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="954"/>
+ <location filename="src/qphotorec.cpp" line="957"/>
<source>File Formats</source>
<translation>檔案格式</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="957"/>
+ <location filename="src/qphotorec.cpp" line="960"/>
<source>&amp;Reset</source>
<translation>重設(&amp;R)</translation>
</message>
<message>
- <location filename="src/qphotorec.cpp" line="958"/>
+ <location filename="src/qphotorec.cpp" line="961"/>
<source>Res&amp;tore</source>
<translation>還原(&amp;T)</translation>
</message>
</context>
-</TS>
+</TS> \ No newline at end of file
diff --git a/src/ntfs.c b/src/ntfs.c
index ee47e0a..1cbdeaa 100644
--- a/src/ntfs.c
+++ b/src/ntfs.c
@@ -184,7 +184,7 @@ int test_NTFS(const disk_t *disk_car, const struct ntfs_boot_sector*ntfs_header,
return 0;
}
-const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record)
+static const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record)
{
const char* location = (const char*)record;
if(le32(record->magic)!=NTFS_Magic ||
@@ -225,10 +225,12 @@ const ntfs_attribheader* ntfs_findattribute(const ntfs_recordheader* record, uin
return ntfs_searchattribute(attrib, attrType, end, 0);
}
-const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end)
+#if 0
+static const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end)
{
return ntfs_searchattribute(attrib, attrType, end, 1);
}
+#endif
const char* ntfs_getattributedata(const ntfs_attribresident* attrib, const char* end)
{
diff --git a/src/ntfs.h b/src/ntfs.h
index 353a7f3..faaa1ac 100644
--- a/src/ntfs.h
+++ b/src/ntfs.h
@@ -254,9 +254,7 @@ int test_NTFS(const disk_t *disk_car, const struct ntfs_boot_sector*ntfs_header,
#define NTFS_GETU64(p) (le64(*(const uint64_t*)(p)))
unsigned int ntfs_sector_size(const struct ntfs_boot_sector *ntfs_header);
int rebuild_NTFS_BS(disk_t *disk_car,partition_t *partition, const int verbose, const unsigned int expert, char**current_cmd);
-const ntfs_attribheader *ntfs_getattributeheaders(const ntfs_recordheader* record);
const ntfs_attribheader* ntfs_findattribute(const ntfs_recordheader* record, uint32_t attrType, const char* end);
-const ntfs_attribheader* ntfs_nextattribute(const ntfs_attribheader* attrib, uint32_t attrType, const char* end);
const char* ntfs_getattributedata(const ntfs_attribresident* attrib, const char* end);
long int ntfs_get_first_rl_element(const ntfs_attribnonresident *attrnr, const char* end);
diff --git a/src/ntfs_fix.c b/src/ntfs_fix.c
index e0157a2..37542a3 100644
--- a/src/ntfs_fix.c
+++ b/src/ntfs_fix.c
@@ -226,7 +226,7 @@ int repair_MFT(disk_t *disk_car, partition_t *partition, const int verbose, cons
{
/* Use MFT mirror */
#ifdef HAVE_NCURSES
- if(ask_confirmation("Fix MFT using its mirror ? (Y/N) - DANGEROUS NON REVERSIBLE OPERATION\nUse it ONLY IF Windows failed to access this filesystem.")!=0)
+ if(ask_confirmation("Fix MFT using its mirror ? (Y/N) - DANGEROUS NON REVERSIBLE OPERATION\nUse it ONLY IF TestDisk and Windows failed to access this filesystem.")!=0)
use_MFT=2;
else
#endif
diff --git a/src/ntfsp.c b/src/ntfsp.c
index 6da6822..b6a040a 100644
--- a/src/ntfsp.c
+++ b/src/ntfsp.c
@@ -37,6 +37,7 @@
#include "common.h"
#include "list.h"
#include "filegen.h"
+#include "photorec.h"
#ifdef HAVE_LIBNTFS
#include <ntfs/attrib.h>
#endif
diff --git a/src/partgpt.c b/src/partgpt.c
index 806ac75..025439d 100644
--- a/src/partgpt.c
+++ b/src/partgpt.c
@@ -38,8 +38,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include <assert.h>
@@ -78,6 +77,7 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt);
const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_EFI, "EFI System" },
+ { GPT_ENT_TYPE_EBP, "Extended Boot" },
{ GPT_ENT_TYPE_MBR, "MBR" },
{ GPT_ENT_TYPE_FREEBSD, "FreeBSD" },
{ GPT_ENT_TYPE_FREEBSD_SWAP, "FreeBSD Swap" },
@@ -90,6 +90,7 @@ const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_MS_LDM_METADATA, "MS LDM MetaData" },
{ GPT_ENT_TYPE_MS_LDM_DATA, "MS LDM Data" },
{ GPT_ENT_TYPE_MS_RECOVERY, "Windows Recovery Env" },
+// { GPT_ENT_TYPE_LINUX_DATA
{ GPT_ENT_TYPE_LINUX_RAID, "Linux Raid" },
{ GPT_ENT_TYPE_LINUX_SWAP, "Linux Swap" },
{ GPT_ENT_TYPE_LINUX_LVM, "Linux LVM" },
@@ -99,6 +100,7 @@ const struct systypes_gtp gpt_sys_types[] = {
{ GPT_ENT_TYPE_LINUX_DATA, "Linux filesys. data" },
{ GPT_ENT_TYPE_HPUX_DATA, "HPUX Data" },
{ GPT_ENT_TYPE_HPUX_SERVICE, "HPUX Service" },
+ { GPT_ENT_TYPE_MAC_AFS, "Apple APFS" },
{ GPT_ENT_TYPE_MAC_HFS, "Mac HFS" },
{ GPT_ENT_TYPE_MAC_UFS, "Mac UFS" },
{ GPT_ENT_TYPE_MAC_RAID, "Mac Raid" },
@@ -511,6 +513,18 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt)
for(i=0; gpt_sys_types[i].name!=NULL; i++)
if(guid_cmp(gpt_sys_types[i].part_type, part_type_gpt)==0)
return gpt_sys_types[i].name;
+ log_info("%8x %04x %04x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ part_type_gpt.time_low,
+ part_type_gpt.time_mid,
+ part_type_gpt.time_hi_and_version,
+ part_type_gpt.clock_seq_hi_and_reserved,
+ part_type_gpt.clock_seq_low,
+ part_type_gpt.node[0],
+ part_type_gpt.node[1],
+ part_type_gpt.node[2],
+ part_type_gpt.node[3],
+ part_type_gpt.node[4],
+ part_type_gpt.node[5]);
return NULL;
}
diff --git a/src/partgptn.c b/src/partgptn.c
index dbe320a..74b76ce 100644
--- a/src/partgptn.c
+++ b/src/partgptn.c
@@ -38,8 +38,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include "common.h"
diff --git a/src/partgptw.c b/src/partgptw.c
index 65cbaac..0621e1b 100644
--- a/src/partgptw.c
+++ b/src/partgptw.c
@@ -37,8 +37,7 @@
#include <uuid.h>
#elif defined(HAVE_UUID_UUID_H)
#include <uuid/uuid.h>
-#endif
-#if defined(HAVE_SYS_UUID_H)
+#elif defined(HAVE_SYS_UUID_H)
#include <sys/uuid.h>
#endif
#include "common.h"
diff --git a/src/parti386.c b/src/parti386.c
index 350a38b..2c334b1 100644
--- a/src/parti386.c
+++ b/src/parti386.c
@@ -199,6 +199,7 @@ static const struct systypes i386_sys_types[] = {
{0xe1, "SpeedStor FAT12 ext"},
{0xe3, "DOS RO"},
{0xe4, "SpeedStor FAT16 ext"},
+ {0xea, "Boot (BLS)"},
{P_BEOS, "BeFS"},
{0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
{0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
diff --git a/src/phbf.c b/src/phbf.c
index 5d501a3..523abe4 100644
--- a/src/phbf.c
+++ b/src/phbf.c
@@ -170,6 +170,7 @@ pstatus_t photorec_bf(struct ph_param *params, const struct ph_options *options,
file_recovery_t file_recovery_new;
// memset(&file_recovery_new, 0, sizeof(file_recovery_t));
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
file_recovery_new.file_stat=NULL;
td_list_for_each(tmpl, &file_check_list.list)
{
@@ -190,7 +191,6 @@ pstatus_t photorec_bf(struct ph_param *params, const struct ph_options *options,
}
if(file_recovery_new.file_stat!=NULL)
{
- file_recovery_new.location.start=offset;
if(options->verbose>0)
{
log_info("%s header found at sector %lu\n",
diff --git a/src/phbs.c b/src/phbs.c
index b1135d8..9ce2d0d 100644
--- a/src/phbs.c
+++ b/src/phbs.c
@@ -100,6 +100,7 @@ pstatus_t photorec_find_blocksize(struct ph_param *params, const struct ph_optio
{
file_recovery_t file_recovery_new;
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint==&file_hint_tar &&
header_check_tar(buffer-0x200,0x200,0,&file_recovery,&file_recovery_new))
{ /* Currently saving a tar, do not check the data for know header */
diff --git a/src/phmain.c b/src/phmain.c
index 6a9c382..0949376 100644
--- a/src/phmain.c
+++ b/src/phmain.c
@@ -182,6 +182,10 @@ int main( int argc, char **argv )
}
logfile=argv[++i];
}
+ else if((strcmp(argv[i],"/nolog")==0) ||(strcmp(argv[i],"-nolog")==0))
+ {
+ create_log=TD_LOG_NONE;
+ }
else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0))
{
if(create_log==TD_LOG_NONE)
@@ -387,7 +391,7 @@ int main( int argc, char **argv )
printf("PhotoRec will try to restart itself using the sudo command to get\n");
printf("root (superuser) privileges.\n");
printf("\n");
- run_sudo(argc, argv);
+ run_sudo(argc, argv, create_log);
}
#endif
delete_list_disk(list_disk);
diff --git a/src/photorec.c b/src/photorec.c
index d8b0da1..c84d54c 100644
--- a/src/photorec.c
+++ b/src/photorec.c
@@ -85,6 +85,11 @@ void del_search_space(alloc_data_t *list_search_space, const uint64_t start, con
update_search_space_aux(list_search_space, start, end, NULL, NULL);
}
+/*@
+ @ requires \valid(list_search_space);
+ @ requires new_current_search_space == \null || \valid(*new_current_search_space);
+ @ requires offset == \null || \valid(*offset);
+ @*/
static void update_search_space_aux(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end, alloc_data_t **new_current_search_space, uint64_t *offset)
{
struct td_list_head *search_walker = NULL;
@@ -510,6 +515,7 @@ void file_block_free(alloc_list_t *list_allocation)
{
alloc_list_t *allocated_space;
allocated_space=td_list_entry(tmp, alloc_list_t, list);
+ header_ignored_cond_reset(allocated_space->start, allocated_space->end);
free_list_allocation_end=allocated_space->end;
td_list_del(tmp);
free(allocated_space);
diff --git a/src/photorec.h b/src/photorec.h
index 4aa30e0..a6ab7ed 100644
--- a/src/photorec.h
+++ b/src/photorec.h
@@ -64,7 +64,6 @@ struct ph_param
uint64_t offset;
};
-void get_prev_location_smart(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset, const uint64_t prev_location);
int get_prev_file_header(alloc_data_t *list_search_space, alloc_data_t **current_search_space, uint64_t *offset);
int file_finish_bf(file_recovery_t *file_recovery, struct ph_param *params,
alloc_data_t *list_search_space);
@@ -93,6 +92,12 @@ void file_block_log(const file_recovery_t *file_recovery, const unsigned int sec
void file_block_free(alloc_list_t *list_allocation);
void file_block_append(file_recovery_t *file_recovery, alloc_data_t *list_search_space, alloc_data_t **new_current_search_space, uint64_t *offset, const unsigned int blocksize, const unsigned int data);
void file_block_truncate_and_move(file_recovery_t *file_recovery, alloc_data_t *list_search_space, const unsigned int blocksize, alloc_data_t **new_current_search_space, uint64_t *offset, unsigned char *buffer);
+
+/*@
+ @ requires \valid(list_search_space);
+ @*/
+void del_search_space(alloc_data_t *list_search_space, const uint64_t start, const uint64_t end);
+
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/photorec_check_header.h b/src/photorec_check_header.h
index 7767ca1..6522d9f 100644
--- a/src/photorec_check_header.h
+++ b/src/photorec_check_header.h
@@ -97,7 +97,6 @@ static pstatus_t photorec_header_found(file_recovery_t *file_recovery_new, file_
*file_recovered=PFSTATUS_BAD;
if(file_recovery_new->file_stat==NULL || file_recovery_new->file_stat->file_hint==NULL)
return PSTATUS_OK;
- file_recovery_new->location.start=offset;
if(file_recovery->file_stat!=NULL)
{
if(options->verbose > 1)
@@ -132,6 +131,7 @@ inline static pstatus_t photorec_check_header(file_recovery_t *file_recovery, st
const unsigned int read_size=(blocksize>65536?blocksize:65536);
file_recovery_t file_recovery_new;
file_recovery_new.blocksize=blocksize;
+ file_recovery_new.location.start=offset;
if(file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_tar &&
header_check_tar(buffer-0x200,0x200, 0, file_recovery, &file_recovery_new))
{ /* Currently saving a tar, do not check the data for know header */
diff --git a/src/qphotorec_locale.qrc b/src/qphotorec_locale.qrc
index 409ab01..f838120 100644
--- a/src/qphotorec_locale.qrc
+++ b/src/qphotorec_locale.qrc
@@ -1,11 +1,14 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>lang/qphotorec.ca.qm</file>
+<file>lang/qphotorec.cs.qm</file>
<file>lang/qphotorec.es.qm</file>
<file>lang/qphotorec.fr.qm</file>
<file>lang/qphotorec.it.qm</file>
+<file>lang/qphotorec.ja.qm</file>
<file>lang/qphotorec.pt.qm</file>
<file>lang/qphotorec.ru.qm</file>
+<file>lang/qphotorec.tr.qm</file>
<file>lang/qphotorec.zh_TW.qm</file>
</qresource>
</RCC>
diff --git a/src/setdate.c b/src/setdate.c
index d05e716..5e26e1a 100644
--- a/src/setdate.c
+++ b/src/setdate.c
@@ -49,10 +49,12 @@ int set_date(const char *pathname, time_t actime, time_t modtime)
return -1;
ut.actime = actime;
ut.modtime = modtime;
+#ifndef __FRAMAC__
if (utime(pathname, &ut)) {
log_error("ERROR: Couldn't set the file's date and time for %s\n", pathname);
return -1;
}
#endif
+#endif
return 0;
}
diff --git a/src/sudo.c b/src/sudo.c
index 5f346ba..245b006 100644
--- a/src/sudo.c
+++ b/src/sudo.c
@@ -38,16 +38,28 @@
#include "types.h"
#include "common.h"
#include "sudo.h"
+#include "log.h"
-void run_sudo(int argc, char **argv)
+void run_sudo(const int argc, char **argv, const int create_log)
{
- int i;
char **argv2;
- argv2 = (char **)MALLOC(sizeof(char *) * (argc + 2));
- argv2[0]=strdup(SUDO_BIN);
- for (i=0; i < argc; i++)
- argv2[i+1] = argv[i];
- argv2[i+1]=NULL;
+ if(argc==1)
+ {
+ argv2 = (char **)MALLOC(sizeof(char *) * 4);
+ argv2[0] = strdup(SUDO_BIN);
+ argv2[1] = argv[0];
+ argv2[2] = strdup(create_log==TD_LOG_NONE?"/nolog":"/debug");
+ argv2[3] = NULL;
+ }
+ else
+ {
+ int i;
+ argv2 = (char **)MALLOC(sizeof(char *) * (argc + 2));
+ argv2[0]=strdup(SUDO_BIN);
+ for (i=0; i < argc; i++)
+ argv2[i+1] = argv[i];
+ argv2[i+1]=NULL;
+ }
printf("sudo may ask your user password, it doesn't ask for the root password.\n");
printf("Usually there is no echo or '*' displayed when you type your password.\n");
printf("\n");
diff --git a/src/sudo.h b/src/sudo.h
index fce6f3c..d16ee66 100644
--- a/src/sudo.h
+++ b/src/sudo.h
@@ -23,7 +23,7 @@
#ifdef __cplusplus
extern "C" {
#endif
-void run_sudo(int argc, char **argv);
+void run_sudo(const int argc, char **argv, const int create_log);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
diff --git a/src/testdisk.c b/src/testdisk.c
index 891833a..4317cc7 100644
--- a/src/testdisk.c
+++ b/src/testdisk.c
@@ -43,9 +43,7 @@
#include "types.h"
#include "common.h"
#include "intrf.h"
-#ifdef HAVE_NCURSES
#include "intrfn.h"
-#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -259,6 +257,10 @@ int main( int argc, char **argv )
}
logfile=argv[++i];
}
+ else if((strcmp(argv[i],"/nolog")==0) ||(strcmp(argv[i],"-nolog")==0))
+ {
+ create_log=TD_LOG_NONE;
+ }
else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0))
{
if(create_log==TD_LOG_NONE)
@@ -515,7 +517,7 @@ int main( int argc, char **argv )
printf("TestDisk will try to restart itself using the sudo command to get\n");
printf("root (superuser) privileges.\n");
printf("\n");
- run_sudo(argc, argv);
+ run_sudo(argc, argv, create_log);
}
#endif
return 0;
diff --git a/src/tpartwr.c b/src/tpartwr.c
index d6c3d43..0eece16 100644
--- a/src/tpartwr.c
+++ b/src/tpartwr.c
@@ -84,9 +84,14 @@ int interface_write(disk_t *disk_car,list_part_t *list_part,const int can_search
}
else
{
+ char options[10];
+ options[0]='R';
+ options[1]=0;
+ if(can_search_deeper)
+ strcat(options,"S");
log_flush();
#ifdef HAVE_NCURSES
- command=screen_buffer_display_ext(stdscr,(can_search_deeper?"S":""),menuWrite,menu);
+ command=screen_buffer_display_ext(stdscr, options, menuWrite,menu);
#endif
}
}