summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/common.c12
-rw-r--r--src/common.h8
-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.c960
-rw-r--r--src/file_exe.c954
-rw-r--r--src/file_exr.c58
-rw-r--r--src/file_fp7.c2
-rw-r--r--src/file_ico.c30
-rw-r--r--src/file_jpg.c2
-rw-r--r--src/file_list.c2
-rw-r--r--src/file_mp3.c446
-rw-r--r--src/file_pf.c118
-rw-r--r--src/file_raf.c14
-rw-r--r--src/file_sig.c51
-rw-r--r--src/file_tiff.c14
-rw-r--r--src/file_tiff.h59
-rw-r--r--src/file_tiff_be.c181
-rw-r--r--src/file_tiff_le.c190
-rw-r--r--src/file_txt.c25
-rw-r--r--src/file_zip.c595
-rw-r--r--src/filegen.c166
-rw-r--r--src/filegen.h152
-rw-r--r--src/godmode.c4
-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/ntfsp.c1
-rw-r--r--src/partgpt.c3
-rw-r--r--src/partgptn.c3
-rw-r--r--src/partgptw.c3
-rw-r--r--src/phbf.c2
-rw-r--r--src/phbs.c1
-rw-r--r--src/photorec.c5
-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/tpartwr.c7
50 files changed, 3920 insertions, 1390 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d761d91..a7c2a2b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -122,6 +122,7 @@ file_C = filegen.c \
file_evt.c \
file_evtx.c \
file_exe.c \
+ file_exr.c \
file_exs.c \
file_ext.c \
file_ext2.c \
@@ -370,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/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 67645f5..8a5e5ea 100644
--- a/src/common.h
+++ b/src/common.h
@@ -438,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..de28d49 100644
--- a/src/file_doc.c
+++ b/src/file_doc.c
@@ -39,10 +39,12 @@
#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);
@@ -68,135 +70,34 @@ const char WilcomDesignInformationDDD[56]=
'D', '\0', 'D', '\0', 'D', '\0', '\0', '\0'
};
-void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
+/*@
+ @ requires \valid(IN);
+ @ requires (9 == uSectorShift) || (12 == uSectorShift);
+ @ requires \valid( buf + (0 .. (1<<uSectorShift)-1));
+ @ ensures \result == -1 || \result == 0;
+ @*/
+static int OLE_read_block(FILE *IN, unsigned char *buf, const unsigned int uSectorShift, const unsigned int block, const uint64_t offset)
{
- unsigned char buffer_header[512];
- uint64_t doc_file_size;
- uint32_t *fat;
- unsigned long int i;
- 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;
- 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 ;
-#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("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))
- return ;
- if((fat=OLE_load_FAT(file_recovery->handle, header, offset))==NULL)
+ if(block==0xFFFFFFFF || block==0xFFFFFFFE)
+ return -1;
+ if(my_fseek(IN, offset + ((uint64_t)(1+block)<<uSectorShift), SEEK_SET) < 0)
{
-#ifdef DEBUG_OLE
- log_info("OLE_load_FAT failed\n");
-#endif
- return ;
+ return -1;
}
- /* 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));
- if(doc_file_size > doc_file_size_org)
+ if(fread(buf, 1<<uSectorShift, 1, IN)!=1)
{
-#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));
- log_info("doc_file_size %llu > doc_file_size_org %llu\n",
- (unsigned long long)doc_file_size, (unsigned long long)doc_file_size_org);
-#endif
- free(fat);
- return ;
+ return -1;
}
-#ifdef DEBUG_OLE
- log_trace("==> size : %llu\n", (long long unsigned)doc_file_size);
-#endif
- {
- unsigned int block;
- const unsigned int fat_entries=(le32(header->num_FAT_blocks)==0 ?
- 109:
- (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
-#ifdef DEBUG_OLE
- log_info("root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)buf, 1<<uSectorShift);
#endif
- /* FFFFFFFE = ENDOFCHAIN
- * Use a loop count i to avoid endless loop */
- for(block=le32(header->root_start_block), i=0;
- block!=0xFFFFFFFE && i<fat_entries;
- block=le32(fat[block]), i++)
- {
- struct OLE_DIR *dir_entries;
-#ifdef DEBUG_OLE
- log_info("read block %u\n", block);
-#endif
- if(!(block < fat_entries))
- {
- 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");
-#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)
- {
-#ifdef DEBUG_OLE
- log_info("fread failed\n");
-#endif
- free(dir_entries);
- free(fat);
- return ;
- }
- {
- 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++)
- {
- if(offset +
- le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 &&
- ((le32(dir_entry->size) >= le32(header->miniSectorCutoff)
- && le32(dir_entry->start_block) > fat_entries) ||
- le32(dir_entry->size) > doc_file_size))
- {
-#ifdef DEBUG_OLE
- log_info("error at sid %u\n", sid);
-#endif
- free(dir_entries);
- free(fat);
- return ;
- }
- }
- }
- free(dir_entries);
- }
- }
- free(fat);
- file_recovery->file_size=doc_file_size;
-}
-
-static void file_check_doc(file_recovery_t *file_recovery)
-{
- file_check_doc_aux(file_recovery, 0);
+ return 0;
}
+/*@
+ @ requires buffer_size >= sizeof(struct OLE_HDR);
+ @ requires \valid_read(buffer + (0 .. buffer_size-1));
+ @*/
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;
@@ -204,23 +105,28 @@ static const char *ole_get_file_extension(const unsigned char *buffer, const uns
unsigned int fat_entries;
unsigned int block;
unsigned int i;
+ /*@ assert 9 == le16(header->uSectorShift) || 12 == le16(header->uSectorShift); */
+ /*@ assert le32(header->num_FAT_blocks)>0; */
+ const unsigned int uSectorShift=le16(header->uSectorShift);
if(buffer_size<512)
return NULL;
- if(le32(header->num_FAT_blocks)==0)
- {
- fat=(const uint32_t *)(header+1);
- fat_entries=109;
- }
- else
+ /*@ assert buffer_size >= 512; */
{
const uint32_t *fati=(const uint32_t *)(header+1);
- const unsigned int fat_offset=(1+le32(fati[0])) << le16(header->uSectorShift);
+ const uint64_t fat_offset=((uint64_t)1+le32(fati[0])) << uSectorShift;
+ unsigned int fat_size;
+ if(fat_offset > buffer_size)
+ return NULL;
+ /*@ assert 0 < fat_offset <= buffer_size; */
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;
+ fat_size=(le32(header->num_FAT_blocks) << uSectorShift);
+ if(fat_offset + fat_size > buffer_size)
+ {
+ /*@ assert fat_offset + fat_size <= buffer_size; */
+ fat_size=buffer_size - fat_offset;
+ }
+ fat_entries=fat_size>>2;
+ /*@ assert \valid_read(fat + (0 .. fat_entries-1)); */
}
/* FFFFFFFE = ENDOFCHAIN
* Use a loop count i to avoid endless loop */
@@ -231,40 +137,48 @@ static const char *ole_get_file_extension(const unsigned char *buffer, const uns
block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
block=le32(fat[block]), i++)
{
- const unsigned int offset_root_dir=(1+block)<<le16(header->uSectorShift);
+ 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_entry;
+ 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,dir_entry=(const struct OLE_DIR *)&buffer[offset_root_dir];
- sid<512/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
- sid++,dir_entry++)
+ 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]);
+ 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));
}
- 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 ||
+ 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++;
+ is_db=2;
switch(le16(dir_entry->namsiz))
{
case 10:
@@ -386,8 +300,187 @@ static const char *ole_get_file_extension(const unsigned char *buffer, const uns
return NULL;
}
+/*@
+ @ 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];
+ uint64_t doc_file_size;
+ uint32_t *fat;
+ unsigned long int i;
+ 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<<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
+ 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
+ log_info("OLE_load_FAT failed\n");
+#endif
+ return ;
+ }
+ /* Search how many entries are not used at the end of the FAT */
+ {
+ const unsigned int val_max=(num_FAT_blocks<<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,
+ num_FAT_blocks, uSectorShift,
+ freesect_count, uSectorShift);
+ log_info("doc_file_size %llu > doc_file_size_org %llu\n",
+ (unsigned long long)doc_file_size, (unsigned long long)doc_file_size_org);
+#endif
+ free(fat);
+ return ;
+ }
+#ifdef DEBUG_OLE
+ log_trace("==> size : %llu\n", (long long unsigned)doc_file_size);
+#endif
+ {
+ unsigned int block;
+ const unsigned int fat_entries=(num_FAT_blocks==0 ?
+ 109:
+ (num_FAT_blocks<<uSectorShift)/4);
+#ifdef DEBUG_OLE
+ log_info("root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
+#endif
+ /* FFFFFFFE = ENDOFCHAIN
+ * Use a loop count i to avoid endless loop */
+ for(block=le32(header->root_start_block), i=0;
+ block!=0xFFFFFFFE && i<fat_entries;
+ block=le32(fat[block]), i++)
+ {
+ struct OLE_DIR *dir_entries;
+#ifdef DEBUG_OLE
+ log_info("read block %u\n", block);
+#endif
+ if(!(block < fat_entries))
+ {
+ free(fat);
+ return ;
+ }
+#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_recovery->handle, (unsigned char *)dir_entries, uSectorShift, block, offset)<0)
+ {
+#ifdef DEBUG_OLE
+ log_info("OLE_read_block failed\n");
+#endif
+ free(dir_entries);
+ free(fat);
+ return ;
+ }
+ {
+ unsigned int sid;
+ for(sid=0;
+ sid<(1<<uSectorShift)/sizeof(struct OLE_DIR);
+ sid++)
+ {
+ 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) ||
+ le32(dir_entry->size) > doc_file_size))
+ {
+#ifdef DEBUG_OLE
+ log_info("error at sid %u\n", sid);
+#endif
+ free(dir_entries);
+ free(fat);
+ return ;
+ }
+ }
+ }
+ free(dir_entries);
+ }
+ }
+ free(fat);
+ file_recovery->file_size=doc_file_size;
+}
+
+/*@
+ @ 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);
+}
+
+/*@
+ @ 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)
@@ -415,8 +508,9 @@ static int header_check_doc(const unsigned char *buffer, const unsigned int buff
*/
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))
+ 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); */
reset_file_recovery(file_recovery_new);
file_recovery_new->file_check=&file_check_doc;
file_recovery_new->file_rename=&file_rename_doc;
@@ -497,49 +591,59 @@ static int header_check_doc(const unsigned char *buffer, const unsigned int buff
return 1;
}
+/*@
+ @ 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;
- dif=(uint32_t*)MALLOC(109*4+(le32(header->num_extra_FAT_blocks)<<le16(header->uSectorShift)));
+ 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;
- 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)]))
+ for(i=0; i<le32(header->num_extra_FAT_blocks); i++)
{
- if(my_fseek(IN, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET) < 0)
+ 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;
}
- 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));
+#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 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)))
+ unsigned int j;
+ for(j=0; j<num_FAT_blocks; j++)
{
- 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)
+ if(OLE_read_block(IN, (unsigned char*)fat + (j<<uSectorShift), uSectorShift, le32(dif[j]), offset)<0)
{
free(dif);
free(fat);
@@ -551,29 +655,38 @@ static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint
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,47 +695,72 @@ 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));
+ @*/
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));
+ @*/
static uint64_t get64u(const void *buffer, const unsigned int offset)
{
const uint64_t *val=(const uint64_t *)((const unsigned char *)buffer+offset);
return le64(*val);
}
+/*@
+ @ requires \valid(ext);
+ @ requires *ext == \null || valid_read_string(*ext);
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. count-1));
+ @ ensures *ext == \null || valid_read_string(*ext);
+ @*/
static void software2ext(const char **ext, const unsigned int count, const unsigned char *software)
{
if(count>=12 && memcmp(software, "MicroStation", 12)==0)
@@ -664,6 +802,11 @@ static void software2ext(const char **ext, const unsigned int count, const unsig
return ;
}
+/*@
+ @ requires count > 0;
+ @ requires \valid_read(software + (0 .. 2*count-1));
+ @ ensures \result == \null || valid_read_string(\result);
+ @*/
static const char *software_uni2ext(const unsigned int count, const unsigned char *software)
{
if(count>=15 && memcmp(software, "M\0i\0c\0r\0o\0s\0o\0f\0t\0 \0E\0x\0c\0e\0l\0", 30)==0)
@@ -673,99 +816,173 @@ static const char *software_uni2ext(const unsigned int count, const unsigned cha
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 \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
- dump_log(dataPt, dirLen);
+ log_info("Property Info %u entries - %u bytes\n", numEntries, size);
#endif
- if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
+ if(numEntries == 0 || numEntries > 1024*1024)
return ;
- pos=get32u(dataPt, 44);
- if(pos > dirLen - 8)
+ /*@ assert 0 < numEntries <= 1024*1024; */
+ if(8 + numEntries * 8 > size)
return ;
+ /*@ assert 8 + numEntries * 8 <= size; */
+ /*@ assert numEntries * 8 <= size - 8; */
+ /*@ assert numEntries < size/8; */
+ if((const unsigned char *)&entries[numEntries] > &buffer[size])
+ return ;
+ /*TODO assert (const unsigned char *)&entries[numEntries] <= &buffer[size]; */
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read((buffer+8) + (8 .. size - 8 - 1)); */
+ /*TODO assert \valid_read((char *)entries + (0 .. size - 8 - 1)); */
+ /*TODO assert \valid_read(entries + (0 .. numEntries-1)); */
+ /*@
+ @ loop invariant 0 <= i <= numEntries;
+ @ loop variant numEntries-i;
+ @*/
+ for(i=0; i<numEntries; i++)
{
-// unsigned int size;
- unsigned int numEntries;
- unsigned int i;
- numEntries=get32u(dataPt, pos+4);
-#ifdef DEBUG_OLE
- {
- unsigned int size=get32u(dataPt, pos);
- log_info("Property Info %u - %u at 0x%x\n", numEntries, size, pos);
- }
-#endif
- if(pos + 8 + 8 * numEntries > dirLen)
+ // const struct summary_entry *entry=&entries[i];
+ const unsigned int entry_offset=8+8*i;
+ if(entry_offset + 8 > size)
return ;
- for(i=0; i<numEntries; i++)
+ /*@ assert entry_offset + 8 <= 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;
+ 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)
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)
+ if(offset >= size - 8)
return ;
-#ifdef DEBUG_OLE
+ /*@ assert offset < size - 8; */
{
- unsigned int j;
- log_info("Software ");
- for(j=0; j<count; j++)
+ const unsigned int count=get32u(buffer, offset + 4);
+ const unsigned int offset_soft=offset + 8;
+ /*@ assert offset_soft == offset + 8; */
+ if(count > size)
+ return ;
+ /*@ assert count <= size; */
+ if(offset_soft + count > size)
+ return ;
+ /*@ assert offset_soft + count <= size; */
+ if(count > 0)
{
- log_info("%c", dataPt[valStart + 4 + j]);
+ /*@ assert count > 0; */
+#ifdef DEBUG_OLE
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j<count; j++)
+ {
+ log_info("%c", buffer[offset_soft + j]);
+ }
+ log_info("\n");
+#endif
+ software2ext(ext, count, &buffer[offset_soft]);
}
- log_info("\n");
}
-#endif
- software2ext(ext, count, &dataPt[valStart + 4]);
}
/* tag: Software, type: VT_LPWSTR */
if(tag==0x12 && type==31)
{
- unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + 2 * count > dirLen)
+ if(offset >= size - 8)
return ;
-#ifdef DEBUG_OLE
+ /*@ assert offset < size - 8; */
{
- unsigned int j;
- log_info("Software ");
- for(j=0; j < 2 * count; j+=2)
+ const unsigned int count=get32u(buffer, offset + 4);
+ if(count > size)
+ return ;
+ /*@ assert count <= size; */
+ if(offset + 8 + 2 * count > size)
+ return ;
+ /*@ assert offset + 8 + 2 * count <= size; */
+ if(count > 0)
{
- log_info("%c", dataPt[valStart + 4 + j]);
+ /*@ assert count > 0; */
+#ifdef DEBUG_OLE
+ unsigned int j;
+ log_info("Software ");
+ for(j=0; j < 2 * count; j+=2)
+ {
+ log_info("%c", buffer[offset + 8 + j]);
+ }
+ log_info("\n");
+#endif
+ *ext=software_uni2ext(count, &buffer[offset + 8]);
}
- log_info("\n");
}
-#endif
- *ext=software_uni2ext(count, &dataPt[valStart + 4]);
}
+ /* tag: title, type: VT_LPSTR */
if(tag==0x02 && type==30 && *title==NULL)
{
- const unsigned int count=get32u(dataPt, valStart);
- if(valStart + 4 + count > dirLen)
+ if(offset + 8 > size)
return ;
- *title=(char*)MALLOC(count+1);
- memcpy(*title, &dataPt[valStart + 4], count);
- (*title)[count]='\0';
+ /*@ 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;
+ if(count > size)
+ return ;
+ /*@ assert count <= size; */
+ if(offset_tmp + count > size)
+ return ;
+ /*@ assert offset_tmp + count <= size; */
+ if(count > 0)
+ {
+ /*@ assert count > 0; */
+ char *tmp;
+ /*@ assert \valid_read(buffer + (0 .. size - 1)); */
+ /*@ assert \valid_read(buffer + (0 .. offset_tmp + count - 1)); */
+ tmp=(char*)MALLOC(count+1);
+ memcpy(tmp, &buffer[offset_tmp], count);
+ tmp[count]='\0';
#ifdef DEBUG_OLE
- log_info("Title %s\n", *title);
+ log_info("Title %s\n", tmp);
#endif
+ *title=tmp;
+ }
+ }
}
/* ModifyDate, type=VT_FILETIME */
if(tag==0x0d && type==64)
{
- uint64_t tmp=get64u(dataPt, valStart);
+ 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)
{
@@ -777,6 +994,53 @@ static void OLE_parse_summary_aux(const unsigned char *dataPt, const unsigned in
}
}
+/*@
+ @ requires 48 <= dirLen <= 1024*1024;
+ @ requires \valid_read(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);
+#ifdef DEBUG_OLE
+ dump_log(dataPt, dirLen);
+#endif
+#ifndef __FRAMAC__
+ if(dataPt[0]!=0xfe || dataPt[1]!=0xff)
+ return ;
+#endif
+ pos=get32u(dataPt, 44);
+ if(pos > dirLen - 8)
+ return ;
+ /*@ assert pos <= dirLen - 8; */
+ {
+ /* PropertySet */
+ const unsigned int size=get32u(dataPt, pos);
+ if(size <= 8 || size > dirLen || pos + size > dirLen)
+ return ;
+ /*@ assert 8 < size <= dirLen <=1024*1024; */
+ /*@ assert \valid_read(dataPt + (0 .. dirLen-1)); */
+ /*@ assert pos + size <= dirLen; */
+ /*@ assert \valid_read(dataPt + (0 .. pos+size-1)); */
+ /*TODO assert \valid_read(&dataPt[pos] + (0 .. 1024*1024-1-pos)); */
+ OLE_parse_PropertySet(&dataPt[pos], size, ext, title, file_time);
+ }
+}
+
+/*@
+ @ 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 +1048,70 @@ 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))
{
- 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));
+ if((mblock+1)> ministream_size>>uMiniSectorShift)
+ {
+ free(dataPt);
+ return NULL;
+ }
+ /*TODO assert \valid_read(ministream + (0 .. (mblock<<uMiniSectorShift) + (1<<uMiniSectorShift) -1)); */
+ memcpy(&dataPt[size_read], &ministream[mblock<<uMiniSectorShift], (1<<uMiniSectorShift));
}
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)
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)
+ return ;
+ if(ministream_size > 1024*1024 || le32(header->csectMiniFat) > 2048)
+ return ;
+ /*@ assert 0 < le32(header->csectMiniFat) <= 2048; */
{
- const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << le16(header->uSectorShift)) / 4;
+ const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << uSectorShift) / 4;
uint32_t *minifat;
unsigned char *ministream;
if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries, offset))==NULL)
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,7 +1125,7 @@ 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(summary!=NULL)
{
@@ -841,6 +1134,10 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
}
}
+/*@
+ @ 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,6 +1148,8 @@ 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";
if((file=fopen(file_recovery->filename, "rb"))==NULL)
@@ -865,10 +1164,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 +1200,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 +1216,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 +1229,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]=
@@ -952,6 +1270,12 @@ static void file_rename_doc(file_recovery_t *file_recovery)
#endif
switch(le16(dir_entry->namsiz))
{
+ 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 10:
if(memcmp(dir_entry->name, ".\0Q\0D\0F\0\0\0",10)==0)
ext="qdf-backup";
@@ -970,6 +1294,8 @@ static void file_rename_doc(file_recovery_t *file_recovery)
/* 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";
+ 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
@@ -1022,6 +1348,9 @@ static void file_rename_doc(file_recovery_t *file_recovery)
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";
+ /* Revit */
+ else if(memcmp(dir_entry->name, "R\0e\0v\0i\0t\0P\0r\0e\0v\0i\0e\0w\0004\0.\0000\0\0", 32)==0)
+ ext="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)
@@ -1082,6 +1411,8 @@ static void file_rename_doc(file_recovery_t *file_recovery)
#endif
}
}
+ if(ext==NULL && is_db==2)
+ ext="db";
}
free(dir_entries);
}
@@ -1099,8 +1430,81 @@ static void file_rename_doc(file_recovery_t *file_recovery)
file_rename(file_recovery, NULL, 0, 0, ext, 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_exe.c b/src/file_exe.c
index 1348db5..e0e6386 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,140 @@ 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;
+ @ 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)
+ le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr))
{
- /* NE Win16 */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_exe.extension;
- return 1;
- }
- if(le32(dos_hdr->e_lfanew)>0 &&
- le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
- (le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
- {
- /* Windows PE */
- if(le16(pe_hdr->Characteristics) & 0x2000)
- {
- /* Dynamic Link Library */
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension="dll";
- }
- else if(le16(pe_hdr->Characteristics) & 0x02)
+ const struct pe_image_file_hdr *pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
+ if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
{
+ /* NE Win16 */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
+ file_recovery_new->min_filesize=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr);
+ return 1;
}
- else
+ if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
{
+ /* Windows PE */
+ if(le16(pe_hdr->Characteristics) & 0x2000)
+ {
+ /* Dynamic Link Library */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=extension_dll;
+ }
+ else if(le16(pe_hdr->Characteristics) & 0x02)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_exe.extension;
+ }
+ else
+ {
#ifdef DEBUG_EXE
- log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
+ log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
#endif
- return 0;
- }
- file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
-#ifdef DEBUG_EXE
- {
- const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
- (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
- if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
- {
- log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
- log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
+ return 0;
}
- else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
+#ifdef DEBUG_EXE
{
- const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
(((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ if((const unsigned char*)(pe_image_optional32+1) <= buffer+buffer_size)
+ {
+ /*@ assert \valid_read(pe_image_optional32); */
+ if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
+ {
+ log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
+ log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
+ }
+ else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ }
+ log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
+ (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
+ }
}
- log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
- (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
- }
#endif
- {
- unsigned int i;
- uint64_t sum=0;
- const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
- ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
- for(i=0;
- i<le16(pe_hdr->NumberOfSections) &&
- (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
- i++,pe_image_section++)
{
- if(le32(pe_image_section->SizeOfRawData)>0)
+ unsigned int i;
+ uint64_t sum=le32(dos_hdr->e_lfanew) + sizeof(struct pe_image_file_hdr);
+ const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
+ ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
+ for(i=0;
+ i<le16(pe_hdr->NumberOfSections) &&
+ (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
+ i++,pe_image_section++)
{
+ if(le32(pe_image_section->SizeOfRawData)>0)
+ {
+ const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
#ifdef DEBUG_EXE
- log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
- (unsigned long)le32(pe_image_section->PointerToRawData),
- (unsigned long)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
+ log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
+ (unsigned long)le32(pe_image_section->PointerToRawData),
+ (unsigned long)(tmp-1));
#endif
- if(le32(pe_image_section->SizeOfRawData)%32==0)
- {
- if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
- sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
+ if(le32(pe_image_section->SizeOfRawData)%32==0)
+ {
+ if(sum < tmp)
+ sum=tmp;
+ }
}
- }
- if(le16(pe_image_section->NumberOfRelocations)>0)
- {
+ if(le16(pe_image_section->NumberOfRelocations)>0)
+ {
+ /*@ assert le16(pe_image_section->NumberOfRelocations)>0; */
+ const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ /*@ assert tmp > 0; */
#ifdef DEBUG_EXE
- log_debug("relocations 0x%lx-0x%lx\n",
- (unsigned long)le32(pe_image_section->PointerToRelocations),
- (unsigned long)le32(pe_image_section->PointerToRelocations)+1*le16(pe_image_section->NumberOfRelocations)-1);
+ log_debug("relocations 0x%lx-0x%lx\n",
+ (unsigned long)le32(pe_image_section->PointerToRelocations),
+ (unsigned long)(tmp-1));
#endif
- if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
- sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ if(sum < tmp)
+ sum = tmp;
+ }
}
- }
- if(le32(pe_hdr->NumberOfSymbols)>0)
- {
+ if(le32(pe_hdr->NumberOfSymbols)>0)
+ {
+ /*@ assert le32(pe_hdr->NumberOfSymbols)>0; */
+ const uint64_t tmp=(uint64_t)le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*(uint64_t)le32(pe_hdr->NumberOfSymbols);
+ /*@ assert tmp > 0; */
#ifdef DEBUG_EXE
- log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
- (long unsigned)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
+ log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
+ (long unsigned)(tmp-1));
#endif
- if(le32(pe_hdr->NumberOfSymbols)<0x10000)
- {
- if(sum < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
- sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
+ if(le32(pe_hdr->NumberOfSymbols)<0x10000)
+ {
+ if(sum < tmp)
+ sum = tmp;
+ }
}
+ /* It's not perfect, EXE overlay are not recovered */
+ file_recovery_new->calculated_file_size=sum;
}
- /* It's not perfect, EXE overlay are not recovered */
- file_recovery_new->calculated_file_size=sum;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->file_rename=&file_rename_pe_exe;
+ return 1;
}
- file_recovery_new->data_check=&data_check_size;
- file_recovery_new->file_check=&file_check_size;
- file_recovery_new->file_rename=&file_rename_pe_exe;
- return 1;
}
if(le16(dos_hdr->bytes_in_last_block) <= 512 &&
le16(dos_hdr->blocks_in_file) > 0 &&
@@ -183,23 +201,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 +244,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 +278,586 @@ 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;
}
- 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;
- return pos;
+ 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);
}
-static int PEVersion_aux(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+static int parse_StringFileInfo(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
{
+ /* https://docs.microsoft.com/en-us/windows/win32/menurc/stringfileinfo */
+ const struct PE_index *PE_index;
+ unsigned int pos;
+ unsigned int len;
+ unsigned int val_len;
+ if(6 > end)
+ {
+ return -1;
+ }
+ PE_index=(const struct PE_index*)buffer;
+ /*@ assert \valid_read(PE_index); */
+ len=le16(PE_index->len);
+ val_len=le16(PE_index->val_len);
+ 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;
+ if(pos > len)
+ return -1;
+ return parse_StringTable(file_recovery, &buffer[pos], len - pos, needle, needle_len, force_ext);
+}
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @ requires end > 0;
+ @ requires needle_len > 0;
+ @ requires \valid_read(buffer+(0..end-1));
+ @ requires \valid_read(needle+(0..needle_len-1));
+ @*/
+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;
- }
+ 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[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 ;
+ if(fread(&buffer, length, 1, file) != 1)
+ {
+ return ;
+ }
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown(&buffer, sizeof(buffer));
+#endif
+ if(parse_VS_VERSIONINFO(file_recovery, (const char *)&buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
+ {
+ return;
+ }
+ parse_VS_VERSIONINFO(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
+}
+
+/*@
+ @ requires \valid(file);
+ @ requires base <= 0x7fffffff;
+ @ requires dir_start <= 0x7fffffff;
+ @ requires \valid_read(pe_sections);
+ @ requires \valid(file_recovery);
+ @ requires valid_read_string((char*)&file_recovery->filename);
+ @*/
+static void pe_resource_language(FILE *file, const unsigned int base, const unsigned int dir_start, const struct pe_image_section_hdr *pe_sections, const unsigned int nbr_sections, file_recovery_t *file_recovery)
+{
+ struct rsrc_entries_s *rsrc_entries;
+ unsigned int count;
+ unsigned int i;
#ifdef DEBUG_EXE
- log_info(": ");
+ log_info("pe_resource_language(file, %u, %u)\n", base, dir_start);
#endif
- pt=ReadUnicodeStr(buffer, pt, pos);
- }
- }
+ {
+ 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;
+ }
+ log_info("pe_resource_language count=%u\n", count);
+ 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
+ /*@
+ @ loop invariant 0 <= i <= count;
+ @ loop variant count - i;
+ @*/
+ for(i=0; i<count; i++)
+ {
+ const struct rsrc_entries_s *rsrc_entry=&rsrc_entries[i];
#ifdef DEBUG_EXE
- log_info("\n");
+ log_info("resource lang=%u, %x, offset %u\n",
+ le32(rsrc_entry->Type),
+ le32(rsrc_entry->Pos),
+ base + (le32(rsrc_entry->Pos) & 0x7fffffff));
#endif
- }
+ {
+ struct rsrc_offlen buffer;
+ uint64_t off;
+ unsigned int len;
+ unsigned int j;
+ if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0)
+ {
+ free(rsrc_entries);
+ return ;
}
- else
+ if(fread(&buffer, 1, sizeof(buffer), file) != sizeof(buffer))
+ {
+ free(rsrc_entries);
+ return ;
+ }
+#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++)
{
- pos+=le16(PE_index->len)+le16(PE_index->val_len);
+ const struct pe_image_section_hdr *pe_section=&pe_sections[j];
+ if(le32(pe_section->VirtualAddress) <= off
+ && off < (uint64_t)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);
}
-static void PEVersion(FILE *file, const unsigned int offset, const unsigned int length, 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_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)
{
- char *buffer;
- if(length==0 || length > 1024*1024)
- return;
- if(fseek(file, offset, SEEK_SET)<0)
+ 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 ;
- buffer=(char*)MALLOC(length);
- if(fread(buffer, length, 1, file) != 1)
+ /*@ 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(buffer);
+ free(rsrc_entries);
return ;
}
- if(PEVersion_aux(file_recovery, buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
+#if defined(__FRAMAC__)
+ Frama_C_make_unknown((char *)rsrc_entries, count * sizeof(struct rsrc_entries_s));
+#endif
+ for(i=0; i<count; i++)
{
- free(buffer);
- return;
+ 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);
+ }
}
- PEVersion_aux(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
- free(buffer);
+ free(rsrc_entries);
}
-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 \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;
- 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_type(file, %u, %u)\n", base, dir_start);
#endif
- if(level > 2)
- return ;
- if(fseek(file, base + dir_start, SEEK_SET)<0)
+ /* TODO: remove these artifical limits ? */
+ if(base > 0x7fffffff || dir_start > 0x7fffffff)
return ;
- buffer_size=fread(buffer, 1, sizeof(buffer), file);
- if(buffer_size<16)
- 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 +867,92 @@ 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()
+{
+ 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;
+ file_hint_exe.register_header_check(&file_stats);
+ if(header_check_exe(buffer, BLOCKSIZE, 0u, &file_recovery, &file_recovery_new)!=1)
+ return 0;
+ strcpy(file_recovery_new.filename, "recup_dir.1/f0000000.exe");
+ /*@ 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("demo", "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_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 0cbad05..f706680 100644
--- a/src/file_list.c
+++ b/src/file_list.c
@@ -123,6 +123,7 @@ 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;
@@ -461,6 +462,7 @@ file_enable_t list_file_enable[]=
{ .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_mp3.c b/src/file_mp3.c
index 9cde947..65950a1 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;
+ file_hint_mp3.register_header_check(&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_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_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..6dc113f 100644
--- a/src/file_tiff.c
+++ b/src/file_tiff.c
@@ -50,6 +50,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,6 +136,8 @@ 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;
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)
@@ -161,8 +165,8 @@ 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);
+ register_header_check(0, tiff_header_be, sizeof(tiff_header_be), &header_check_tiff_be, file_stat);
+ register_header_check(0, tiff_header_le, sizeof(tiff_header_le), &header_check_tiff_le, file_stat);
}
void file_check_tiff(file_recovery_t *fr)
@@ -177,14 +181,14 @@ void file_check_tiff(file_recovery_t *fr)
return;
}
if(header.tiff_magic==TIFF_LITTLEENDIAN)
- calculated_file_size=header_check_tiff_le(fr, le32(header.tiff_diroff), 0, 0);
+ calculated_file_size=file_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);
+ calculated_file_size=file_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);
#endif
- if(fr->file_size < calculated_file_size || calculated_file_size==0)
+ 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,
diff --git a/src/file_tiff.h b/src/file_tiff.h
index ed2f86c..5ef2325 100644
--- a/src/file_tiff.h
+++ b/src/file_tiff.h
@@ -22,6 +22,7 @@
#ifdef __cplusplus
extern "C" {
#endif
+#define TIFF_ERROR 0xffffffffffffffffull
#define TIFF_BIGENDIAN 0x4d4d
#define TIFF_LITTLEENDIAN 0x4949
@@ -66,16 +67,66 @@ 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);
+
+/*@
+ @ requires \valid(file_recovery);
+ @ requires \valid(file_recovery->handle);
+ @*/
void file_check_tiff(file_recovery_t *file_recovery);
+/*@
+ @ 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 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 \initialized(&fr->extension);
+ @
+ */
+uint64_t file_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
+
+/*@
+ @ requires \valid(fr);
+ @ requires \valid(fr->handle);
+ @ requires \valid_read(&fr->extension);
+ @ requires \initialized(&fr->extension);
+ @
+ */
+uint64_t file_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, const unsigned int depth, const unsigned int count);
+
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @
+ */
+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);
+
+/*@
+ @ requires \valid_read(buffer+(0..buffer_size-1));
+ @
+ */
+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);
+
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..ffb6d4b 100644
--- a/src/file_tiff_be.c
+++ b/src/file_tiff_be.c
@@ -38,9 +38,18 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
extern const file_hint_t file_hint_jpg;
+/*@
+ @ 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 +59,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 +86,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,17 +137,18 @@ 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; */
offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp));
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;
}
sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep));
if(fseek(handle, be32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 ||
@@ -132,7 +156,7 @@ static uint64_t parse_strip_be(FILE *handle, const TIFFDirEntry *entry_strip_off
{
free(offsetp);
free(sizep);
- return -1;
+ return TIFF_ERROR;
}
for(i=0; i<nbr; i++)
{
@@ -145,6 +169,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 +211,13 @@ static uint64_t tiff_be_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert 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 +228,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 +250,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 +289,11 @@ 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)
+uint64_t file_check_tiff_be(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,36 +307,47 @@ 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(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(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_tag=be16(entry->tdir_tag);
const uint64_t val=(uint64_t)be32(entry->tdir_count) * tiff_type2size(be16(entry->tdir_type));
#ifdef DEBUG_TIFF
@@ -324,15 +364,18 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
#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;
}
@@ -354,18 +397,18 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
break;
case TIFFTAG_SUBIFD:
{
- const uint64_t new_offset=header_check_tiff_be(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_be(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -374,8 +417,8 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_be_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -385,6 +428,7 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
else if(be32(entry->tdir_count) > 1)
{
+ /*@ assert le32(entry->tdir_count) > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -393,30 +437,34 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(be16(entry->tdir_type)==4)
{
const unsigned int nbr=(be32(entry->tdir_count)<32?be32(entry->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
+ /*@
+ @ 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(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);
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -434,7 +482,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,30 +498,34 @@ uint64_t header_check_tiff_be(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_be(fr->handle, entry_strip_offsets, entry_strip_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_be(fr->handle, entry_tile_offsets, entry_tile_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(be32(*tiff_next_diroff) > 0)
+ if ( 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(fr, be32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
return max_offset;
}
-int header_check_tiff_be_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+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;
diff --git a/src/file_tiff_le.c b/src/file_tiff_le.c
index 2a4aa92..fb62732 100644
--- a/src/file_tiff_le.c
+++ b/src/file_tiff_le.c
@@ -38,10 +38,19 @@
#include "common.h"
#include "file_tiff.h"
#include "log.h"
+#if defined(__FRAMAC__)
+#include "__fc_builtin.h"
+#endif
extern const file_hint_t file_hint_raf;
extern const file_hint_t file_hint_jpg;
+/*@
+ @ 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 +60,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 +87,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,17 +138,18 @@ 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; */
offsetp=(uint32_t *)MALLOC(nbr*sizeof(*offsetp));
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;
}
sizep=(uint32_t *)MALLOC(nbr*sizeof(*sizep));
if(fseek(handle, le32(entry_strip_bytecounts->tdir_offset), SEEK_SET) < 0 ||
@@ -133,7 +157,7 @@ static uint64_t parse_strip_le(FILE *handle, const TIFFDirEntry *entry_strip_off
{
free(offsetp);
free(sizep);
- return -1;
+ return TIFF_ERROR;
}
for(i=0; i<nbr; i++)
{
@@ -146,6 +170,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 +212,13 @@ static uint64_t tiff_le_makernote(FILE *in, const uint32_t tiff_diroff)
uint64_t tile_bytecounts=0;
const TIFFDirEntry *entry;
if(tiff_diroff < sizeof(TIFFHeader))
- return -1;
+ return TIFF_ERROR;
if(fseek(in, tiff_diroff, SEEK_SET) < 0)
- return -1;
+ return TIFF_ERROR;
data_read=fread(buffer, 1, sizeof(buffer), in);
if(data_read<2)
- return -1;
+ return TIFF_ERROR;
+ /*@ assert 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 +229,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 +251,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 +290,11 @@ 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)
+uint64_t file_check_tiff_le(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,36 +308,47 @@ 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(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(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_tag=le16(entry->tdir_tag);
const uint64_t val=(uint64_t)le32(entry->tdir_count) * tiff_type2size(le16(entry->tdir_type));
#ifdef DEBUG_TIFF
@@ -324,16 +364,20 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
(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(strcmp(fr->extension,"sr2")!=0)
+ 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;
}
@@ -355,9 +399,9 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case TIFFTAG_EXIFIFD:
case TIFFTAG_KODAKIFD:
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -371,9 +415,9 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
else
{
- const uint64_t new_offset=header_check_tiff_le(fr, tmp, depth+1, 0);
- if(new_offset==-1)
- return -1;
+ const uint64_t new_offset=file_check_tiff_le(fr, tmp, depth+1, 0);
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -382,8 +426,8 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
case EXIFTAG_MAKERNOTE:
{
const uint64_t new_offset=tiff_le_makernote(fr->handle, tmp);
- if(new_offset==-1)
- return -1;
+ if(new_offset==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < new_offset)
max_offset=new_offset;
}
@@ -393,6 +437,7 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
}
else if(le32(entry->tdir_count) > 1)
{
+ /*@ assert le32(entry->tdir_count) > 1; */
switch(tdir_tag)
{
case TIFFTAG_EXIFIFD:
@@ -401,30 +446,34 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(le16(entry->tdir_type)==4)
{
const unsigned int nbr=(le32(entry->tdir_count)<32?le32(entry->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
+ /*@
+ @ 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(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);
}
break;
case TIFFTAG_STRIPOFFSETS:
@@ -442,7 +491,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,32 +507,36 @@ uint64_t header_check_tiff_le(file_recovery_t *fr, const uint32_t tiff_diroff, c
if(entry_strip_offsets != NULL && entry_strip_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_le(fr->handle, entry_strip_offsets, entry_strip_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
if(entry_tile_offsets != NULL && entry_tile_bytecounts != NULL)
{
const uint64_t tmp=parse_strip_le(fr->handle, entry_tile_offsets, entry_tile_bytecounts);
- if(tmp==-1)
- return -1;
+ if(tmp==TIFF_ERROR)
+ return TIFF_ERROR;
if(max_offset < tmp)
max_offset=tmp;
}
- tiff_next_diroff=(const uint32_t *)entry;
- if(le32(*tiff_next_diroff) > 0)
+ if ( 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(fr, le32(*tiff_next_diroff), depth+1, count+1);
+ if(new_offset != TIFF_ERROR && max_offset < new_offset)
+ max_offset=new_offset;
+ }
}
return max_offset;
}
-int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+int header_check_tiff_le(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
- const char raf_fp[15]={0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x0d, 0x00, 0x01};
+ const 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))
@@ -526,7 +578,7 @@ int header_check_tiff_le_new(const unsigned char *buffer, const unsigned int buf
file_recovery_new->extension="sr2";
else if(strncmp(tag_make, "SONY ",5)==0)
file_recovery_new->extension="arw";
- else if(memcmp(tag_make, "NIKON CORPORATION", 18)==0)
+ else if(tag_make < (const char *)buffer + buffer_size - 18 && memcmp(tag_make, "NIKON CORPORATION", 18)==0)
file_recovery_new->extension="nef";
}
}
diff --git a/src/file_txt.c b/src/file_txt.c
index 289beb7..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 */
@@ -1156,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);
@@ -1165,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);
@@ -1491,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_zip.c b/src/file_zip.c
index 5d74cbd..11f2cc9 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,143 +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";
- /* 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);
+ /*@ assert fr->file_size < 0x8000000000000000; */
}
+ /*@ assert fr->file_size < 0x8000000000000000; */
#ifdef DEBUG_ZIP
log_info("\n");
#endif
@@ -324,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)
{
@@ -339,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;
@@ -352,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
@@ -362,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))
{
@@ -378,17 +465,26 @@ static int zip_parse_file_entry(file_recovery_t *fr, const char **ext, const uns
#ifdef DEBUG_ZIP
log_trace("Searched footer, got length %lli\n", (long long int)pos);
#endif
- if (pos < 0)
+ if (pos < 0 || pos > 0x7fffffffffffffff)
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;
@@ -417,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);
@@ -429,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 */
@@ -447,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 {
@@ -468,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;
@@ -492,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 {
@@ -511,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)
@@ -531,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 {
@@ -546,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",
@@ -559,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;
@@ -570,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)
@@ -588,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 {
@@ -603,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;
@@ -622,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
@@ -632,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);
@@ -640,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)
{
@@ -690,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;
@@ -710,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)
{
@@ -719,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
@@ -791,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];
@@ -798,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 &&
@@ -879,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);
@@ -887,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 61bd77c..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,13 +711,14 @@ 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;
}
@@ -618,7 +745,7 @@ 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;
}
@@ -626,7 +753,7 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
}
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
@@ -641,7 +768,7 @@ int header_ignored_adv(const file_recovery_t *file_recovery, const file_recovery
}
if(fr_test.file_size>0)
return 1;
- 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;
}
@@ -655,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;
}
@@ -679,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));
@@ -692,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 352a15e..1e2fb4e 100644
--- a/src/filegen.h
+++ b/src/filegen.h
@@ -119,31 +119,179 @@ 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 \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/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/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 0652a09..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>
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/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/photorec.c b/src/photorec.c
index f98ee43..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;
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/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
}
}