summaryrefslogtreecommitdiffstats
path: root/src/file_fs.c
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2014-07-26 18:12:21 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2014-07-26 18:12:21 +0200
commit5bc6372cacd71f2eb23350fc1b5df1cbd18ba5e1 (patch)
tree23af181938be1cfbdb8cee0afe7d4381f1027941 /src/file_fs.c
parent0c1bc9427c427fb7d65e09f42ab2716382011c5c (diff)
PhotoRec: stricter check for Zope .fs
Diffstat (limited to 'src/file_fs.c')
-rw-r--r--src/file_fs.c60
1 files changed, 51 insertions, 9 deletions
diff --git a/src/file_fs.c b/src/file_fs.c
index 9a15643..e1708a8 100644
--- a/src/file_fs.c
+++ b/src/file_fs.c
@@ -30,6 +30,8 @@
#include "types.h"
#include "common.h"
#include "filegen.h"
+#include "common.h"
+#include "log.h"
static void register_header_check_fs(file_stat_t *file_stat);
static int header_check_fs(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);
@@ -44,20 +46,60 @@ const file_hint_t file_hint_fs= {
.register_header_check=&register_header_check_fs
};
-static const unsigned char fs_header[4]={ 'F', 'S','2','1' };
+/* See http://www.linkitsolutions.org/uploader/dilu/lib/python2.6/site-packages/ZODB/FileStorage/FileStorage.py for more information */
+struct transaction_header
+{
+ uint64_t id;
+ uint64_t len;
+ char status;
+ uint16_t len_username;
+ uint16_t len_descr;
+ uint16_t len_ext;
+} __attribute__ ((__packed__));
-static void register_header_check_fs(file_stat_t *file_stat)
+static data_check_t data_check_fs(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
- register_header_check(0, fs_header,sizeof(fs_header), &header_check_fs, file_stat);
+ while(file_recovery->calculated_file_size + buffer_size/2 >= file_recovery->file_size &&
+ file_recovery->calculated_file_size + 0x11 < file_recovery->file_size + buffer_size/2)
+ {
+ const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
+ const struct transaction_header *hdr=(const struct transaction_header *)&buffer[i];
+ const uint64_t len=be64(hdr->len);
+ if(len < sizeof(struct transaction_header)-8)
+ return DC_STOP;
+ if(hdr->status!=' ' && hdr->status!='p' && hdr->status!='c' && hdr->status!='u')
+ return DC_STOP;
+#ifdef DEBUG_FS
+ log_info("0x%08llx len=%llu status=%c\n", (long long unsigned)file_recovery->calculated_file_size, (long long unsigned)len, hdr->status);
+#endif
+ file_recovery->calculated_file_size+=len+8;
+#ifdef DEBUG_FS
+ log_info("0x%08llx\n", (long long unsigned)file_recovery->calculated_file_size);
+#endif
+ }
+ return DC_CONTINUE;
}
static int header_check_fs(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]=='F' && buffer[1]=='S' && buffer[2]=='2' && buffer[3]=='1')
- {
- reset_file_recovery(file_recovery_new);
- file_recovery_new->extension=file_hint_fs.extension;
+ const struct transaction_header *hdr=(const struct transaction_header *)&buffer[4];
+ const uint64_t len=be64(hdr->len);
+ if(len < sizeof(struct transaction_header)-8)
+ return 0;
+ if(hdr->status!=' ' && hdr->status!='p' && hdr->status!='c' && hdr->status!='u')
+ return 0;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_fs.extension;
+ if(file_recovery_new->blocksize < 0x11)
return 1;
- }
- return 0;
+ file_recovery_new->data_check=&data_check_fs;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->calculated_file_size=4;
+ return 1;
+}
+
+static void register_header_check_fs(file_stat_t *file_stat)
+{
+ static const unsigned char fs_header[4]={ 'F', 'S','2','1' };
+ register_header_check(0, fs_header,sizeof(fs_header), &header_check_fs, file_stat);
}