diff --git a/src/Makefile.am b/src/Makefile.am index 45ad33a9..ac264978 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -.PRECIOUS: session_%.framac session_fidentify-%.framac +.PRECIOUS: session_%.framac session_fidentify-%.framac session_photorec-%.framac FRAMA_C_FLAGS=-machdep x86_64 \ -warn-left-shift-negative \ -warn-right-shift-negative \ @@ -36,13 +36,13 @@ endif bin_PROGRAMS = testdisk photorec fidentify $(QPHOTOREC) EXTRA_PROGRAMS = photorecf fuzzerfidentify -smallbase_C = common.c crc.c ext2_common.c fat_common.c log.c misc.c setdate.c -smallbase_H = common.h crc.h ext2_common.h fat_common.h log.h misc.h setdate.h +smallbase_C = common.c crc.c apfs_common.c ext2_common.c fat_common.c log.c misc.c setdate.c +smallbase_H = common.h crc.h apfs_common.h ext2_common.h fat_common.h log.h misc.h setdate.h base_C = $(smallbase_C) autoset.c ewf.c fnctdsk.c hdaccess.c hdcache.c hdwin32.c hidden.c hpa_dco.c intrf.c iso.c list_sort.c log_part.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 = $(smallbase_H) alignio.h autoset.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_part.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 ext2.c fat.c fatx.c f2fs.c jfs.c gfs2.c hfs.c hfsp.c hpfs.c luks.c lvm.c md.c netware.c ntfs.c refs.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 ext2.h fat.h fatx.h f2fs.h f2fs_fs.h jfs_superblock.h jfs.h gfs2.h hfs.h hfsp.h hpfs.h hfsp_struct.h luks.h luks_struct.h lvm.h md.h netware.h ntfs.h ntfs_struct.h refs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h vmfs.h wbfs.h xfs.h xfs_struct.h zfs.h +fs_C = analyse.c apfs.c bfs.c bsd.c btrfs.c cramfs.c exfat.c ext2.c fat.c fatx.c f2fs.c jfs.c gfs2.c hfs.c hfsp.c hpfs.c luks.c lvm.c md.c netware.c ntfs.c refs.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 apfs.h bfs.h bsd.h btrfs.h cramfs.h exfat.h ext2.h fat.h fatx.h f2fs.h f2fs_fs.h jfs_superblock.h jfs.h gfs2.h hfs.h hfsp.h hpfs.h hfsp_struct.h luks.h luks_struct.h lvm.h md.h netware.h ntfs.h ntfs_struct.h refs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h vmfs.h wbfs.h xfs.h xfs_struct.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_adv.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 diff --git a/src/analyse.c b/src/analyse.c index be1f6af9..303b3788 100644 --- a/src/analyse.c +++ b/src/analyse.c @@ -30,13 +30,15 @@ #include "types.h" #include "common.h" #include "analyse.h" +#include "fat.h" +#include "exfat.h" +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) +#include "apfs.h" #include "bfs.h" #include "bsd.h" #include "btrfs.h" #include "cramfs.h" -#include "exfat.h" #include "ext2.h" -#include "fat.h" #include "fatx.h" #include "f2fs_fs.h" #include "f2fs.h" @@ -61,8 +63,9 @@ #include "wbfs.h" #include "xfs.h" #include "zfs.h" -#include "log.h" +#endif #include "parti386.h" +#include "log.h" int search_NTFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) { @@ -70,10 +73,12 @@ int search_NTFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partiti return -1; { const struct ntfs_boot_sector *ntfs_header=(const struct ntfs_boot_sector*)buffer; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) /* NTFS recovery using backup sector */ if(le16(ntfs_header->marker)==0xAA55 && recover_NTFS(disk, ntfs_header, partition, verbose, dump_ind, 1)==0) return 1; +#endif } return 0; } @@ -82,6 +87,7 @@ int search_HFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partitio { if(disk->pread(disk, buffer, 0x400, partition->part_offset)!= 0x400) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { const hfs_mdb_t *hfs_mdb=(const hfs_mdb_t *)buffer; const struct hfsp_vh *vh=(const struct hfsp_vh *)buffer; @@ -99,6 +105,7 @@ int search_HFS_backup(unsigned char *buffer, disk_t *disk, partition_t *partitio return 1; } } +#endif return 0; } @@ -135,6 +142,7 @@ int search_FAT_backup(unsigned char *buffer, disk_t *disk, partition_t *partitio int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) { +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) /* Expect a buffer filled with 8k to handle the SWAP detection */ const pv_disk_t *pv=(const pv_disk_t *)buffer; const struct cramfs_super *cramfs=(const struct cramfs_super *)buffer; @@ -149,6 +157,7 @@ int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partit const struct xfs_sb *xfs=(const struct xfs_sb *)buffer; const union swap_header *swap_header=(const union swap_header *)buffer; const struct ReFS_boot_sector *refs_header=(const struct ReFS_boot_sector *)buffer; + const nx_superblock_t *apfs=(const nx_superblock_t *)buffer; static const uint8_t LUKS_MAGIC[LUKS_MAGIC_L] = {'L','U','K','S', 0xba, 0xbe}; // assert(sizeof(union swap_header)<=8*DEFAULT_SECTOR_SIZE); // assert(sizeof(pv_disk_t)<=8*DEFAULT_SECTOR_SIZE); @@ -162,6 +171,9 @@ int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partit log_trace("search_type_0 lba=%lu\n", (long unsigned)(partition->part_offset/disk->sector_size)); } + if(le32(apfs->nx_magic)== 0x4253584e && + recover_APFS(disk, apfs, partition, verbose, dump_ind)==0) + return 1; if((memcmp(swap_header->magic.magic, "SWAP", 4)==0 || memcmp(swap_header->magic8k.magic, "SWAP", 4)==0) && recover_Linux_SWAP(swap_header, partition)==0) @@ -212,16 +224,20 @@ int search_type_0(const unsigned char *buffer, disk_t *disk, partition_t *partit if(cramfs->magic==le32(CRAMFS_MAGIC) && recover_cramfs(disk, cramfs, partition, verbose, dump_ind)==0) return 1; +#endif +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_I386) /* Try to locate logical partition that may host truecrypt encrypted filesystem */ if(buffer[0x1fe]==0x55 && buffer[0x1ff]==0xAA && recover_i386_logical(disk, buffer, partition)==0 && partition->upart_type==UP_UNK) return 1; +#endif return 0; } int search_type_1(const unsigned char *buffer, const disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) { +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) const struct disklabel *bsd_header=(const struct disklabel *)(buffer+0x200); const struct disk_super_block *beos_block=(const struct disk_super_block*)(buffer+0x200); const struct cramfs_super *cramfs=(const struct cramfs_super *)(buffer+0x200); @@ -256,11 +272,13 @@ int search_type_1(const unsigned char *buffer, const disk_t *disk, partition_t * if(le32(sunlabel->magic_start) == SUN_LABEL_MAGIC_START && recover_sun_i386(disk, sunlabel, partition, verbose, dump_ind)==0) return 1; +#endif return 0; } int search_type_2(const unsigned char *buffer, disk_t *disk, partition_t *partition, const int verbose, const int dump_ind) { +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) const hfs_mdb_t *hfs_mdb=(const hfs_mdb_t *)(buffer+0x400); const struct hfsp_vh *vh=(const struct hfsp_vh *)(buffer+0x400); const struct ext2_super_block *sb=(const struct ext2_super_block*)(buffer+0x400); @@ -286,6 +304,7 @@ int search_type_2(const unsigned char *buffer, disk_t *disk, partition_t *partit if(sb_f2fs->magic == le32(F2FS_SUPER_MAGIC) && recover_f2fs(disk, sb_f2fs, partition)==0) return 1; +#endif return 0; } @@ -298,6 +317,7 @@ int search_type_8(unsigned char *buffer, disk_t *disk,partition_t *partition,con } if(disk->pread(disk, buffer, 4096, partition->part_offset + 4096) != 4096) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { /* MD 1.2 */ const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer; if(le32(sb1->major_version)==1 && @@ -307,6 +327,7 @@ int search_type_8(unsigned char *buffer, disk_t *disk,partition_t *partition,con return 1; } } +#endif return 0; } @@ -320,6 +341,7 @@ int search_type_16(unsigned char *buffer, disk_t *disk,partition_t *partition,co /* 8k offset */ if(disk->pread(disk, buffer, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 16 * 512) != 3 * DEFAULT_SECTOR_SIZE) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { const struct ufs_super_block *ufs=(const struct ufs_super_block *)buffer; const struct vdev_boot_header *zfs=(const struct vdev_boot_header*)buffer; @@ -332,6 +354,7 @@ int search_type_16(unsigned char *buffer, disk_t *disk,partition_t *partition,co recover_ZFS(disk, zfs, partition, verbose, dump_ind)==0) return 1; } +#endif return 0; } @@ -345,6 +368,7 @@ int search_type_64(unsigned char *buffer, disk_t *disk,partition_t *partition,co /* 32k offset */ if(disk->pread(disk, buffer, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 63 * 512) != 3 * DEFAULT_SECTOR_SIZE) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { const struct jfs_superblock* jfs=(const struct jfs_superblock*)(buffer+0x200); /* Test JFS */ @@ -352,6 +376,7 @@ int search_type_64(unsigned char *buffer, disk_t *disk,partition_t *partition,co recover_JFS(disk, jfs, partition, verbose, dump_ind)==0) return 1; } +#endif return 0; } @@ -364,6 +389,7 @@ int search_type_128(unsigned char *buffer, disk_t *disk, partition_t *partition, } if(disk->pread(disk, buffer, 11 * DEFAULT_SECTOR_SIZE, partition->part_offset + 126 * 512) != 11 * DEFAULT_SECTOR_SIZE) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { const unsigned char *buffer_1024=buffer+0x400; const struct reiserfs_super_block *rfs=(const struct reiserfs_super_block *)buffer_1024; @@ -389,6 +415,7 @@ int search_type_128(unsigned char *buffer, disk_t *disk, partition_t *partition, recover_gfs2(disk, gfs2, partition, dump_ind)==0) return 1; } +#endif return 0; } @@ -401,17 +428,20 @@ int search_type_2048(unsigned char *buffer, disk_t *disk, partition_t *partition } if(disk->pread(disk, buffer, 2*DEFAULT_SECTOR_SIZE, partition->part_offset + 2048 * 512) != 2*DEFAULT_SECTOR_SIZE) return -1; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) { const struct vmfs_volume *sb_vmfs=(const struct vmfs_volume *)buffer; if(le32(sb_vmfs->magic)==0xc001d00d && recover_VMFS(disk, sb_vmfs, partition, verbose, dump_ind)==0) return 1; } +#endif return 0; } int check_linux(disk_t *disk, partition_t *partition, const int verbose) { +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) if(check_JFS(disk, partition)==0 || check_rfs(disk, partition, verbose)==0 || check_EXT2(disk, partition, verbose)==0 || @@ -423,6 +453,7 @@ int check_linux(disk_t *disk, partition_t *partition, const int verbose) check_gfs2(disk, partition)==0 || check_ZFS(disk, partition)==0) return 0; +#endif return 1; } diff --git a/src/apfs.c b/src/apfs.c new file mode 100644 index 00000000..94a61233 --- /dev/null +++ b/src/apfs.c @@ -0,0 +1,105 @@ +/* + + File: apfs.c + + Copyright (C) 2021 Christophe GRENIER + + 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 +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include "types.h" +#include "common.h" +#include "apfs.h" +#include "fnctdsk.h" +#include "log.h" +#include "guid_cpy.h" + +static void set_APFS_info(const nx_superblock_t *sb, partition_t *partition) +{ + partition->upart_type=UP_APFS; +} + +int check_APFS(disk_t *disk_car, partition_t *partition) +{ + unsigned char *buffer=(unsigned char*)MALLOC(APFS_SUPERBLOCK_SIZE); + const nx_superblock_t* sb=(const nx_superblock_t *)buffer; + if(disk_car->pread(disk_car, buffer, APFS_SUPERBLOCK_SIZE, partition->part_offset) != APFS_SUPERBLOCK_SIZE) + { + free(buffer); + return 1; + } + if(test_APFS(sb, partition)!=0) + { + free(buffer); + return 1; + } + set_APFS_info(sb, partition); + free(buffer); + return 0; +} + +int recover_APFS(const disk_t *disk, const nx_superblock_t *sb, partition_t *partition, const int verbose, const int dump_ind) +{ + if(test_APFS(sb, partition)!=0) + return 1; + if(dump_ind!=0) + { + if(partition!=NULL && disk!=NULL) + log_info("\nAPFS magic value at %u/%u/%u\n", + offset2cylinder(disk,partition->part_offset), + offset2head(disk,partition->part_offset), + offset2sector(disk,partition->part_offset)); + /* There is a little offset ... */ + dump_log(sb,DEFAULT_SECTOR_SIZE); + } + if(partition==NULL) + return 0; + set_APFS_info(sb, partition); + partition->part_type_i386=P_LINUX; + partition->part_type_mac=PMAC_LINUX; + partition->part_type_sun=PSUN_LINUX; + partition->part_type_gpt=GPT_ENT_TYPE_MAC_APFS; + partition->part_size=le32(sb->nx_block_size) * le64(sb->nx_block_count); + guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->nx_uuid); + if(verbose>0) + { + log_info("\n"); + } + partition->sborg_offset=0; + partition->sb_size=le32(sb->nx_block_size); + partition->sb_offset=0; + if(verbose>0) + { + log_info("recover_APFS: s_blocksize=%u\n", partition->blocksize); + log_info("recover_APFS: s_blocks_count %lu\n", (long unsigned int)le64(sb->nx_block_count)); + if(disk==NULL) + log_info("recover_APFS: part_size %lu\n", (long unsigned)(partition->part_size / DEFAULT_SECTOR_SIZE)); + else + log_info("recover_APFS: part_size %lu\n", (long unsigned)(partition->part_size / disk->sector_size)); + } + return 0; +} diff --git a/src/apfs.h b/src/apfs.h new file mode 100644 index 00000000..b9163c4f --- /dev/null +++ b/src/apfs.h @@ -0,0 +1,48 @@ +/* + + File: apfs.h + + Copyright (C) 2021 Christophe GRENIER + + 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. + + */ +#ifndef _APFS_H +#define _APFS_H +#include "apfs_common.h" +#ifdef __cplusplus +extern "C" { +#endif +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int check_APFS(disk_t *disk_car, partition_t *partition); + +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ requires \valid_read(sb); + @ requires \valid(partition); + @ requires \separated(disk_car, partition); + @*/ +int recover_APFS(const disk_t *disk_car, const nx_superblock_t *sb, partition_t *partition, const int verbose, const int dump_ind); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/src/apfs_common.c b/src/apfs_common.c new file mode 100644 index 00000000..c2b9e6c2 --- /dev/null +++ b/src/apfs_common.c @@ -0,0 +1,76 @@ +/* + + File: apfs_common.c + + Copyright (C) 2021 Christophe GRENIER + + 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 +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include "types.h" +#include "common.h" +#include "apfs_common.h" +#include "log.h" + +static uint64_t fletcher64(const uint32_t *data, const size_t cnt, const uint64_t init) +{ + size_t k; + uint64_t sum1 = init & 0xFFFFFFFFU; + uint64_t sum2 = (init >> 32); + for (k = 0; k < cnt; k++) + { + sum1 = (sum1 + le32(data[k])); + sum2 = (sum2 + sum1); + } + sum1 = sum1 % 0xFFFFFFFF; + sum2 = sum2 % 0xFFFFFFFF; + return (sum2 << 32) | sum1; +} + +static uint64_t VerifyBlock(const void *block, const size_t size) +{ + uint64_t cs; + const uint32_t *data = (const uint32_t *)block; + const size_t size4 = size / sizeof(uint32_t); + + cs = fletcher64(data + 2, size4 - 2, 0); + cs = fletcher64(data, 2, cs); + return cs; +} + +int test_APFS(const nx_superblock_t *sb, const partition_t *partition) +{ + if(le32(sb->nx_magic)!=0x4253584e) + return 1; + if(le32(sb->nx_xp_desc_blocks) + le32(sb->nx_xp_data_blocks) > le64(sb->nx_block_count)) + return 2; + if(le32(sb->nx_block_size) < NX_MINIMUM_BLOCK_SIZE || + le32(sb->nx_block_size) > NX_MAXIMUM_BLOCK_SIZE) + return 3; + if(VerifyBlock(sb, 4096) != 0) + return 4; + return 0; +} diff --git a/src/apfs_common.h b/src/apfs_common.h new file mode 100644 index 00000000..724c7132 --- /dev/null +++ b/src/apfs_common.h @@ -0,0 +1,104 @@ +#ifndef _APFS_COMMON_H +#define _APFS_COMMON_H +#ifdef __cplusplus +extern "C" +{ +#endif +#define MAX_CKSUM_SIZE 8 +#define NX_EPH_INFO_COUNT 4 +#define NX_EPH_INFO_VERSION_1 1 +#define NX_EPH_MIN_BLOCK_COUNT 8 +#define NX_MAGIC 'BSXN' +#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 +#define NX_MAX_FILE_SYSTEMS 100 +#define NX_MAXIMUM_BLOCK_SIZE 65536 +#define NX_MINIMUM_BLOCK_SIZE 4096 +#define NX_TX_MIN_CHECKPOINT_COUNT 4 + + typedef enum { + NX_CNTR_OBJ_CKSUM_SET + = 0, + NX_CNTR_OBJ_CKSUM_FAIL = 1, + NX_NUM_COUNTERS = 32 + } nx_counter_id_t; + + typedef uint64_t oid_t; + typedef uint64_t xid_t; + + struct obj_phys { + uint8_t o_cksum[MAX_CKSUM_SIZE]; + oid_t o_oid; + xid_t o_xid; + uint32_t o_type; + uint32_t o_subtype; + } __attribute__((gcc_struct, __packed__)); + + typedef struct obj_phys obj_phys_t; + typedef int64_t paddr_t; + + struct prange { + paddr_t pr_start_paddr; + uint64_t pr_block_count; + } __attribute__((gcc_struct, __packed__)); + typedef struct prange prange_t; + + typedef unsigned char apfs_uuid_t[16]; + + struct nx_superblock { + obj_phys_t nx_o; + uint32_t nx_magic; + uint32_t nx_block_size; + uint64_t nx_block_count; + uint64_t nx_features; + uint64_t nx_readonly_compatible_features; + uint64_t nx_incompatible_features; + apfs_uuid_t nx_uuid; + oid_t nx_next_oid; + xid_t nx_next_xid; + uint32_t nx_xp_desc_blocks; + uint32_t nx_xp_data_blocks; + paddr_t nx_xp_desc_base; + paddr_t nx_xp_data_base; + uint32_t nx_xp_desc_next; + uint32_t nx_xp_data_next; + uint32_t nx_xp_desc_index; + uint32_t nx_xp_desc_len; + uint32_t nx_xp_data_index; + uint32_t nx_xp_data_len; + oid_t nx_spaceman_oid; + oid_t nx_omap_oid; + oid_t nx_reaper_oid; + uint32_t nx_test_type; + uint32_t nx_max_file_systems; + oid_t nx_fs_oid[NX_MAX_FILE_SYSTEMS]; + uint64_t nx_counters[NX_NUM_COUNTERS]; + prange_t nx_blocked_out_prange; + oid_t nx_evict_mapping_tree_oid; + uint64_t nx_flags; + paddr_t nx_efi_jumpstart; + apfs_uuid_t nx_fusion_uuid; + prange_t nx_keylocker; + uint64_t nx_ephemeral_info[NX_EPH_INFO_COUNT]; + oid_t nx_test_oid; + oid_t nx_fusion_mt_oid; + oid_t nx_fusion_wbc_oid; + prange_t nx_fusion_wbc; + uint64_t nx_newest_mounted_version; + prange_t nx_mkb_locker; + }; +typedef struct nx_superblock nx_superblock_t; + +//#define APFS_SUPERBLOCK_SIZE (sizeof(nx_superblock_t)) +#define APFS_SUPERBLOCK_SIZE 4096 +/*@ + @ requires \valid_read(sb); + @ requires partition==\null || (\valid_read(partition) && valid_partition(partition)); + @ requires \separated(sb, partition); + @ assigns \nothing; + @ */ +int test_APFS(const nx_superblock_t *sb, const partition_t *partition); + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/src/common.h b/src/common.h index c80d2f6c..10c3e320 100644 --- a/src/common.h +++ b/src/common.h @@ -245,6 +245,7 @@ struct efi_guid_s enum upart_type { UP_UNK=0, + UP_APFS, UP_BEOS, UP_BTRFS, UP_CRAMFS, @@ -458,8 +459,9 @@ struct param_disk_struct disk->sector_size > 0 )); */ +/*@ predicate valid_list_disk(list_disk_t* root) = ((root == \null) || (\valid_read(root))); */ -/*@ predicate valid_list_disk{L}(list_disk_t* root) = +/* TODO predicate valid_list_disk{L}(list_disk_t* root) = \forall list_disk_t *node; \valid(node) && ld_reachable(root,node) ==> \valid(node->disk); */ diff --git a/src/partgpt.c b/src/partgpt.c index add4e516..e6cb461f 100644 --- a/src/partgpt.c +++ b/src/partgpt.c @@ -20,7 +20,7 @@ */ - +#if !defined(SINGLE_PARTITION_TYPE) || defined(SINGLE_PARTITION_GPT) #ifdef HAVE_CONFIG_H #include #endif @@ -56,6 +56,7 @@ #include "chgtype.h" #include "partgpt.h" #include "savehdr.h" +#include "apfs.h" #include "bfs.h" #include "exfat.h" #include "fat.h" @@ -80,6 +81,7 @@ static int check_part_gpt(disk_t *disk, const int verbose, partition_t *partitio /*@ @ requires \valid(disk_car); + @ ensures valid_list_part(\result); @*/ static list_part_t *read_part_gpt(disk_t *disk_car, const int verbose, const int saveheader); @@ -100,7 +102,6 @@ static void set_next_status_gpt(const disk_t *disk_car, partition_t *partition); /*@ @ requires list_part == \null || \valid_read(list_part); - @ assigns \nothing; @*/ static int test_structure_gpt(const list_part_t *list_part); @@ -201,6 +202,11 @@ arch_fnct_t arch_gpt= .is_part_known=&is_part_known_gpt }; +/*@ + @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @*/ +// ensures valid_list_part(\result); static list_part_t *read_part_gpt_aux(disk_t *disk_car, const int verbose, const int saveheader, const uint64_t hdr_lba) { struct gpt_hdr *gpt; @@ -398,7 +404,10 @@ list_part_t *add_partition_gpt_cli(const disk_t *disk_car, list_part_t *list_par new_partition=partition_new(&arch_gpt); new_partition->part_offset=disk_car->sector_size; new_partition->part_size=disk_car->disk_size-new_partition->part_offset; - /*@ loop invariant valid_read_string(*current_cmd); */ + /*@ + @ loop invariant valid_list_part(list_part); + @ loop invariant valid_read_string(*current_cmd); + @ */ while(1) { skip_comma_in_command(current_cmd); @@ -434,19 +443,23 @@ list_part_t *add_partition_gpt_cli(const disk_t *disk_car, list_part_t *list_par { int insert_error=0; list_part_t *new_list_part=insert_new_partition(list_part, new_partition, 0, &insert_error); + /*@ assert valid_list_part(new_list_part); */ if(insert_error>0) { free(new_partition); + /*@ assert valid_list_part(new_list_part); */ return new_list_part; } new_partition->status=STATUS_PRIM; if(test_structure_gpt(list_part)!=0) new_partition->status=STATUS_DELETED; + /*@ assert valid_list_part(new_list_part); */ return new_list_part; } else { free(new_partition); + /*@ assert valid_list_part(list_part); */ return list_part; } } @@ -549,6 +562,12 @@ static int check_part_gpt(disk_t *disk, const int verbose,partition_t *partition if(ret!=0) screen_buffer_add("No HFS or HFS+ structure\n"); } + else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MAC_APFS)==0) + { + ret=check_APFS(disk, partition); + if(ret!=0) + screen_buffer_add("No valid APFS structure\n"); + } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_BEOS_BFS)==0) { ret=check_BeFS(disk, partition); @@ -576,6 +595,7 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt) for(i=0; gpt_sys_types[i].name!=NULL; i++) if(guid_cmp(gpt_sys_types[i].part_type, part_type_gpt)==0) return gpt_sys_types[i].name; +#ifndef __FRAMAC__ log_info("%8x %04x %04x %02x %02x %02x %02x %02x %02x %02x %02x\n", part_type_gpt.time_low, part_type_gpt.time_mid, @@ -588,6 +608,7 @@ static const char *get_gpt_typename(const efi_guid_t part_type_gpt) part_type_gpt.node[3], part_type_gpt.node[4], part_type_gpt.node[5]); +#endif return NULL; } @@ -595,3 +616,4 @@ static const char *get_partition_typename_gpt(const partition_t *partition) { return get_gpt_typename(partition->part_type_gpt); } +#endif diff --git a/src/partnone.c b/src/partnone.c index f354941b..4a59825c 100644 --- a/src/partnone.c +++ b/src/partnone.c @@ -39,6 +39,9 @@ #include "analyse.h" #include "lang.h" #include "intrf.h" +#include "fat_common.h" +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) +#include "apfs.h" #include "bfs.h" #include "bsd.h" #include "btrfs.h" @@ -46,7 +49,6 @@ #include "exfat.h" #include "ext2.h" #include "fat.h" -#include "fat_common.h" #include "fatx.h" #include "f2fs_fs.h" #include "f2fs.h" @@ -73,6 +75,7 @@ #include "vmfs.h" #include "wbfs.h" #include "zfs.h" +#endif #include "log.h" /*@ @@ -91,6 +94,8 @@ static int get_geometry_from_nonembr(const unsigned char *buffer, const int verb /*@ @ requires \valid(disk_car); + @ requires valid_disk(disk_car); + @ ensures valid_list_part(\result); @*/ static list_part_t *read_part_none(disk_t *disk_car, const int verbose, const int saveheader); @@ -143,6 +148,7 @@ static unsigned int get_part_type_none(const partition_t *partition); static const char *get_partition_typename_none(const partition_t *partition); static const struct systypes none_sys_types[] = { + {UP_APFS, "APFS"}, {UP_BEOS, "BeFS"}, {UP_BTRFS, "btrfs"}, {UP_CRAMFS, "CramFS"}, @@ -257,6 +263,7 @@ static list_part_t *read_part_none(disk_t *disk, const int verbose, const int sa partition=partition_new(&arch_none); buffer_disk=(unsigned char *)MALLOC(16*DEFAULT_SECTOR_SIZE); partition->part_size=disk->disk_size; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) if(recover_MD_from_partition(disk, partition, verbose)==0) res=1; else @@ -341,6 +348,7 @@ static list_part_t *read_part_none(disk_t *disk, const int verbose, const int sa } } } +#endif free(buffer_disk); if(res<=0) partition_reset(partition,&arch_none); @@ -350,7 +358,9 @@ static list_part_t *read_part_none(disk_t *disk, const int verbose, const int sa partition->status=STATUS_PRIM; screen_buffer_reset(); check_part_none(disk, verbose,partition,saveheader); +#ifndef __FRAMAC__ aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk, partition); +#endif list_part=insert_new_partition(NULL, partition, 0, &insert_error); if(insert_error>0) free(partition); @@ -395,8 +405,12 @@ static void init_structure_none(const disk_t *disk_car,list_part_t *list_part, c static int check_part_none(disk_t *disk_car,const int verbose,partition_t *partition, const int saveheader) { int ret=0; +#if !defined(__FRAMAC__) && !defined(MAIN_photorec) switch(partition->upart_type) { + case UP_APFS: + ret=check_APFS(disk_car, partition); + break; case UP_BEOS: ret=check_BeFS(disk_car,partition); break; @@ -525,6 +539,7 @@ static int check_part_none(disk_t *disk_car,const int verbose,partition_t *parti case UP_UNK: break; } +#endif return ret; }