/*************************************************************************** * Copyright (C) 2010 by Roberto Maar * * robi6@users.sf.net * * * * This program 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, see . * * * * * * C Implementation: magic_block_scan * ***************************************************************************/ #include #include #include #include #include #include "util.h" #include "inode.h" #include "magic.h" #include "extent_db.h" //#define DEBUG_MAGIC_SCAN extern ext2_filsys current_fs ; extern char* magicfile; ext2fs_block_bitmap d_bmap = NULL ; static __u32 get_block_len(char *buf){ int len = current_fs->blocksize -1; while ((len >= 0) && (!(*(buf + len)))) len--; return ++len; } struct found_data_t* free_file_data(struct found_data_t* old){ int tmp; if(old->inode) free(old->inode); if(old->scan_result) free(old->scan_result); if(old->name) free(old->name); if(old->priv){ old->func(NULL,&tmp,0,4,old); old->priv = NULL; } free(old); return NULL; } static struct found_data_t* copy_file_data(struct found_data_t* old){ static struct found_data_t* new = NULL; int str_len = strlen(old->scan_result)+1; int name_len = strlen(old->name)+1; //FIXME private new = malloc(sizeof(struct found_data_t)); if (!new) return NULL; memcpy(new,old,sizeof(struct found_data_t)); new->scan_result = malloc(str_len); new->name = malloc(name_len); new->inode = new_inode(); if(old->priv){ new->priv = malloc(old->priv_len); if (new->priv) memcpy(new->priv,old->priv,old->priv_len); else new->priv_len = 0; } if((!new->scan_result) || (!new->name) || (!new->inode)){ if (new->priv){ free (new->priv); new->priv = NULL; } new = free_file_data(new); fprintf(stderr,"ERROR; while allocate memory for found copy file struct\n"); } else{ memcpy(new->scan_result,old->scan_result,str_len); memcpy(new->name,old->name,name_len); memcpy(new->inode,old->inode,128); } return new; } static struct found_data_t* new_file_data(blk_t blk,__u32 scan,char *magic_buf, unsigned char* buf, __u32 *f, __u32 buf_length){ struct found_data_t *new; int str_len; int name_len; char *c; int def_len = 20; char name_str[20]; new = malloc(sizeof(struct found_data_t)); if (!new) return NULL; new->first = blk; new->last = blk; new->buf_length = buf_length; new->next_offset = 0; new->last_match_blk = 0; new->scantype = H_F_Carving; new->scan = scan; new->size = 0; new->h_size = 0; new->priv_len = 0; new->func = NULL; new->priv = NULL; if ( ident_file(new,&scan,magic_buf,buf)){ new->type = scan; str_len = strlen(magic_buf) + 1; c = strpbrk(magic_buf,";:, "); if (c){ *c = 0; name_len = c - magic_buf + def_len; } else name_len = str_len + def_len; new->scan_result = malloc(str_len); new->name = malloc(name_len); new->inode = new_inode(); if((!new->scan_result) || (!new->name) || (!new->inode)){ new = free_file_data(new); fprintf(stderr,"ERROR; while allocate memory for found file struct\n"); } else{ strcpy(new->scan_result,magic_buf); strncpy(new->name, magic_buf , name_len - def_len+1); sprintf(name_str,"/%010lu",(long unsigned int)blk); strcat(new->name,name_str); get_file_property(new); new->func(buf,&name_len,scan,2,new); } if ((!new->func) || (!new->first)) { *f = 0; return free_file_data(new); } } *f++; //"gcc warning: value computed is not used" warning is okay return new; } static struct found_data_t* recover_file_data(char *des_dir, struct found_data_t* this, __u32 *follow){ recover_file(des_dir,"MAGIC-3",this->name,(struct ext2_inode*)this->inode, 0 , 1); *follow = 0; return free_file_data(this); } static struct found_data_t* forget_file_data(struct found_data_t* this, __u32 *p_follow){ #ifdef DEBUG_MAGIC_SCAN printf("TRASH : %s : leng %lu : begin %lu\n", this->name, this->inode->i_size , this->first); // dump_inode(stdout, "",0, (struct ext2_inode *)this->inode, 1); #endif free_file_data(this); *p_follow = 0; return NULL; } static __u32 add_file_data(struct found_data_t* this, blk_t blk, __u32 scan ,__u32 *f){ if (inode_add_block(this->inode , blk )){ this->last = blk; (*f)++ ; } return *f ; } static int file_data_correct_size(struct found_data_t* this, int size){ unsigned long long i_size; int flag=0; int i,ref; if (size <= current_fs->blocksize){ flag = 1; i_size = (((unsigned long long)this->inode->i_size_high) << 32) + this->inode->i_size; i_size -= (current_fs->blocksize - size); this->inode->i_size = i_size & 0xffffffff ; this->inode->i_size_high = i_size >> 32 ; if ((i_size <= (12 * current_fs->blocksize))&&(!(this->inode->i_flags & EXT4_EXTENTS_FL))) { //correcting small ext3 inodes if(this->inode->i_block[EXT2_IND_BLOCK]){ this->inode->i_block[EXT2_IND_BLOCK] = 0; this->inode->i_block[EXT2_DIND_BLOCK] = 0; this->inode->i_block[EXT2_TIND_BLOCK] = 0; } for (i = current_fs->blocksize,ref=1; iblocksize,ref++); while (ref < EXT2_IND_BLOCK){ this->inode->i_block[ref] = 0; ref++; } } } return flag; } static int check_file_data_end(struct found_data_t* this,unsigned char *buf, __u32 mask){ int size; int ret = 0; size = get_block_len((char*)buf); ret = (this->func(buf, &size ,this->scan ,0 , this) & mask) ; if (ret) ret = file_data_correct_size(this,size); return (mask & FORCE_RECOVER) ? 1 : ret ; } static int check_file_data_possible(struct found_data_t* this, __u32 scan ,unsigned char *buf){ int size ; size = (scan & M_SIZE ); return this->func(buf, &size ,scan ,1 , this); } static int check_meta3_block(char *block_buf, blk_t blk, __u32 size, int flag){ blk_t block, *pb_block; int i,j ; size = (size + 3) & 0xFFFFFC ; if (! size ) return 0; for (i = size-4 ; i>=0 ; i -= 4){ pb_block = (blk_t*)(block_buf+i); block = ext2fs_le32_to_cpu(*pb_block); if( block && (block < current_fs->super->s_blocks_count) && (ext2fs_test_block_bitmap( d_bmap, block)) && ( ((!flag) && (!ext2fs_test_block_bitmap(bmap,block))) || (((flag == 1) && (i == (size -4)) && (i>4))||(!ext2fs_test_block_bitmap(bmap,block))) || (flag == 2) ) ){ if (i) { //work not by sparse file for (j = i - 4 ; j >= 0 ;j -= 4){ if (block == ext2fs_le32_to_cpu(*((blk_t*)(block_buf+j)))) return 0; } } else { if (block == blk+1) return 1; } } else return 0; } return 0; //never used } static int check_indirect_meta3(char *block_buf){ blk_t *pb_block; blk_t last; int i = current_fs->blocksize/sizeof(blk_t) -1; int count=0; int next =0; pb_block = (blk_t*)block_buf; last = ext2fs_le32_to_cpu(*pb_block); while (i && last ) { pb_block++; i--; count++; if ((ext2fs_le32_to_cpu(*pb_block) -1) == last) next++; if (ext2fs_le32_to_cpu(*pb_block)) last = ext2fs_le32_to_cpu(*pb_block); else break; } return (next >= (count>>1)) ? 1 : 0; } static int check_dindirect_meta3(char * block_buf){ __u32 *p_blk; __u32 block; char *buf = NULL; int ret = 0; buf = malloc(current_fs->blocksize); if (buf) { p_blk = (__u32*) block_buf; block = ext2fs_le32_to_cpu(*p_blk); io_channel_read_blk ( current_fs->io, block, 1, buf ); if (check_meta3_block(buf, block, get_block_len(buf),2)){ ret = check_indirect_meta3(buf); } free (buf); } return ret; } static int check_tindirect_meta3(char * block_buf){ __u32 *p_blk; __u32 block; char *buf = NULL; int ret = 0; buf = malloc(current_fs->blocksize); if (buf) { p_blk = (__u32*) block_buf; block = ext2fs_le32_to_cpu(*p_blk); io_channel_read_blk ( current_fs->io, block, 1, buf ); if (check_meta3_block(buf, block, get_block_len(buf),2)){ ret = check_dindirect_meta3(buf); } free (buf); } return ret; } static int check_meta4_block(unsigned char *block_buf, blk_t blk, __u32 size){ return (ext2fs_extent_header_verify((void*)block_buf, current_fs->blocksize)) ? 0 : 1; /* __u16 *p_h16; __u16 h16; if(!((block_buf[0] == 0x0a) && (block_buf[1] == (unsigned char)0xf3))) return 0; p_h16 = (__u16*)(block_buf+2); h16 = ext2fs_le16_to_cpu(*p_h16); p_h16 = (__u16*)(block_buf+4); if (ext2fs_le16_to_cpu(*p_h16) != (__u16)((current_fs->blocksize -12)/ 12)) return 0; if ((!h16) || (h16 > ext2fs_le16_to_cpu(*p_h16))) return 0; return 1 ;*/ } static int check_dir_block(unsigned char *block_buf, blk_t blk, __u32 size){ struct ext2_dir_entry_2 *dir_entry; ext2_ino_t inode_nr; __u16 len; __u16 p_len; int i; dir_entry = (struct ext2_dir_entry_2*)block_buf; inode_nr = ext2fs_le32_to_cpu(dir_entry->inode); if ((inode_nr && (inode_nr < EXT2_GOOD_OLD_FIRST_INO)) || (inode_nr > current_fs->super->s_inodes_count)) return 0; len = ext2fs_le16_to_cpu(dir_entry->rec_len); if ((len < 8) || (len % 4) || (len> current_fs->blocksize) ||(len < (((unsigned)dir_entry->name_len + 11) & ~3 ))||(!dir_entry->name_len) || (! dir_entry->file_type) || (dir_entry->file_type & 0xf8)) return 0; for (i=0; iname_len;i++) if(!dir_entry->name[i]) return 0; if((dir_entry->name_len == 1) && ((dir_entry->name[0] < 33) || (dir_entry->name[0] > 126))) return 0; loop: p_len =len; if (len < current_fs->blocksize - 12){ dir_entry = (struct ext2_dir_entry_2*) (((void*)dir_entry) + len); len = ext2fs_le16_to_cpu(dir_entry->rec_len); if ((len < 8) || (len % 4) || ((len+p_len) > current_fs->blocksize) ||(len < (((unsigned)dir_entry->name_len + 11) & ~3 ))||(!dir_entry->name_len) || (! dir_entry->file_type) || (dir_entry->file_type & 0xf8) ) return 0; if ((dir_entry->name_len & 0x01) && dir_entry->name[(unsigned)dir_entry->name_len]) goto loop; }else if (block_buf[current_fs->blocksize -1]) return 0; return 1; } static int check_acl_block(unsigned char *block_buf, blk_t blk, __u32 size){ __u32 *p32; int i; p32 = (__u32*)block_buf; if ((!(*p32)) || (ext2fs_le32_to_cpu(*p32) & (~ 0xEA030000))) return 0; p32 += 2; if ((!(*p32)) || (ext2fs_le32_to_cpu(*p32) > 0xff)) return 0; p32++; if (! (*p32)) return 0; p32++; for (i = 0; i<4; i++){ if (*p32) return 0; p32++; } return (size > (current_fs->blocksize-32)) ? 1 : 0; } static int add_ext4_extent_idx_data(struct found_data_t* this, struct extent_area* ea){ return inode_add_extent(this->inode ,ea, &(this->last), 1); } //for future use ; gcc warning is okay static int add_ext4_extent_data(struct found_data_t* this, struct extent_area* ea){ return inode_add_extent(this->inode ,ea, &(this->last), 0); } static int add_ext3_file_meta_data(struct found_data_t* this, char *buf, blk_t blk){ blk_t next_meta = 0; blk_t meta = 0; blk_t last_data = 0; int ret = 0; if (check_indirect_meta3(buf)){ ret = inode_add_meta_block(this->inode , blk, &last_data, &next_meta, buf ); this->last = last_data; this->scantype |= DATA_METABLOCK; } if (ret && (next_meta > 10 && (ext2fs_test_block_bitmap ( d_bmap, next_meta) && (! ext2fs_test_block_bitmap( bmap, next_meta))))){ meta = next_meta; next_meta = 0; io_channel_read_blk ( current_fs->io, meta, 1, buf ); if (check_meta3_block(buf, meta, get_block_len(buf),1) && check_dindirect_meta3(buf)){ ret = inode_add_meta_block(this->inode , meta, &last_data, &next_meta, buf ); this->last = last_data; if (ret && (next_meta > 10 && (ext2fs_test_block_bitmap ( d_bmap, next_meta) && (! ext2fs_test_block_bitmap( bmap, next_meta))))){ meta = next_meta; next_meta = 0; io_channel_read_blk ( current_fs->io, meta, 1, buf ); if (check_meta3_block(buf, meta, get_block_len(buf),1) && check_tindirect_meta3(buf)){ ret = inode_add_meta_block(this->inode , meta, &last_data, &next_meta, buf ); this->last = last_data; } } } } return ret ; } // skip not of interest blocks : return 1 if skiped static int skip_block(blk_t *p_blk ,struct ext2fs_struct_loc_generic_bitmap *ds_bmap ){ struct ext2fs_struct_loc_generic_bitmap *p_bmap; blk_t o_blk; int flag = 0; int diff = (current_fs->blocksize == 1024)?1:0; o_blk = (*p_blk) >> 3; p_bmap = (struct ext2fs_struct_loc_generic_bitmap *) bmap; while (((! *(ds_bmap->bitmap + o_blk)) || (*(p_bmap->bitmap + o_blk) == (unsigned char)0xff) || (*(ds_bmap->bitmap + o_blk) == *(p_bmap->bitmap + o_blk))) && (o_blk < (ds_bmap->end >> 3))){ o_blk ++; flag = 1; } *p_blk = (o_blk << 3) + diff ; return flag; } static int is_ecryptfs(unsigned char* buf){ int ret = 0; if ((!buf[0]) && (!buf[20]) && (!buf[21]) && (buf[22]) && (!buf[23]) && (!buf[24]) && ((buf[8] ^ buf[12]) == 0x3c) && ((buf[9] ^ buf[13]) == 0x81) && ((buf[10] ^ buf[14]) == 0xb7) && ((buf[11] ^ buf[15]) == 0xf5)) ret =1; return ret; } //magic scanner //FIXME static int magic_check_block(unsigned char* buf,magic_t cookie , magic_t cookie_f, char *magic_buf, __u32 size, blk_t blk, int deep){ int count = current_fs->blocksize -1 ; int len; char text[100] = ""; char *p_search; __u32 retval = 0; char token[20]; memset(magic_buf,0,100); //FIXME memset(text,0,100); while ((count >= 0) && (*(buf+count) == 0)) count-- ; if (ext2fs_le32_to_cpu(*(blk_t*)buf) == blk +1){ if (check_meta3_block((char*)buf, blk, count+1, 0)){ retval = M_EXT3_META ; goto out; } } if (size > current_fs->blocksize){ strncpy(text,magic_buffer(cookie_f, buf, 512),60); if ((!strncmp(text,"data",4))|| (!strncmp((char*)buf,"ID3",3))){ strncpy(text,magic_buffer(cookie_f,buf , size),60); strncpy(magic_buf, magic_buffer(cookie , buf , size),60); } else{ strncpy(magic_buf, magic_buffer(cookie , buf , 512),60); } } else{ strncpy(text,magic_buffer(cookie_f,buf , size),60); strncpy(magic_buf, magic_buffer(cookie , buf , size),60); } if (!strncmp(text,"data",4)){ if (count == -1) { retval |= M_BLANK; goto out; } } if((strstr(magic_buf,"text/")) || (strstr(magic_buf,"application/") && (strstr(text,"text")))){ retval |= M_TXT ; if (deep && count && (count > 60))// current_fs->blocksize)) strncpy(magic_buf, magic_buffer(cookie , buf , count-1),60); } //loop: if ((strstr(magic_buf,"text/plain"))||(strstr(magic_buf,"text/html"))){ char *type; char searchstr[] = "bin/perl python PEM SGML OpenSSH libtool M3U Tcl=script Perl=POD module=source PPD make=config bin/make awk bin/ruby bin/sed bin/expect bash "; char searchtype[] = "text/x-perl text/x-python text/PEM text/SGML text/ssh text/libtool text/M3U text/tcl text/POD text/x-perl text/PPD text/configure text/x-makefile text/x-awk text/ruby text/sed text/expect text/x-shellscript "; if (deep && (count > 250) && (!strncmp((char*)buf,"From ",5))){ p_search = (char*)buf + 6; for (len = 0; (len < (count -7)) ; len++){ if( *(p_search++) == 0x40) break; } for (;len<(count -7); len++){ if( *(p_search++) == 0x0a) break; } if ((len < (count - 180)) && ((!strncmp(p_search,"From:",5))||(!strncmp(p_search,"Return-Path:",12)))){ strncpy(magic_buf,"message/rfc822",15); retval = M_TXT | M_MESSAGE | M_CLASS_1 ; goto out; } } if(!(strstr(magic_buf,"text/html"))){ if (deep){ //FIXME p_search = searchstr; type = searchtype; while (*p_search){ len=0; while((*p_search) != 0x20){ token[len] = ((*p_search)==0x3d)? 0x20 : (*p_search); p_search++; len++; } token[len] = 0; if (strstr(text,token)){ len = 0; while (type[len] != 0x20){ magic_buf[len] = type[len]; len++; } magic_buf[len] = 0; retval = (M_TXT | M_CLASS_1); goto out; } p_search++; while (type[0] != 0x20) type++; if (*type) type++; } if((count < (current_fs->blocksize -2)) || (!buf[-1])){ p_search = (char*)buf + 6; for (len = 0; len < 20 ; len++){ if((*p_search ==0x0a) || (*(p_search++) == 0x20)) break; } if (len < 20){ for (len = 6; len < 80 ; len++) if( buf[len] == 0x0a) break; if (len <80){ retval = M_TXT | M_CLASS_2 ; goto out; } } } } retval |= (M_DATA | M_TXT) ; goto out; } } if (strstr(magic_buf,"application/vnd.oasis.opendocument")){ retval |= (M_APPLI | M_BINARY | M_CLASS_1); goto out; } if (strstr(magic_buf,"charset=binary")){ retval |= M_BINARY ; } //FIXME test: catch of properties from file-5.04 if ((retval & M_TXT) && ((retval & M_BINARY) ||// (strstr(magic_buf,"charset=unknown-8bit") && (count > 8)) || (strstr(text,"very long lines, with no")))){ retval |= M_DATA; } else{ if ((strstr(magic_buf,"application/octet-stream")) && (!(strncmp(text,"data",4)))){ if (is_ecryptfs (buf)) strncpy(text,"ecryptfs ",9); else retval |= M_DATA; } } if ((retval & M_DATA) || (*(buf+7) < EXT2_FT_MAX) || (count < 32) ) { if (check_meta4_block(buf, blk, count+1)){ retval = M_EXT4_META ; goto out; } if (check_dir_block(buf, blk, count+1)){ retval = M_DIR ; goto out; } if (check_acl_block(buf, blk, count+1)){ retval = M_ACL ; goto out ; } } if (retval & M_DATA) goto out; if (deep && (retval & M_TXT)){ char searchstr[] = "html PGP rtf texmacs vnd.graphviz x-awk x-gawk x-info x-msdos-batch x-nawk x-perl x-php x-shellscript x-texinfo x-tex x-vcard x-xmcd xml "; p_search = searchstr; while (*p_search){ len=0; while((*p_search) != 0x20){ token[len] = *p_search; p_search++; len++; } token[len] = 0; if (strstr(magic_buf,token)){ //strncpy(magic_buf,text,60); retval |= M_CLASS_1; break; } p_search++; } if (! (retval & M_CLASS_1)) retval |= M_CLASS_2 ; goto out; } if (strstr(magic_buf,"application/octet-stream")){ char searchstr[] = "7-zip cpio CD-ROM MPEG 9660 Targa Kernel boot SQLite OpenOffice.org VMWare3 VMware4 JPEG ART PCX IFF DIF RIFF ATSC ScreamTracker matroska LZMA Audio=Visual Sample=Vision ISO=Media ext2 ext3 ext4 LUKS python ESRI=Shape ecryptfs Matlab=v5 "; p_search = searchstr; while (*p_search){ len=0; while((*p_search) != 0x20){ token[len] = ((*p_search)==0x3d)? 0x20 : (*p_search); p_search++; len++; } token[len] = 0; if (strstr(text,token)){ strncpy(magic_buf,text,60); retval |= ( M_APPLI | M_ARCHIV | M_CLASS_1 ); break; } p_search++; } if (! (retval & M_APPLI)) retval |= M_DATA ; goto out; } else { if (strstr(magic_buf,"application/")){ if (strstr(magic_buf,"x-tar")) retval |= ( M_APPLI | M_TAR | M_CLASS_1) ; else{ if((!strstr(magic_buf,"x-archive")) &&((strstr(magic_buf,"x-elc") || strstr(magic_buf,"keyring") || strstr(magic_buf,"x-arc")||strstr(magic_buf,"keystore")||strstr(magic_buf,"x-123")|| strstr(magic_buf,"fontobject")))){ //FIXME fontobject //conflict x-123 <-> Targa on many file-versions if (strstr(magic_buf,"x-123") && (strstr(text,"Targa"))){ strncpy(magic_buf,text,60); retval |= ( M_APPLI | M_ARCHIV | M_CLASS_1 ); }else retval = M_DATA; } else { if (strstr(magic_buf,"encrypted") || strstr(magic_buf,"x-tex-tfm") || strstr(magic_buf,"x-compress")) retval |= ( M_APPLI | M_CLASS_2 ); else retval |= ( M_APPLI | M_CLASS_1 ); } } goto out; } else { if (strstr(magic_buf,"image/")){ if (strstr(magic_buf,"x-portable-") && (! isspace( *(buf+2)))){ retval = M_DATA; } else retval |= ( M_IMAGE | M_CLASS_1 ); goto out; } else { if (strstr(magic_buf,"audio/")){ if (strstr(magic_buf,"x-mp4a-latm") || strstr(magic_buf,"x-hx-aac-adts")) retval = M_DATA; else { if(strstr(magic_buf,"mpeg")) retval |= ( M_AUDIO | M_CLASS_2 ); else retval |= ( M_AUDIO | M_CLASS_1 ); } goto out; } else{ if (strstr(magic_buf,"video/")){ retval |= ( M_VIDEO | M_CLASS_1 ); goto out; } else { if (strstr(magic_buf,"message/")){ retval |= ( M_MESSAGE | M_CLASS_1); goto out; } else{ if (strstr(magic_buf,"model/")){ retval |= ( M_MODEL | M_CLASS_2); goto out; } else{ if (strstr(magic_buf," V2 Document")){ retval |= (M_APPLI | M_ARCHIV | M_CLASS_1 ); goto out; } } } } } } } } out: #ifdef DEBUG_MAGIC_SCAN printf("BLOCK_SCAN : Block = %010u ; 0x%08x\n",blk, retval & 0xffffe000); blockhex(stdout,buf,0,(count < (64)) ? count : 64 ); #endif retval |= (count+1); return retval; } static struct found_data_t* soft_border(char *des_dir, unsigned char *buf, struct found_data_t* file_data, __u32* follow, blk_t blk ,blk_t* last_rec, __u32 mask){ if ( check_file_data_end(file_data, buf ,mask )){ file_data = recover_file_data(des_dir, file_data, follow); *last_rec = blk; } else{ file_data = forget_file_data(file_data, follow); } return file_data; } static __u32 check_next_border(struct ext2fs_struct_loc_generic_bitmap *ds_bmap, blk_t blk, __u32 count){ __u32 ret = 0; __u32 i = 0; while ((i < count) && (! ret) && ((blk + i) < ds_bmap->end)){ ret = (ext2fs_test_block_bitmap(d_bmap, blk + i) && (! ext2fs_test_block_bitmap(bmap, blk +i)))? 0 :1 ; i++; } return (ret) ? i-1 : 0 ; } static int get_range(blk_t* p_blk ,struct ext2fs_struct_loc_generic_bitmap *ds_bmap, unsigned char* buf, int *flag){ blk_t begin; blk_t end; int count=1; int diff = (current_fs->blocksize == 1024)?1:0; for (begin = *p_blk; begin <= ds_bmap->end ; begin++){ if((!((begin-diff) & 0x7)) && skip_block(&begin, ds_bmap)){ #ifdef DEBUG_MAGIC_SCAN printf("jump to %lu \n",begin); #endif } *p_blk = begin; if (begin > ds_bmap->end) return 0; if (ext2fs_test_block_bitmap ( d_bmap, begin) && (! ext2fs_test_block_bitmap( bmap, begin))) break; } if (begin > ds_bmap->end) return 0; for (end = begin,count=1 ; ((count < MAX_RANGE) && (end < ds_bmap->end-1)); ){ if (ext2fs_test_block_bitmap(d_bmap, end+1) && (! ext2fs_test_block_bitmap( bmap, end+1))){ end++; count++; } else break; } *(p_blk+1) = end; //add the previous block to the end of the buffer if (io_channel_read_blk ( current_fs->io,(*p_blk)-1,1,buf - current_fs->blocksize) || (io_channel_read_blk ( current_fs->io, begin , count, buf ))){ fprintf(stderr,"ERROR: while read block %10u + %d\n",begin,count); return 0; } if (count && count < MAX_RANGE){ memset(buf+(count * current_fs->blocksize), 255, current_fs->blocksize); *flag = 1; }else *flag = (ext2fs_test_block_bitmap(d_bmap, end+1) && (! ext2fs_test_block_bitmap( bmap, end+1)))? 0 :1 ; return count; } static int get_full_range(blk_t* p_blk ,struct ext2fs_struct_loc_generic_bitmap *ds_bmap, unsigned char* buf, blk_t* p_flag){ blk_t begin; blk_t end; int count=0; int i; int diff = (current_fs->blocksize == 1024)?1:0; for (begin = *p_blk; begin <= ds_bmap->end ; begin++){ if((!((begin - diff) & 0x7)) && skip_block(&begin, ds_bmap)){ #ifdef DEBUG_MAGIC_SCAN printf("jump to %lu \n",begin); #endif } *p_blk = begin; if (begin > ds_bmap->end) return 0; if (ext2fs_test_block_bitmap ( d_bmap, begin) && (! ext2fs_test_block_bitmap( bmap, begin))) break; } i = 0; //add the previous block to the end of the buffer if(io_channel_read_blk ( current_fs->io,begin-1,1,buf - current_fs->blocksize)){ fprintf(stderr,"ERROR: while read block %10lu + %d %d\n",(long unsigned int)begin,i,count-1); return 0; } for (end = begin,count=1 ; ((count <= MAX_RANGE) && (end < ds_bmap->end)); ){ if (ext2fs_test_block_bitmap(d_bmap, end) && (! ext2fs_test_block_bitmap( bmap, end))){ count++; if (!begin) begin = end; *p_flag = end++; p_flag++; i++; } else { if (i){ if (io_channel_read_blk ( current_fs->io, begin , i, buf )){ fprintf(stderr,"ERROR: while read block %10lu + %d\n",(long unsigned int)begin,i); return 0; } buf += (current_fs->blocksize *i); begin = 0; i = 0; } end++; } } *(p_blk+1) = end; if (i){ if (io_channel_read_blk ( current_fs->io, begin , i, buf )){ fprintf(stderr,"ERROR: while read block %10lu + %d %d\n",(long unsigned int)begin,i,count-1); return 0; } } return count-1; } //FIXME //Attention : Changes have a very strong effect of the magic-fuction result static int check_plain_passing(unsigned char * buf){ int ret = 0; unsigned char *last = buf-1; unsigned char *next = buf; int i,j, count1,count2; if ((!(*last)) || (!(buf[current_fs->blocksize-1]))) return 0; //NULL at end last = buf -32; count1 = count2 = 0; for (i = 0; i< 32; i++){ for (j = 0; j<32; j++){ if (last[i] == next[j]){ count1++; break; } } for (j = 0; j<32; j++){ if (next[i] == last[j]){ count2++; break; } } } if ((count1 > 7 ) && (count2 > 7 )) ret = 1; //many duplicate count1 = count2 = 0; for (i = 0; i< 31; i++){ if( last[i] == last[i+1]) count1++; if( next[i] == next[i+1]) count2++; } if ((count1 > 10) && (count2 > 10)) ret += 2; //many repetitions count1 = count2 = 0; for (i = 0; i< 31; i++){ for (j = i+1; j<32; j++){ if (last[i] == last[j]) count1++; if (next[i] == next[j]) count2++; } } if ((count1 < 5) && (count2 < 5)) ret += 4; //very different return ret; } static blk_t block_backward(blk_t blk , int count){ int i=count; while (i && blk){ if (ext2fs_test_block_bitmap(d_bmap, blk) && (! ext2fs_test_block_bitmap( bmap, blk))) i--; blk--; } return (!i) ? blk+1 : 0; } //main of the magic_scan_engine for ext3 //FIXME Disabled (not tested and can't work by version) int magic_block_scan3(char* des_dir, __u32 t_after){ magic_t cookie = 0; magic_t cookie_f = 0; struct ext2fs_struct_loc_generic_bitmap *ds_bmap; struct found_data_t *file_data = NULL; blk_t blk[2] ; blk_t j; blk_t flag[MAX_RANGE]; blk_t fragment_flag; blk_t last_rec; unsigned char *v_buf = NULL; unsigned char *buf ; char *magic_buf = NULL; unsigned char *tmp_buf = NULL; int blocksize, ds_retval,count,i,ret,dummy, size; __u32 scan,follow; printf("MAGIC-3 : start ext3-magic-scan search. Please wait, this may take a long time\n"); blocksize = current_fs->blocksize ; count = 0; blk[0] = 0; cookie = magic_open(MAGIC_MIME | MAGIC_NO_CHECK_COMPRESS | MAGIC_NO_CHECK_ELF ); cookie_f = magic_open(MAGIC_NO_CHECK_COMPRESS | MAGIC_NO_CHECK_ELF | MAGIC_RAW ); if ((! cookie) || magic_load(cookie, NULL) || (! cookie_f) || magic_load(cookie_f, NULL)){ fprintf(stderr,"ERROR: can't find libmagic\n"); goto errout; } v_buf = malloc(blocksize * (MAX_RANGE+1)); buf = v_buf + blocksize ; tmp_buf = malloc(blocksize); magic_buf = malloc(100); if ((! v_buf) || (! magic_buf) || (! tmp_buf)){ fprintf(stderr,"ERROR: can't allocate memory\n"); goto errout; } memset(magic_buf,0,100); ds_retval = init_block_bitmap_list(&d_bmap, t_after); while (ds_retval){ ds_retval = next_block_bitmap(d_bmap); if (ds_retval == 2 ) continue; if (d_bmap && ds_retval ){ ds_bmap = (struct ext2fs_struct_loc_generic_bitmap *) d_bmap; count = 0; blk[0] = 1; count = get_range(blk ,ds_bmap, buf, &dummy); while (count){ #ifdef DEBUG_MAGIC_SCAN printf(" %lu %lu %d\n", blk[0],blk[1],count); #endif for (i = 0; i< ((count>12) ? MAX_RANGE - 12 : count) ;i++){ scan = magic_check_block(buf+(i*blocksize), cookie, cookie_f , magic_buf , blocksize * (((count-i) >=9) ? 9 : 1) ,blk[0]+i , 0); if(scan & (M_DATA | M_BLANK | M_IS_META | M_TXT)){ if (scan & (M_ACL | M_EXT4_META | M_DIR)) ext2fs_mark_generic_bitmap(bmap, blk[0]+i); continue; } #ifdef DEBUG_MAGIC_SCAN printf("SCAN %lu : %09x : %s\n",blk[0]+i,scan,magic_buf); #endif if (((count -i) > 12) && (ext2fs_le32_to_cpu(*(__u32*)(buf +((i+12)*blocksize))) == blk[0] + i +1 + 12)){ follow = 0; file_data = new_file_data(blk[0]+i,scan,magic_buf,buf+(i*blocksize),&follow, count - i); for(j=blk[0]+i; j<(blk[0]+i+12);j++) add_file_data(file_data, j, scan ,&follow); scan = magic_check_block(buf+((i+12)*blocksize), cookie, cookie_f , magic_buf , blocksize ,blk[0]+i+12, 0); if ((scan & M_EXT3_META) && (check_indirect_meta3((char*)buf+((i+12)*blocksize)))){ if (add_ext3_file_meta_data(file_data, (char*)buf+((i+12)*blocksize), j)){ io_channel_read_blk (current_fs->io, file_data->last, 1, tmp_buf); file_data = soft_border(des_dir, tmp_buf, file_data, &follow, 0 ,&last_rec, 0x7); i++ ; break; } else file_data = forget_file_data(file_data, &follow); } else file_data = forget_file_data(file_data, &follow); } else{ // no matches // In the first step we are taking nothing } } blk[0] += (i)?i:1; count = get_range(blk ,ds_bmap,buf, &dummy); } count = 0; blk[0] = 1; last_rec = 0; fragment_flag = 0; count = get_full_range(blk ,ds_bmap, buf,flag); while (count){ #ifdef DEBUG_MAGIC_SCAN printf("%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu - %d\n",flag[0],flag[1],flag[2],flag[3],flag[4],flag[5],flag[6],flag[7],flag[8],flag[9],flag[10],flag[11],flag[12],flag[13],flag[14],flag[15],count); #endif for (i = 0; i< ((count>12) ? MAX_RANGE - 12 : count) ;i++){ follow = 0; scan = magic_check_block(buf+(i*blocksize), cookie, cookie_f , magic_buf , blocksize ,flag[i], 1); if(scan & (M_DATA | M_BLANK | M_IS_META)){ if ((!fragment_flag) && (scan & M_EXT3_META) && (check_indirect_meta3((char*)buf+(i*blocksize)))){ blk[1] = block_backward(flag[i] , 13); if (blk[1] && (blk[1] < last_rec) && (blk[1] < (flag[i]-12))){ blk[0] = blk[1]; fragment_flag = flag[i]; #ifdef DEBUG_MAGIC_SCAN printf("Try a fragment recover for metablock: %lu at blk: %lu\n",flag[i],blk[1] ); #endif goto load_new; } } else continue; } #ifdef DEBUG_MAGIC_SCAN printf("SCAN %lu : %09x : %s\n",flag[i],scan,magic_buf); #endif if (((count -i) > 12) && (ext2fs_le32_to_cpu(*(__u32*)(buf +((i+12)*blocksize))) == flag[12+i]+1)){ file_data = new_file_data(flag[i],scan,magic_buf,buf+(i*blocksize),&follow,count - i); for(j=i; j<(12+i);j++) add_file_data(file_data, flag[j], scan ,&follow); scan = magic_check_block(buf+((i+12)*blocksize), cookie, cookie_f , magic_buf , blocksize ,flag[i+12],0); if (scan & M_EXT3_META){ if (add_ext3_file_meta_data(file_data, (char*)buf+((i+12)*blocksize), flag[j])){ io_channel_read_blk (current_fs->io, file_data->last, 1, tmp_buf); file_data = soft_border(des_dir, tmp_buf, file_data, &follow, flag[i], &last_rec, 0x7); i++; break; } else file_data = forget_file_data(file_data, &follow); } else file_data = forget_file_data(file_data, &follow); } else{ if (scan & M_IS_FILE){ for (j=i; j< 12+i; j++){ if (!follow){ file_data = new_file_data(flag[i],scan,magic_buf,buf+(i*blocksize),&follow,count - i); add_file_data(file_data, flag[i], scan ,&follow); } else{ scan = magic_check_block(buf+(j*blocksize), cookie, cookie_f , magic_buf , blocksize ,flag[j] , 0); if ( check_file_data_possible(file_data, scan ,buf+(j*blocksize))){ add_file_data(file_data, flag[j], scan ,&follow); } else{ j--; file_data = soft_border(des_dir,buf+(j*blocksize), file_data, &follow, flag[j], &last_rec,0x7); if ((!fragment_flag) && (scan & M_EXT3_META) && (check_indirect_meta3((char*)buf+((j+1)*blocksize)))){ blk[1] = block_backward(flag[j] , 12); if (blk[1] && (blk[1] < last_rec) && (blk[1] < flag[j]-12)){ blk[0] = blk[1]; fragment_flag = flag[j+1]; #ifdef DEBUG_MAGIC_SCAN printf("Try fragment recover for metablock: %lu at blk: %lu\n",flag[j+1], blk[0]); #endif goto load_new; } } break; } } size = (scan & M_SIZE ); //get_block_len(buf+(i*blocksize)); ret = file_data->func(buf+(j*blocksize), &size ,scan ,0 , file_data); if (ret == 1){ if (file_data_correct_size(file_data,size)){ file_data = recover_file_data(des_dir, file_data, &follow); last_rec = flag[i]; } else{ file_data = forget_file_data(file_data, &follow); #ifdef DEBUG_MAGIC_SCAN printf("Don't recover this file, current block %lu \n",flag[i]); #endif } break; } } if (follow){ #ifdef DEBUG_MAGIC_SCAN printf("stop no file-end\n"); #endif file_data = soft_border(des_dir,buf+((j-1)*blocksize), file_data, &follow, flag[i], &last_rec, 0x3); i = j - 12; } else i = j; } } } blk[0]+=(i)?i:1; if (fragment_flag && (blk[0] > fragment_flag)) fragment_flag = 0; load_new : count = get_full_range(blk ,ds_bmap, buf,flag); } }//operation } //while transactions errout: clear_block_bitmap_list(d_bmap); if (file_data) free_file_data(file_data); if (v_buf) free(v_buf); if (tmp_buf) free(tmp_buf); if (magic_buf) free(magic_buf); if (cookie) magic_close(cookie); if (cookie_f) magic_close(cookie_f); return 0; } //end static int check_extent_len(struct ext3_extent_header *header, struct extent_area* ea, blk_t blocknr ){ void *buf = NULL; int ret = 0; struct ext3_extent_idx *idx; struct ext3_extent *extent; int entry,i; ret = ext2fs_extent_header_verify((void*) header, current_fs->blocksize); if(!ret){ ea->b_count++; for (entry =1; ((!ret) && (entry <= ext2fs_le16_to_cpu(header->eh_entries))) ; entry++){ if (ext2fs_le16_to_cpu(header->eh_depth)){ idx = (struct ext3_extent_idx*) (header + entry); buf=malloc(current_fs->blocksize); if (!buf) return 1; if(io_channel_read_blk ( current_fs->io,ext2fs_le32_to_cpu(idx->ei_leaf), 1, buf )){ fprintf(stderr,"Error read block %lu\n",(long unsigned int)ext2fs_le32_to_cpu(idx->ei_leaf)); ret = 2; } else{ //Recursion ret = check_extent_len((struct ext3_extent_header*)buf, ea , 0); } if (buf){ free(buf); buf = NULL ;} } else{ extent = (struct ext3_extent*)(header + entry); if ((ext2fs_le16_to_cpu(extent->ee_len)) & 0x8000){ continue; } for (i = 0; ((! ret) && (i< ext2fs_le16_to_cpu(extent->ee_len))); i++){ if (ext2fs_test_block_bitmap(bmap,ext2fs_le32_to_cpu(extent->ee_start)+i) && (!ext2fs_test_block_bitmap(d_bmap,ext2fs_le32_to_cpu(extent->ee_start)+i))) ret = 4; } if (!ret){ if ((entry == 1) && (!ea->start_b)){ ea->start_b = ext2fs_le32_to_cpu(extent->ee_start); ea->l_start = ext2fs_le32_to_cpu(extent->ee_block); } // if (entry == ext2fs_le16_to_cpu(header->eh_entries)){ ea->end_b = ext2fs_le32_to_cpu(extent->ee_start) + ext2fs_le16_to_cpu(extent->ee_len)-1; ea->l_end = ext2fs_le32_to_cpu(extent->ee_block) + ext2fs_le16_to_cpu(extent->ee_len)-1; // } ea->b_count += ext2fs_le16_to_cpu(extent->ee_len); ea->size = ((unsigned long long) ((ext2fs_le32_to_cpu(extent->ee_block)) + (ext2fs_le16_to_cpu(extent->ee_len)))) * current_fs->blocksize; } } } if ((blocknr) && (!ret)){ ea->blocknr = blocknr; ea->depth = ext2fs_le16_to_cpu(header->eh_depth); } } return ret; } int recover_db(struct extent_db_t *db , struct extent_area *ea_group){ int flag = 0; int count = 0; __u32 start; struct extent_area *ea = ea_group ; memset (ea_group, 0 ,sizeof(struct extent_area) *4); start = 0; while ((!flag) && (count < 4)) { start = extentd_db_find(db, (start) ? start+1 : start , ea); if (start){ count++; // printf(" --> %d ; start: %lu end: %lu depth: %lu \n",count, ea->l_start, ea->l_end, ea->depth); ea++; } else flag++; } return count; } //FIXME NEW --------------------------------------------------------------------------------------------------------- //main of the magic_scan_engine for ext4 int magic_block_scan4(char* des_dir, __u32 t_after){ magic_t cookie = 0; magic_t cookie_f = 0; struct ext2fs_struct_loc_generic_bitmap *ds_bmap = NULL; ext2fs_block_bitmap c_bmap = NULL; struct extent_db_t *db = NULL; struct found_data_t *file_data = NULL; struct found_data_t *tmp_file_data = NULL; struct extent_area *ea = NULL; struct extent_area ea_group[4]; blk_t blk[2] ; blk_t first_b; blk_t last_rec; unsigned char *v_buf = NULL; unsigned char *buf ; char *magic_buf = NULL; unsigned char *tmp_buf = NULL; int blocksize, size, ds_retval,count,i,j,ret,dummy, border; __u32 scan,follow; int tes ; //typical extent size //only for test //int zahler = 0; //int zahler1 =0; printf("MAGIC-3 : start ext4-magic-scan search\n"); blocksize = current_fs->blocksize ; tes = 1048576 / blocksize; if (ext2fs_copy_bitmap(current_fs->block_map, &c_bmap)){ fprintf(stderr,"Error: while duplicate bitmap\n"); return 0; } ext2fs_clear_block_bitmap(c_bmap); scan = 0; count = 0; blk[0] = 1; cookie = magic_open(MAGIC_MIME | MAGIC_NO_CHECK_COMPRESS | MAGIC_NO_CHECK_ELF | MAGIC_CONTINUE); cookie_f = magic_open(MAGIC_NO_CHECK_COMPRESS | MAGIC_NO_CHECK_ELF | MAGIC_RAW ); if ((! cookie) || magic_load(cookie, magicfile) || (! cookie_f) || magic_load(cookie_f, magicfile)){ fprintf(stderr,"ERROR: can't find libmagic\n"); goto errout; } v_buf = malloc(blocksize * (MAX_RANGE+1)); buf = v_buf + blocksize ; tmp_buf = malloc(blocksize * 9); magic_buf = malloc(100); if ((! v_buf) || (! magic_buf) || (! tmp_buf)){ fprintf(stderr,"ERROR: can't allocate memory\n"); goto errout; } ds_retval = init_block_bitmap_list(&d_bmap, t_after); while (ds_retval){ ds_retval = next_block_bitmap(d_bmap); if (ds_retval == 2 ) continue; db = extent_db_init(d_bmap); if (d_bmap && ds_retval && db ){ ds_bmap = (struct ext2fs_struct_loc_generic_bitmap *) d_bmap; last_rec = 0; count = 0; blk[0] = 1; follow = 0; count = get_range(blk ,ds_bmap, buf, &dummy); while (count){ #ifdef DEBUG_MAGIC_SCAN printf(" %lu %lu %d\n", blk[0],blk[1],count); #endif for (i=0 ; i< count; i++){ // printf(">>>>> %lu \n",blk[0]+i); if ((check_dir_block(buf +(i*blocksize), blk[0]+i,1)) || (check_acl_block(buf+(i*blocksize), blk[0]+i,1))){ ext2fs_mark_generic_bitmap(bmap, blk[0]+i); // printf ("<<> %lu DIR-BLOCK \n",blk[0]+i); continue; } if (check_plain_passing((buf +(i*blocksize))) && ((blk[0]+i-((blocksize==1024)?1:0)) % tes ) ) ext2fs_mark_generic_bitmap(c_bmap, blk[0]+i); //zahler++; if (check_meta4_block(buf+(i*blocksize), blk[0]+i,1)){ // printf ("<<> %lu IDX \n",blk[0]+i); ea = new_extent_area(); if ( ea ){ if (check_extent_len((struct ext3_extent_header*) (buf+(i*blocksize)) , ea, blk[0]+i)){ printf("extent %lu range allocated or damage\n",(long unsigned int)blk[0]+i); } else{ // printf(" --> start: %lu end: %lu depth: %lu \n",ea->l_start, ea->l_end, ea->depth); if (!ea->l_start){ first_b = ea->start_b; if(( ext2fs_test_block_bitmap( bmap,first_b)) || (io_channel_read_blk (current_fs->io,first_b - 1,9,tmp_buf ))){ fprintf(stderr,"Warning: block %10lu can not read or is allocated\n",(long unsigned int)first_b); //FIXME ERROR goto ? } else{ scan = magic_check_block(tmp_buf+blocksize, cookie, cookie_f , magic_buf , blocksize*8 ,first_b, 1); file_data = new_file_data(first_b,scan,magic_buf,tmp_buf+blocksize,&follow, 8); if ((file_data) && (add_ext4_extent_idx_data(file_data, ea))){ file_data->scantype |= DATA_METABLOCK; io_channel_read_blk (current_fs->io, file_data->last, 1, tmp_buf); file_data = soft_border(des_dir, tmp_buf, file_data, &follow, ea->blocknr ,&last_rec, 0x7); if(last_rec == blk[0]+i){ extent_db_add (db, ea,1); extent_db_del(db,blk[0]+i); ea=NULL; } else{ extent_db_add (db, ea,1); ea = NULL; } } } } else{ extent_db_add (db, ea,1); ea = NULL; } } blk[0] = blk[0] - count + i; i = count; if(ea) {free(ea); ea=NULL;} } } //ext4meta } //for i blk[0] += (i)?i:1; count = get_range(blk ,ds_bmap,buf, &dummy); } //count // } //ds_bmap while(1){ count = recover_db(db, ea_group); if(count){ ea = ea_group; if (( ea->blocknr) &&(! ea->l_start)){ first_b = ea->start_b; if(( ext2fs_test_block_bitmap( bmap,first_b)) || (io_channel_read_blk (current_fs->io,first_b-1 ,9,tmp_buf ))){ fprintf(stderr,"Warning: block %10lu can not read or is allocated\n",(long unsigned int)first_b); //FIXME ERROR goto ? } else{ scan = magic_check_block(tmp_buf+blocksize, cookie, cookie_f , magic_buf , blocksize*8,first_b, 1); file_data = new_file_data(first_b,scan,magic_buf,tmp_buf+blocksize,&follow,8); if ((file_data) && (add_ext4_extent_idx_data(file_data, ea))){ for (i = 1; iio, file_data->last, 1, tmp_buf); file_data = soft_border(des_dir, tmp_buf, file_data, &follow, ea_group[0].blocknr, &last_rec, 0x7 | FORCE_RECOVER); if(last_rec != ea_group[0].blocknr) printf("error: block %lu -> file not written\n",(long unsigned int)ea_group[0].blocknr); for (i=0; ilen)++; if (file_data) add_file_data(file_data, blk[0]+i, scan ,&follow); else follow++; continue; } if (!follow){ scan = magic_check_block(buf+(i*blocksize), cookie, cookie_f , magic_buf , (count-i)*blocksize ,blk[0]+i, 1); //printf("SCAN %lu : %09x : %s\n",blk[0]+i,scan,magic_buf); ea = new_extent_area(); if ( ea ){ ea->start_b = blk[0]+i; (ea->len)++; if ((scan & M_IS_FILE) && (!(scan & M_DATA))){ file_data = new_file_data(blk[0]+i,scan,magic_buf,buf+(i*blocksize),&follow,count - i); if (file_data){ //----------------------<<< //File can recover by follow the datastream if (file_data->scantype & DATA_CARVING){ (ea->len)--; for (j=0;jbuf_length;j++){ add_file_data(file_data, blk[0]+i+j, scan ,&follow); (ea->len)++; } blk[0] += i+j; count = get_range(blk ,ds_bmap,buf, &border); ret = 1; while (ret && (!(file_data->scantype & (DATA_READY | DATA_BREAK)))){ file_data->buf_length = (!follow) ? (count+1) : count; ret = file_data->func(buf, &size ,scan ,3 , file_data); if (ret){ if (((!file_data->buf_length)&& (!(file_data->scantype & (DATA_READY))))|| ((ret == 3) && (file_data->scantype & H_F_Carving))){ // break follow > scan now goto newloop; } if (file_data->buf_length > count){ i = check_next_border(ds_bmap, blk[0],file_data->buf_length); if (i){ ea->len = file_data->last_match_blk; // printf("%lu : BREAK-1 : %s after %ld blocks\n",blk[0]+i,file_data->name, ea->len); blk[0] = ea->start_b + ((ea->len)?ea->len:1); extent_db_add (db, ea, 0); ea = NULL; file_data = forget_file_data(file_data, &follow); count = get_range(blk ,ds_bmap,buf, &border); goto newloop; } } for (j=0;jbuf_length;j++){ add_file_data(file_data, blk[0]+j, scan ,&follow); (ea->len)++; } if ((border && (file_data->last == blk[1]))&& (!(file_data->scantype & (DATA_READY)))){ if ((!file_data->next_offset)&&(file_data->scantype & DATA_NO_FOOT)){ file_data->scantype |= DATA_READY; // printf("possible EOF, recover this\n"); } else { // printf("%lu : BREAK-2 : %s after %ld blocks\n",blk[0]+i,file_data->name, file_data->last - file_data->first); extent_db_add (db, ea, 0); ea = NULL; blk[0] = file_data->last + 1; file_data = forget_file_data(file_data, &follow); count = get_range(blk ,ds_bmap,buf, &border); goto newloop; } } blk[0] += j; count = get_range(blk ,ds_bmap,buf, &border); } else{ // printf("%lu : BREAK-3 : %s after %ld blocks\n",blk[0]+file_data->buf_length,file_data->name, file_data->last - file_data->first); if (!file_data->last_match_blk) (file_data->last_match_blk)++; ea->len = file_data->last_match_blk; extent_db_add (db, ea, 0); ea = NULL; blk[0] = file_data->first + file_data->last_match_blk ; file_data = forget_file_data(file_data, &follow); count = get_range(blk ,ds_bmap,buf, &border); goto newloop; } } if (file_data->scantype & (DATA_READY)){ io_channel_read_blk (current_fs->io, file_data->last, 1, tmp_buf); file_data = soft_border(des_dir, tmp_buf, file_data, &follow, ea->start_b ,&last_rec, 0x7); if (ea->start_b != last_rec){ // printf("%lu force recover, but not written\n",ea->blocknr); extent_db_add (db, ea, 0); ea = NULL; } } else{ // printf("%lu : BREAK put into extent-cache\n", blk[0]); if (!file_data->last_match_blk) (file_data->last_match_blk)++; ea->len = file_data->last_match_blk; extent_db_add (db, ea, 0); ea = NULL; blk[0] = file_data->first + file_data->last_match_blk; file_data = forget_file_data(file_data, &follow); count = get_range(blk ,ds_bmap,buf, &border); } if (ea){free(ea);ea = NULL;} follow = 0; goto newloop; } //End follow datastream else{ add_file_data(file_data, blk[0]+i, scan ,&follow); //add the first block } if (file_data->scantype & DATA_LENGTH){ //Start of size carving j = check_next_border(ds_bmap, blk[0]+i,((file_data->size-1)/blocksize)+1); if ((!j) && (! io_channel_read_blk (current_fs->io, blk[0]+ i + ((file_data->size-1)/blocksize), 1, tmp_buf))){ size = get_block_len((char*)tmp_buf); if ((!(file_data->scantype & DATA_MINIMUM)) && (size <= ((file_data->size % blocksize)?(file_data->size % blocksize):blocksize))){ tmp_file_data = copy_file_data(file_data); if (tmp_file_data){ for (j = 1; j< (((file_data->size-1)/blocksize)+1); j++){ add_file_data(tmp_file_data, blk[0]+i+j, scan ,&follow); } tmp_file_data = soft_border(des_dir, tmp_buf, tmp_file_data, &follow, blk[0]+i ,&last_rec, 0x3); if (blk[0]+i == last_rec){ file_data = forget_file_data(file_data, &follow); if (ea){free(ea);ea = NULL;} blk[0]+= j + i; count = get_range(blk ,ds_bmap,buf, &border); goto newloop; } } } } //and only MIN_SIZE if ((!j) && (file_data->scantype & DATA_MINIMUM)){ for (j = 1; j< (((file_data->size-1)/blocksize)+1); j++){ add_file_data(file_data, blk[0]+i+j, scan ,&follow); (ea->len)++; } file_data->scantype = H_F_Carving; blk[0]+=(i+j-2); count = get_range(blk ,ds_bmap,buf, &border); i = 1; // size = get_block_len(buf+(i*blocksize)); goto followloop; } else{ file_data->scantype = H_F_Carving; follow = ea->len; } } //End size carving //------------------------------>>> }else { // no file_data // printf("%lu : no file_data\n",blk[0]+i); if(ea){ (ea->l_start)--; if(!ea->len) (ea->len)++; extent_db_add (db, ea, 0); ea = NULL; } } }else { // printf("%lu : no file begin\n",blk[0]+i); (ea->l_start)--; follow++; } }else printf("fail malloc ea\n"); } else{ scan = magic_check_block(buf+(i*blocksize), cookie, cookie_f , magic_buf , blocksize ,blk[0]+i, 0); // zahler1++; // printf("SCAN %lu : %09x : %s\n",blk[0]+i,scan,magic_buf); if (file_data){ if ( check_file_data_possible(file_data, scan ,buf+(i*blocksize))){ add_file_data(file_data, blk[0]+i, scan ,&follow); (ea->len)++; } else{ file_data = soft_border(des_dir,buf+((i-1)*blocksize), file_data, &follow, blk[0]+i-1, &last_rec,0x3); if (last_rec != blk[0]+i-1){ // printf("%lu : clear, put into extent-cache\n", blk[0]+i-1 ); extent_db_add (db, ea, 0); ea = NULL; } if (ea){free(ea);ea = NULL;} i--; } } else{ if ((scan & M_IS_FILE) && (!(scan & M_DATA))){ // printf("%lu : end of fragment, put into extent-cache\n",blk[0]+i); extent_db_add (db, ea, 0); ea = NULL; follow = 0; i--; } else { (ea->len)++; follow++; if ((scan & M_SIZE) < (blocksize - 32)){ // printf("%lu : possible end of fragment, add extent-cache\n",blk[0]+i); extent_db_add (db, ea, 0); ea = NULL; follow = 0; } } } } size = (scan & M_SIZE ); //get_block_len(buf+(i*blocksize)); followloop: if (follow && file_data){ ret = file_data->func(buf+(i*blocksize), &size ,scan ,0 , file_data); if (ret == 1){ if (file_data_correct_size(file_data,size)){ file_data = recover_file_data(des_dir, file_data, &follow); last_rec = blk[0]+i; } else{ file_data = forget_file_data(file_data, &follow); extent_db_add (db, ea, 0); ea = NULL; // printf("%lu : Don't recover this file\n",blk[0]+i); } if (ea){free(ea);ea = NULL;} } else if(ea && (file_data->func == file_none)) (ea->l_start)--; } } if(border){ // printf("%lu : border warning\n", blk[0]+i); if (file_data) { file_data = soft_border(des_dir,buf+((i-1)*blocksize), file_data, &follow, blk[0]+i-1, &last_rec,0x3); if (last_rec != blk[0]+i-1){ // printf("%lu : clear and put into extent-cache\n", blk[0]+i-1 ); extent_db_add (db, ea, 0); ea = NULL; } else { free(ea);ea = NULL; } } if (follow){ // printf("%lu : end of fragment\n", blk[0]+i); follow = 0; } if (ea){ extent_db_add (db, ea, 0); ea = NULL; } } blk[0] += (i)?i:1; count = get_range(blk ,ds_bmap,buf, &border); } } // printf("ExtentDB : %lu entries\n",db->count); if (db){ extent_db_clear(db) ; db=NULL;} }//ds_retval errout: clear_block_bitmap_list(d_bmap); ext2fs_free_block_bitmap(c_bmap); if (ea) free (ea); if (db) extent_db_clear(db); if (v_buf) free(v_buf); if (tmp_buf) free(tmp_buf); if (magic_buf) free(magic_buf); if (cookie) magic_close(cookie); if (cookie_f) magic_close(cookie_f); //printf("Count-1 = %lu Count-2 = %lu \n",zahler, zahler1); return 0; }//funcion //--------END----------