TestDisk: handle ext4 with 64 bit blocks (EXT4_FEATURE_INCOMPAT_64BIT)

This commit is contained in:
Christophe Grenier 2013-08-28 08:29:32 +02:00
parent ed174946a0
commit da8028ea3f
7 changed files with 188 additions and 79 deletions

View file

@ -17,8 +17,8 @@ EXTRA_PROGRAMS = photorecf
base_C = autoset.c common.c crc.c ewf.c fnctdsk.c hdaccess.c hdcache.c hdwin32.c hidden.c hpa_dco.c intrf.c iso.c list_sort.c log.c log_part.c misc.c msdos.c parti386.c partgpt.c parthumax.c partmac.c partsun.c partnone.c partxbox.c io_redir.c ntfs_io.c ntfs_utl.c partauto.c sudo.c unicode.c win32.c
base_H = alignio.h autoset.h common.h crc.h ewf.h fnctdsk.h hdaccess.h hdwin32.h hidden.h guid_cmp.h guid_cpy.h hdcache.h hpa_dco.h intrf.h iso.h iso9660.h lang.h list.h list_sort.h log.h log_part.h misc.h types.h io_redir.h msdos.h ntfs_utl.h parti386.h partgpt.h parthumax.h partmac.h partsun.h partxbox.h partauto.h sudo.h unicode.h win32.h
fs_C = analyse.c bfs.c bsd.c btrfs.c cramfs.c exfat.c fat.c fatx.c ext2.c jfs.c gfs2.c hfs.c hfsp.c hpfs.c luks.c lvm.c md.c netware.c ntfs.c rfs.c savehdr.c sun.c swap.c sysv.c ufs.c vmfs.c wbfs.c xfs.c zfs.c
fs_H = analyse.h bfs.h bsd.h btrfs.h cramfs.h exfat.h fat.h fatx.h ext2.h jfs_superblock.h jfs.h gfs2.h hfs.h hfsp.h hpfs.h luks.h lvm.h md.h netware.h ntfs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h vmfs.h wbfs.h xfs.h zfs.h
fs_C = analyse.c bfs.c bsd.c btrfs.c cramfs.c exfat.c fat.c fatx.c ext2.c ext2_common.c jfs.c gfs2.c hfs.c hfsp.c hpfs.c luks.c lvm.c md.c netware.c ntfs.c rfs.c savehdr.c sun.c swap.c sysv.c ufs.c vmfs.c wbfs.c xfs.c zfs.c
fs_H = analyse.h bfs.h bsd.h btrfs.h cramfs.h exfat.h fat.h fatx.h ext2.h ext2_common.h jfs_superblock.h jfs.h gfs2.h hfs.h hfsp.h hpfs.h luks.h lvm.h md.h netware.h ntfs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h vmfs.h wbfs.h xfs.h zfs.h
testdisk_ncurses_C = addpart.c addpartn.c adv.c askloc.c chgarch.c chgarchn.c chgtype.c chgtypen.c dimage.c dirn.c dirpart.c diskacc.c diskcapa.c edit.c ext2_sb.c ext2_sbn.c fat1x.c fat32.c fat_adv.c fat_cluster.c fatn.c geometry.c geometryn.c godmode.c hiddenn.c intrface.c intrfn.c nodisk.c ntfs_adv.c ntfs_fix.c ntfs_udl.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c tanalyse.c tbanner.c tdelete.c tdiskop.c tdisksel.c testdisk.c texfat.c thfs.c tload.c tlog.c tmbrcode.c tntfs.c toptions.c tpartwr.c
testdisk_ncurses_H = addpart.h addpartn.h adv.h askloc.h chgarch.h chgarchn.h chgtype.h chgtypen.h dimage.h dirn.h dirpart.h diskacc.h diskcapa.h edit.h ext2_sb.h ext2_sbn.h fat1x.h fat32.h fat_adv.h fat_cluster.h fatn.h geometry.h geometryn.h godmode.h hiddenn.h intrface.h intrfn.h nodisk.h ntfs_fix.h ntfs_udl.h partgptn.h parti386n.h partmacn.h partsunn.h partxboxn.h tanalyse.h tdelete.h tdiskop.h tdisksel.h texfat.h thfs.h tload.h tlog.h tmbrcode.h tntfs.h toptions.h tpartwr.h
@ -292,7 +292,7 @@ file_C = filegen.c \
file_xz.c \
file_zip.c
file_H = ext2.h filegen.h file_jpg.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
file_H = ext2.h ext2_common.h filegen.h file_jpg.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
photorec_C = photorec.c phcfg.c addpart.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c poptions.c sessionp.c setdate.c dfxml.c list.c
@ -309,7 +309,7 @@ qphotorec_SOURCES = qmainrec.cpp qphotorec.cpp qphotorec.h qphotorec.qrc qphbs.c
nodist_qphotorec_SOURCES = moc_qphotorec.cpp rcc_qphotorec.cpp
fidentify_SOURCES = fidentify.c common.c common.h phcfg.c phcfg.h setdate.c setdate.h $(file_C) $(file_H) log.c log.h crc.c crc.h fat_common.c suspend_no.c
fidentify_SOURCES = fidentify.c common.c common.h phcfg.c phcfg.h setdate.c setdate.h $(file_C) $(file_H) log.c log.h crc.c crc.h ext2_common.c fat_common.c suspend_no.c
CLEANFILES = nodist_qphotorec_SOURCES
DISTCLEANFILES = *~ core

View file

@ -33,12 +33,12 @@
#include "types.h"
#include "common.h"
#include "ext2.h"
#include "ext2_common.h"
#include "fnctdsk.h"
#include "log.h"
#include "guid_cpy.h"
static int set_EXT2_info(const struct ext2_super_block *sb, partition_t *partition, const int verbose);
static int test_EXT2(const struct ext2_super_block *sb, partition_t *partition);
int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose)
{
@ -119,7 +119,7 @@ int recover_EXT2(disk_t *disk, const struct ext2_super_block *sb,partition_t *pa
partition->part_type_mac=PMAC_LINUX;
partition->part_type_sun=PSUN_LINUX;
partition->part_type_gpt=GPT_ENT_TYPE_LINUX_DATA;
partition->part_size=(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
partition->part_size=td_ext2fs_blocks_count(sb) * EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size);
guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->s_uuid);
if(verbose>0)
{
@ -148,12 +148,12 @@ int recover_EXT2(disk_t *disk, const struct ext2_super_block *sb,partition_t *pa
{
log_info("recover_EXT2: s_block_group_nr=%u/%u, s_mnt_count=%u/%u, s_blocks_per_group=%u, s_inodes_per_group=%u\n",
le16(sb->s_block_group_nr),
(unsigned int)(le32(sb->s_blocks_count)/le32(sb->s_blocks_per_group)),
(unsigned int)(td_ext2fs_blocks_count(sb) /le32(sb->s_blocks_per_group)),
le16(sb->s_mnt_count), le16(sb->s_max_mnt_count),
(unsigned int)le32(sb->s_blocks_per_group),
(unsigned int)le32(sb->s_inodes_per_group));
log_info("recover_EXT2: s_blocksize=%u\n", partition->blocksize);
log_info("recover_EXT2: s_blocks_count %u\n", (unsigned int)le32(sb->s_blocks_count));
log_info("recover_EXT2: s_blocks_count %lu\n", (long unsigned int)td_ext2fs_blocks_count(sb));
if(disk==NULL)
log_info("recover_EXT2: part_size %lu\n", (long unsigned)(partition->part_size / DEFAULT_SECTOR_SIZE));
else
@ -161,40 +161,3 @@ int recover_EXT2(disk_t *disk, const struct ext2_super_block *sb,partition_t *pa
}
return 0;
}
static int test_EXT2(const struct ext2_super_block *sb, partition_t *partition)
{
/* There is a little offset ... */
if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
return 1;
if (le32(sb->s_free_blocks_count) > le32(sb->s_blocks_count)) return 2;
if (le32(sb->s_free_inodes_count) > le32(sb->s_inodes_count)) return 3;
if (le16(sb->s_errors)!=0 &&
(le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
(le16(sb->s_errors) != EXT2_ERRORS_RO) &&
(le16(sb->s_errors) != EXT2_ERRORS_PANIC))
return 4;
if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
return 5;
if (le32(sb->s_blocks_count) == 0) /* reject empty filesystem */
return 6;
if(le32(sb->s_log_block_size)>2) /* block size max = 4096, can be 8192 on alpha */
return 7;
if(partition==NULL)
return 0;
if(partition->part_size!=0 &&
partition->part_size<(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size)))
return 8;
if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_HUGE_FILE)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_GDT_CSUM)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_DIR_NLINK)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)!=0 ||
EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_64BIT)!=0 ||
EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_MMP)!=0)
partition->upart_type=UP_EXT4;
else if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0)
partition->upart_type=UP_EXT3;
else
partition->upart_type=UP_EXT2;
return 0;
}

View file

@ -148,8 +148,58 @@ struct ext2_super_block {
*/
uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
uint16_t s_padding1;
uint32_t s_reserved[204]; /* Padding to the end of the block */
uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */
/*
* Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
*/
uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
uint32_t s_journal_inum; /* inode number of journal file */
uint32_t s_journal_dev; /* device number of journal file */
uint32_t s_last_orphan; /* start of list of inodes to delete */
uint32_t s_hash_seed[4]; /* HTREE hash seed */
uint8_t s_def_hash_version; /* Default hash version to use */
uint8_t s_jnl_backup_type; /* Default type of journal backup */
uint16_t s_desc_size; /* Group desc. size: INCOMPAT_64BIT */
uint32_t s_default_mount_opts;
uint32_t s_first_meta_bg; /* First metablock group */
uint32_t s_mkfs_time; /* When the filesystem was created */
uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
uint32_t s_blocks_count_hi; /* Blocks count high 32bits */
uint32_t s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/
uint32_t s_free_blocks_hi; /* Free blocks count */
uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
uint32_t s_flags; /* Miscellaneous flags */
uint16_t s_raid_stride; /* RAID stride */
uint16_t s_mmp_update_interval; /* # seconds to wait in MMP checking */
uint64_t s_mmp_block; /* Block for multi-mount protection */
uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
uint8_t s_reserved_char_pad;
uint16_t s_reserved_pad; /* Padding to next 32bits */
uint64_t s_kbytes_written; /* nr of lifetime kilobytes written */
uint32_t s_snapshot_inum; /* Inode number of active snapshot */
uint32_t s_snapshot_id; /* sequential ID of active snapshot */
uint64_t s_snapshot_r_blocks_count; /* reserved blocks for active
snapshot's future use */
uint32_t s_snapshot_list; /* inode number of the head of the on-disk snapshot list */
uint32_t s_error_count; /* number of fs errors */
uint32_t s_first_error_time; /* first time an error happened */
uint32_t s_first_error_ino; /* inode involved in first error */
uint64_t s_first_error_block; /* block involved of first error */
uint8_t s_first_error_func[32]; /* function where the error happened */
uint32_t s_first_error_line; /* line number where error happened */
uint32_t s_last_error_time; /* most recent time of an error */
uint32_t s_last_error_ino; /* inode involved in last error */
uint32_t s_last_error_line; /* line number where error happened */
uint64_t s_last_error_block; /* block involved of last error */
uint8_t s_last_error_func[32]; /* function where the error happened */
uint8_t s_mount_opts[64];
uint32_t s_usr_quota_inum; /* inode number of user quota file */
uint32_t s_grp_quota_inum; /* inode number of group quota file */
uint32_t s_overhead_blocks; /* overhead blocks/clusters in fs */
uint32_t s_reserved[108]; /* Padding to the end of the block */
uint32_t s_checksum; /* crc32c(superblock) */
};
int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose);
int recover_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);

92
src/ext2_common.c Normal file
View file

@ -0,0 +1,92 @@
/*
File: ext2_common.c
Copyright (C) 1998-2013 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
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "types.h"
#include "common.h"
#include "ext2.h"
#include "ext2_common.h"
uint64_t td_ext2fs_blocks_count(const struct ext2_super_block *super)
{
return le32(super->s_blocks_count) |
(EXT2_HAS_INCOMPAT_FEATURE(super, EXT4_FEATURE_INCOMPAT_64BIT) ?
(uint64_t) le32(super->s_blocks_count_hi) << 32 : 0);
}
uint64_t td_ext2fs_free_blocks_count(const struct ext2_super_block *super)
{
return le32(super->s_free_blocks_count) |
(EXT2_HAS_INCOMPAT_FEATURE(super, EXT4_FEATURE_INCOMPAT_64BIT) ?
(uint64_t) le32(super->s_free_blocks_hi) << 32 : 0);
}
int test_EXT2(const struct ext2_super_block *sb, partition_t *partition)
{
/* There is a little offset ... */
if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
return 1;
if (td_ext2fs_free_blocks_count(sb) > td_ext2fs_blocks_count(sb))
return 2;
if (le32(sb->s_free_inodes_count) > le32(sb->s_inodes_count))
return 3;
if (le16(sb->s_errors)!=0 &&
(le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
(le16(sb->s_errors) != EXT2_ERRORS_RO) &&
(le16(sb->s_errors) != EXT2_ERRORS_PANIC))
return 4;
if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
return 5;
if(td_ext2fs_blocks_count(sb) == 0) /* reject empty filesystem */
return 6;
if(le32(sb->s_log_block_size)>2) /* block size max = 4096, can be 8192 on alpha */
return 7;
if(le32(sb->s_blocks_per_group)==0)
return 8;
if(partition==NULL)
return 0;
if(partition->part_size!=0 &&
partition->part_size < td_ext2fs_blocks_count(sb) *
(EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size)))
return 8;
if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_HUGE_FILE)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_GDT_CSUM)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_DIR_NLINK)!=0 ||
EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)!=0 ||
EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_64BIT)!=0 ||
EXT2_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_MMP)!=0)
partition->upart_type=UP_EXT4;
else if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0)
partition->upart_type=UP_EXT3;
else
partition->upart_type=UP_EXT2;
return 0;
}

32
src/ext2_common.h Normal file
View file

@ -0,0 +1,32 @@
/*
File: ext2_common.h
Copyright (C) 2013 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 __cplusplus
extern "C" {
#endif
uint64_t td_ext2fs_blocks_count(const struct ext2_super_block *super);
uint64_t td_ext2fs_free_blocks_count(const struct ext2_super_block *super);
int test_EXT2(const struct ext2_super_block *sb, partition_t *partition);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif

View file

@ -30,6 +30,7 @@
#include "types.h"
#include "common.h"
#include "ext2.h"
#include "ext2_common.h"
#include "filegen.h"
static void register_header_check_ext2_sb(file_stat_t *file_stat);
@ -66,22 +67,7 @@ static void file_rename_ext(const char *old_filename)
static int header_check_ext2_sb(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 ext2_super_block *sb=(const struct ext2_super_block *)buffer;
if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
return 0;
if (le32(sb->s_free_blocks_count) >= le32(sb->s_blocks_count))
return 0;
if (le32(sb->s_free_inodes_count) >= le32(sb->s_inodes_count))
return 0;
if (le16(sb->s_errors)!=0 &&
(le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
(le16(sb->s_errors) != EXT2_ERRORS_RO) &&
(le16(sb->s_errors) != EXT2_ERRORS_PANIC))
return 0;
if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
return 0;
if (le32(sb->s_blocks_count) == 0) /* reject empty filesystem */
return 0;
if(le32(sb->s_log_block_size)>2) /* block size max = 4096, can be 8192 on alpha */
if(test_EXT2(sb, NULL)!=0)
return 0;
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_ext2_sb.extension;

View file

@ -30,6 +30,7 @@
#include "types.h"
#include "common.h"
#include "ext2.h"
#include "ext2_common.h"
#include "filegen.h"
static void register_header_check_ext2_fs(file_stat_t *file_stat);
@ -55,22 +56,7 @@ static void register_header_check_ext2_fs(file_stat_t *file_stat)
static int header_check_ext2_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)
{
const struct ext2_super_block *sb=(const struct ext2_super_block *)&buffer[0x400];
if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
return 0;
if (le32(sb->s_free_blocks_count) >= le32(sb->s_blocks_count))
return 0;
if (le32(sb->s_free_inodes_count) >= le32(sb->s_inodes_count))
return 0;
if (le16(sb->s_errors)!=0 &&
(le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
(le16(sb->s_errors) != EXT2_ERRORS_RO) &&
(le16(sb->s_errors) != EXT2_ERRORS_PANIC))
return 0;
if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
return 0;
if (le32(sb->s_blocks_count) == 0) /* reject empty filesystem */
return 0;
if(le32(sb->s_log_block_size)>2) /* block size max = 4096, can be 8192 on alpha */
if(test_EXT2(sb, NULL)!=0)
return 0;
if(le16(sb->s_block_group_nr)!=0)
return 0;