diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.c b/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.c index b66b3f6..67c37c7 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.c +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.c @@ -1,149 +1,374 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #include "fat_functions.h" #include "libxmount_morphing_unallocated_retvalues.h" +#include // For memset + #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(p_fat_handle->debug,__VA_ARGS__); \ } /* * ReadFatHeader */ int ReadFatHeader(pts_FatHandle p_fat_handle, pts_LibXmountMorphingInputFunctions p_input_functions, uint8_t debug) { pts_FatVH p_fat_vh; int ret; size_t bytes_read; uint32_t root_dir_sectors; uint32_t fat_size; uint32_t total_sectors; uint32_t data_sectors; uint32_t cluster_count; // Init FAT handle - p_fat_handle->p_fat_vh=NULL; + memset(p_fat_handle,0,sizeof(ts_FatHandle)); + p_fat_handle->fat_type=FatType_Unknown; p_fat_handle->debug=debug; LOG_DEBUG("Trying to read FAT volume header\n"); // Alloc buffer for header p_fat_vh=calloc(1,sizeof(ts_FatVH)); if(p_fat_vh==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Read VH from input image ret=p_input_functions->Read(0, (char*)(p_fat_vh), 0, sizeof(ts_FatVH), &bytes_read); if(ret!=0 || bytes_read!=sizeof(ts_FatVH)) { free(p_fat_vh); - p_fat_vh=NULL; return UNALLOCATED_FAT_CANNOT_READ_HEADER; } // Convert values to host endianness (FAT values are always stored in little // endian) p_fat_vh->bytes_per_sector=le16toh(p_fat_vh->bytes_per_sector); p_fat_vh->reserved_sectors=le16toh(p_fat_vh->reserved_sectors); p_fat_vh->root_entry_count=le16toh(p_fat_vh->root_entry_count); p_fat_vh->total_sectors_16=le16toh(p_fat_vh->total_sectors_16); p_fat_vh->fat16_sectors=le16toh(p_fat_vh->fat16_sectors); p_fat_vh->total_sectors_32=le32toh(p_fat_vh->total_sectors_32); p_fat_vh->fat32_sectors=le32toh(p_fat_vh->fat32_sectors); LOG_DEBUG("FAT VH jump instruction 1: 0x%02X\n",p_fat_vh->jump_inst[0]); LOG_DEBUG("FAT bytes per sector: %" PRIu16 "\n", p_fat_vh->bytes_per_sector); LOG_DEBUG("FAT sectors per cluster: %" PRIu8 "\n", p_fat_vh->sectors_per_cluster); LOG_DEBUG("FAT reserved sectors: %" PRIu16 "\n", p_fat_vh->reserved_sectors); LOG_DEBUG("FAT count: %" PRIu8 "\n",p_fat_vh->fat_count); LOG_DEBUG("FAT root entry count: %" PRIu16 "\n", p_fat_vh->root_entry_count); LOG_DEBUG("FAT media type: %02X\n",p_fat_vh->media_type); LOG_DEBUG("FAT total sector count (16bit): %" PRIu16 "\n", p_fat_vh->total_sectors_16); LOG_DEBUG("FAT sectors per FAT (16bit): %" PRIu16 "\n", p_fat_vh->fat16_sectors); LOG_DEBUG("FAT total sector count (32bit): %" PRIu32 "\n", p_fat_vh->total_sectors_32); LOG_DEBUG("FAT sectors per FAT (32bit): %" PRIu32 "\n", p_fat_vh->fat32_sectors); // Check header values if((p_fat_vh->jump_inst[0]!=0xEB && p_fat_vh->jump_inst[0]!=0xE9) || p_fat_vh->bytes_per_sector==0 || p_fat_vh->bytes_per_sector%512!=0 || p_fat_vh->sectors_per_cluster==0 || p_fat_vh->sectors_per_cluster%2!=0 || p_fat_vh->reserved_sectors==0 || p_fat_vh->fat_count==0 || (p_fat_vh->total_sectors_16==0 && p_fat_vh->total_sectors_32==0) || (p_fat_vh->total_sectors_16!=0 && p_fat_vh->total_sectors_32!=0)) { free(p_fat_vh); - p_fat_vh=NULL; return UNALLOCATED_FAT_INVALID_HEADER; } LOG_DEBUG("Determining FAT type\n"); // Determine the count of sectors occupied by the root directory root_dir_sectors=((p_fat_vh->root_entry_count*32)+ (p_fat_vh->bytes_per_sector-1))/p_fat_vh->bytes_per_sector; // Determine the count of sectors in the data region if(p_fat_vh->fat16_sectors!=0) fat_size=p_fat_vh->fat16_sectors; else fat_size=p_fat_vh->fat32_sectors; if(p_fat_vh->total_sectors_16!=0) total_sectors=p_fat_vh->total_sectors_16; else total_sectors=p_fat_vh->total_sectors_32; data_sectors=total_sectors-(p_fat_vh->reserved_sectors+ (p_fat_vh->fat_count*fat_size)+root_dir_sectors); // Determine the count of clusters cluster_count=data_sectors/p_fat_vh->sectors_per_cluster; // Determine FAT type if(cluster_count<4085) { - LOG_DEBUG("FAT is of type FAT12\n"); - p_fat_handle->fat_type=FatType_Fat12; + LOG_DEBUG("FAT is of unsupported type FAT12\n"); + free(p_fat_vh); + return UNALLOCATED_FAT_UNSUPPORTED_FS_TYPE; } else if(cluster_count<65525) { LOG_DEBUG("FAT is of type FAT16\n"); p_fat_handle->fat_type=FatType_Fat16; } else { LOG_DEBUG("FAT is of type FAT32\n"); p_fat_handle->fat_type=FatType_Fat32; } + // TODO: What about newer version of FAT like exFAT etc... ?? p_fat_handle->p_fat_vh=p_fat_vh; return UNALLOCATED_OK; } /* * FreeFatHeader */ void FreeFatHeader(pts_FatHandle p_fat_handle) { if(p_fat_handle==NULL) return; if(p_fat_handle->p_fat_vh!=NULL) free(p_fat_handle->p_fat_vh); + switch(p_fat_handle->fat_type) { + case FatType_Fat16: { + if(p_fat_handle->p_fat16!=NULL) free(p_fat_handle->p_fat16); + break; + } + case FatType_Fat32: { + if(p_fat_handle->p_fat32!=NULL) free(p_fat_handle->p_fat32); + break; + } + case FatType_Unknown: + default: + break; + } +} + +/* + * ReadFat + */ +int ReadFat(pts_FatHandle p_fat_handle, + pts_LibXmountMorphingInputFunctions p_input_functions) +{ + pts_FatVH p_fat_vh=p_fat_handle->p_fat_vh; + int ret; + size_t fat_size; + off_t fat_offset; + size_t bytes_read; + + LOG_DEBUG("Trying to read FAT\n"); + + // Determine FAT size + if(p_fat_vh->fat16_sectors!=0) fat_size=p_fat_vh->fat16_sectors; + else fat_size=p_fat_vh->fat32_sectors; + fat_size*=p_fat_vh->bytes_per_sector; + + // Calculate FAT offset + fat_offset=p_fat_vh->reserved_sectors*p_fat_vh->bytes_per_sector; + + LOG_DEBUG("FAT consists of %zu bytes starting at offset %zu\n", + fat_size, + fat_offset); + + // Alloc buffer and Read FAT + if(p_fat_handle->fat_type==FatType_Fat32) { + // Alloc buffer + p_fat_handle->p_fat32=(uint32_t*)calloc(1,fat_size); + if(p_fat_handle->p_fat32==NULL) return UNALLOCATED_MEMALLOC_FAILED; + + // Read FAT + ret=p_input_functions->Read(0, + (char*)(p_fat_handle->p_fat32), + fat_offset, + fat_size, + &bytes_read); + if(ret!=0 || bytes_read!=fat_size) { + free(p_fat_handle->p_fat32); + p_fat_handle->p_fat32=NULL; + return UNALLOCATED_FAT_CANNOT_READ_FAT; + } + + // Convert FAT to host endianness + for(uint64_t i=0;ip_fat32[i]=le32toh(p_fat_handle->p_fat32[i]); + } + } else { + // Alloc buffer + p_fat_handle->p_fat16=(uint16_t*)calloc(1,fat_size); + if(p_fat_handle->p_fat16==NULL) return UNALLOCATED_MEMALLOC_FAILED; + + // Read FAT + ret=p_input_functions->Read(0, + (char*)(p_fat_handle->p_fat16), + fat_offset, + fat_size, + &bytes_read); + if(ret!=0 || bytes_read!=fat_size) { + free(p_fat_handle->p_fat16); + p_fat_handle->p_fat16=NULL; + return UNALLOCATED_FAT_CANNOT_READ_FAT; + } + + // Convert FAT to host endianness + for(uint64_t i=0;ip_fat16[i]=le16toh(p_fat_handle->p_fat16[i]); + } + } + + LOG_DEBUG("FAT read successfully\n"); + + return UNALLOCATED_OK; +} + +/* + * BuildFatBlockMap + */ +int BuildFatBlockMap(pts_FatHandle p_fat_handle, + uint64_t **pp_free_block_map, + uint64_t *p_free_block_map_size, + uint64_t *p_block_size) +{ + pts_FatVH p_fat_vh=p_fat_handle->p_fat_vh; + uint64_t total_clusters; + uint64_t *p_free_block_map=NULL; + uint64_t free_block_map_size=0; + + LOG_DEBUG("Searching unallocated FAT clusters\n"); + + // Calculate total amount of cluster + if(p_fat_vh->total_sectors_16!=0) total_clusters=p_fat_vh->total_sectors_16; + else total_clusters=p_fat_vh->total_sectors_32; + total_clusters/=p_fat_vh->sectors_per_cluster; + + // Save offset of every unallocated cluster in block map + if(p_fat_handle->fat_type==FatType_Fat32) { + for(uint64_t cur_cluster=0;cur_clusterp_fat32[cur_cluster] & 0x0FFFFFFF)==0 || + (p_fat_handle->p_fat32[cur_cluster] & 0x0FFFFFFF)==0x0FFFFFF7) + { + LOG_DEBUG("Cluster %" PRIu64 " is unallocated (FAT value 0x%08X)\n", + cur_cluster, + p_fat_handle->p_fat32[cur_cluster]); + p_free_block_map=realloc(p_free_block_map, + (free_block_map_size+1)*sizeof(uint64_t)); + if(p_free_block_map==NULL) return UNALLOCATED_MEMALLOC_FAILED; + p_free_block_map[free_block_map_size]= + cur_cluster*p_fat_vh->bytes_per_sector*p_fat_vh->sectors_per_cluster; + free_block_map_size++; + } else { + LOG_DEBUG("Cluster %" PRIu64 " is allocated (FAT value 0x%08X)\n", + cur_cluster, + p_fat_handle->p_fat32[cur_cluster]); + } + } + } else { + for(uint64_t cur_cluster=0;cur_clusterp_fat16[cur_cluster] & 0x0FFF)==0 || + (p_fat_handle->p_fat16[cur_cluster] & 0x0FFF)==0x0FF7) + { + LOG_DEBUG("Cluster %" PRIu64 " is unallocated (FAT value 0x%04X)\n", + cur_cluster, + p_fat_handle->p_fat16[cur_cluster]); + p_free_block_map=realloc(p_free_block_map, + (free_block_map_size+1)*sizeof(uint64_t)); + if(p_free_block_map==NULL) return UNALLOCATED_MEMALLOC_FAILED; + p_free_block_map[free_block_map_size]= + cur_cluster*p_fat_vh->sectors_per_cluster*p_fat_vh->bytes_per_sector; + free_block_map_size++; + } else { + LOG_DEBUG("Cluster %" PRIu64 " is allocated (FAT value 0x%04X)\n", + cur_cluster, + p_fat_handle->p_fat16[cur_cluster]); + } + } + } + + LOG_DEBUG("Found %" PRIu64 " unallocated FAT clusters\n", + free_block_map_size); + + // Free FAT as it is no longer needed + if(p_fat_handle->fat_type==FatType_Fat32) { + free(p_fat_handle->p_fat32); + p_fat_handle->p_fat32=NULL; + } else { + free(p_fat_handle->p_fat16); + p_fat_handle->p_fat16=NULL; + } + + *pp_free_block_map=p_free_block_map; + *p_free_block_map_size=free_block_map_size; + *p_block_size=p_fat_vh->bytes_per_sector*p_fat_vh->sectors_per_cluster; + return UNALLOCATED_OK; +} + +/* + * GetFatInfos + */ +int GetFatInfos(pts_FatHandle p_fat_handle, char **pp_buf) { + pts_FatVH p_fat_vh=p_fat_handle->p_fat_vh; + int ret; + char *p_buf=NULL; + char *p_fat_type; + + switch(p_fat_handle->fat_type) { + case FatType_Fat16: + p_fat_type="FAT16"; + break; + case FatType_Fat32: + p_fat_type="FAT32"; + break; + case FatType_Unknown: + default: + p_fat_type="Unknown"; + } + + ret=asprintf(&p_buf, + "FAT filesystem type: %s\n" + "FAT bytes per sector: %" PRIu16 "\n" + "FAT sectors per cluster: %" PRIu8 "\n" + "FAT reserved sectors: %" PRIu16 "\n" + "FAT count: %" PRIu8 "\n" + "FAT root entry count: %" PRIu16 "\n" + "FAT media type: 0x%02X\n" + "FAT total sector count (16bit): %" PRIu16 "\n" + "FAT sectors per FAT (16bit): %" PRIu16 "\n" + "FAT total sector count (32bit): %" PRIu32 "\n" + "FAT sectors per FAT (32bit): %" PRIu32, + p_fat_type, + p_fat_vh->bytes_per_sector, + p_fat_vh->sectors_per_cluster, + p_fat_vh->reserved_sectors, + p_fat_vh->fat_count, + p_fat_vh->root_entry_count, + p_fat_vh->media_type, + p_fat_vh->total_sectors_16, + p_fat_vh->fat16_sectors, + p_fat_vh->total_sectors_32, + p_fat_vh->fat32_sectors); + + // Check if asprintf worked + if(ret<0 || p_buf==NULL) return UNALLOCATED_MEMALLOC_FAILED; + + *pp_buf=p_buf; + return UNALLOCATED_OK; } diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.h b/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.h index f057013..b1e9fda 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.h +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/fat_functions.h @@ -1,61 +1,72 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #ifndef FAT_FUNCTIONS_H #define FAT_FUNCTIONS_H #include "../libxmount_morphing.h" // Supported FAT types typedef enum e_FatType { - FatType_Fat12=0, + FatType_Unknown=0, FatType_Fat16, FatType_Fat32 } te_FatType; // Needed parts of the FAT volume header typedef struct s_FatVH { uint8_t jump_inst[3]; uint8_t oem_name[8]; uint16_t bytes_per_sector; uint8_t sectors_per_cluster; uint16_t reserved_sectors; uint8_t fat_count; uint16_t root_entry_count; uint16_t total_sectors_16; uint8_t media_type; uint16_t fat16_sectors; uint64_t unused01; uint32_t total_sectors_32; // Following value is only valid for FAT32 uint32_t fat32_sectors; } __attribute__ ((packed)) ts_FatVH, *pts_FatVH; // FAT handle typedef struct s_FatHandle { te_FatType fat_type; pts_FatVH p_fat_vh; + union { + uint16_t *p_fat16; + uint32_t *p_fat32; + }; uint8_t debug; } ts_FatHandle, *pts_FatHandle; int ReadFatHeader(pts_FatHandle p_fat_handle, pts_LibXmountMorphingInputFunctions p_input_functions, uint8_t debug); void FreeFatHeader(pts_FatHandle p_fat_handle); +int ReadFat(pts_FatHandle p_fat_handle, + pts_LibXmountMorphingInputFunctions p_input_functions); +int BuildFatBlockMap(pts_FatHandle p_fat_handle, + uint64_t **pp_free_block_map, + uint64_t *p_free_block_map_size, + uint64_t *p_block_size); +int GetFatInfos(pts_FatHandle p_fat_handle, char **pp_buf); #endif // FAT_FUNCTIONS_H diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.c b/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.c index 1ad9f67..167764b 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.c +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.c @@ -1,228 +1,260 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #include "hfs_functions.h" #include "libxmount_morphing_unallocated_retvalues.h" #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(p_hfs_handle->debug,__VA_ARGS__); \ } /* * ReadHfsHeader */ int ReadHfsHeader(pts_HfsHandle p_hfs_handle, pts_LibXmountMorphingInputFunctions p_input_functions, uint8_t debug) { pts_HfsVH p_hfs_vh; int ret; size_t bytes_read; pts_HfsExtend p_extend; // Init HFS handle p_hfs_handle->p_hfs_vh=NULL; p_hfs_handle->p_alloc_file=NULL; p_hfs_handle->debug=debug; LOG_DEBUG("Trying to read HFS volume header\n"); // Alloc buffer for header p_hfs_vh=calloc(1,sizeof(ts_HfsVH)); if(p_hfs_vh==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Read VH from input image ret=p_input_functions->Read(0, (char*)(p_hfs_vh), HFS_VH_OFFSET, sizeof(ts_HfsVH), &bytes_read); if(ret!=0 || bytes_read!=sizeof(ts_HfsVH)) { free(p_hfs_vh); p_hfs_vh=NULL; return UNALLOCATED_HFS_CANNOT_READ_HEADER; } // Convert VH to host endianness (HFS values are always stored in big endian) p_hfs_vh->signature=be16toh(p_hfs_vh->signature); p_hfs_vh->version=be16toh(p_hfs_vh->version); p_hfs_vh->block_size=be32toh(p_hfs_vh->block_size); p_hfs_vh->total_blocks=be32toh(p_hfs_vh->total_blocks); p_hfs_vh->free_blocks=be32toh(p_hfs_vh->free_blocks); p_hfs_vh->alloc_file_size=be64toh(p_hfs_vh->alloc_file_size); p_hfs_vh->alloc_file_clump_size=be32toh(p_hfs_vh->alloc_file_clump_size); p_hfs_vh->alloc_file_total_blocks=be32toh(p_hfs_vh->alloc_file_total_blocks); for(int i=0;i<8;i++) { p_extend=&(p_hfs_vh->alloc_file_extends[i]); p_extend->start_block=be32toh(p_extend->start_block); p_extend->block_count=be32toh(p_extend->block_count); } LOG_DEBUG("HFS VH signature: 0x%04X\n",p_hfs_vh->signature); LOG_DEBUG("HFS VH version: %" PRIu16 "\n",p_hfs_vh->version); LOG_DEBUG("HFS block size: %" PRIu32 " bytes\n",p_hfs_vh->block_size); LOG_DEBUG("HFS total blocks: %" PRIu32 "\n",p_hfs_vh->total_blocks); LOG_DEBUG("HFS free blocks: %" PRIu32 "\n",p_hfs_vh->free_blocks); LOG_DEBUG("HFS allocation file size: %" PRIu64 " bytes\n", p_hfs_vh->alloc_file_size); LOG_DEBUG("HFS allocation file blocks: %" PRIu32 "\n", p_hfs_vh->alloc_file_total_blocks); // Check header signature and version if(p_hfs_vh->signature!=HFS_VH_SIGNATURE || p_hfs_vh->version!=HFS_VH_VERSION) { free(p_hfs_vh); p_hfs_vh=NULL; return UNALLOCATED_HFS_INVALID_HEADER; } // We currently only support HFS+ p_hfs_handle->hfs_type=HfsType_HfsPlus; LOG_DEBUG("HFS volume header read successfully\n"); p_hfs_handle->p_hfs_vh=p_hfs_vh; return UNALLOCATED_OK; } /* * FreeHfsHeader */ void FreeHfsHeader(pts_HfsHandle p_hfs_handle) { if(p_hfs_handle==NULL) return; if(p_hfs_handle->p_hfs_vh!=NULL) free(p_hfs_handle->p_hfs_vh); if(p_hfs_handle->p_alloc_file!=NULL) free(p_hfs_handle->p_alloc_file); } /* * ReadHfsAllocFile */ int ReadHfsAllocFile(pts_HfsHandle p_hfs_handle, pts_LibXmountMorphingInputFunctions p_input_functions) { uint8_t *p_alloc_file; pts_HfsExtend p_extend; int ret; char *p_buf; size_t bytes_read; uint64_t total_bytes_read=0; LOG_DEBUG("Trying to read HFS allocation file\n"); // Alloc buffer for file p_alloc_file=calloc(1,p_hfs_handle->p_hfs_vh->alloc_file_size); if(p_alloc_file==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Loop over extends and read data p_buf=(char*)(p_alloc_file); for(int i=0;i<8;i++) { p_extend=&(p_hfs_handle->p_hfs_vh->alloc_file_extends[i]); // If start_block and block_count are zero, we parsed last extend if(p_extend->start_block==0 && p_extend->block_count==0) break; LOG_DEBUG("Extend %d contains %" PRIu32 " block(s) starting with block %" PRIu32 "\n", i, p_extend->block_count, p_extend->start_block); // Read data for(uint32_t ii=0;iiblock_count;ii++) { LOG_DEBUG("Reading %" PRIu32 " bytes from block %" PRIu32 " at offset %" PRIu64 "\n", p_hfs_handle->p_hfs_vh->block_size, p_extend->start_block+ii, (uint64_t)((p_extend->start_block+ii)* p_hfs_handle->p_hfs_vh->block_size)); ret=p_input_functions->Read(0, p_buf, (p_extend->start_block+ii)* p_hfs_handle->p_hfs_vh->block_size, p_hfs_handle->p_hfs_vh->block_size, &bytes_read); if(ret!=0 || bytes_read!=p_hfs_handle->p_hfs_vh->block_size) { free(p_alloc_file); return UNALLOCATED_HFS_CANNOT_READ_ALLOC_FILE; } p_buf+=p_hfs_handle->p_hfs_vh->block_size; total_bytes_read+=p_hfs_handle->p_hfs_vh->block_size; } } // Alloc files with more than 8 extends aren't supported yet if(total_bytes_read!=p_hfs_handle->p_hfs_vh->alloc_file_size) { free(p_alloc_file); return UNALLOCATED_HFS_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS; } LOG_DEBUG("HFS allocation file read successfully\n"); p_hfs_handle->p_alloc_file=p_alloc_file; return UNALLOCATED_OK; } /* * BuildHfsBlockMap */ int BuildHfsBlockMap(pts_HfsHandle p_hfs_handle, uint64_t **pp_free_block_map, uint64_t *p_free_block_map_size, uint64_t *p_block_size) { uint64_t *p_free_block_map=NULL; uint64_t free_block_map_size=0; LOG_DEBUG("Searching unallocated HFS blocks\n"); // Save offset of every unallocated block in block map for(uint32_t cur_block=0; cur_blockp_hfs_vh->total_blocks; cur_block++) { if((p_hfs_handle->p_alloc_file[cur_block/8] & (1<<(7-(cur_block%8))))==0) { p_free_block_map=realloc(p_free_block_map, (free_block_map_size+1)*sizeof(uint64_t)); if(p_free_block_map==NULL) return UNALLOCATED_MEMALLOC_FAILED; p_free_block_map[free_block_map_size]= cur_block*p_hfs_handle->p_hfs_vh->block_size; free_block_map_size++; } } LOG_DEBUG("Found %" PRIu64 " unallocated HFS blocks\n", free_block_map_size); if(p_hfs_handle->p_hfs_vh->free_blocks!=free_block_map_size) { LIBXMOUNT_LOG_WARNING("According to VH, there should be %" PRIu64 " unallocated blocks but I found %" PRIu64 "\n", p_hfs_handle->p_hfs_vh->free_blocks, free_block_map_size); } // Free alloc file as it is no longer needed free(p_hfs_handle->p_alloc_file); p_hfs_handle->p_alloc_file=NULL; *pp_free_block_map=p_free_block_map; *p_free_block_map_size=free_block_map_size; *p_block_size=p_hfs_handle->p_hfs_vh->block_size; return UNALLOCATED_OK; } +/* + * GetHfsInfos + */ +int GetHfsInfos(pts_HfsHandle p_hfs_handle, char **pp_buf) { + pts_HfsVH p_hfs_vh=p_hfs_handle->p_hfs_vh; + char *p_buf=NULL; + int ret; + + ret=asprintf(&p_buf, + "HFS filesystem type: HFS+\n" + "HFS VH signature: 0x%04X\n" + "HFS VH version: %" PRIu16 "\n" + "HFS block size: %" PRIu32 " bytes\n" + "HFS total blocks: %" PRIu32 "\n" + "HFS free blocks: %" PRIu32 "\n" + "HFS allocation file size: %" PRIu64 " bytes\n" + "HFS allocation file blocks: %" PRIu32, + p_hfs_vh->signature, + p_hfs_vh->version, + p_hfs_vh->block_size, + p_hfs_vh->total_blocks, + p_hfs_vh->free_blocks, + p_hfs_vh->alloc_file_size, + p_hfs_vh->alloc_file_total_blocks); + + // Check if asprintf worked + if(ret<0 || p_buf==NULL) return UNALLOCATED_MEMALLOC_FAILED; + + *pp_buf=p_buf; + return UNALLOCATED_OK; +} + diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.h b/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.h index caaceb6..6e25652 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.h +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/hfs_functions.h @@ -1,72 +1,73 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #ifndef HFS_FUNCTIONS_H #define HFS_FUNCTIONS_H #include "../libxmount_morphing.h" // Supported HFS types typedef enum e_HfsType { HfsType_HfsPlus=0 } te_HfsType; // HFS extend typedef struct s_HfsExtend { uint32_t start_block; uint32_t block_count; } __attribute__ ((packed)) ts_HfsExtend, *pts_HfsExtend; // Needed parts of the HFS volume header #define HFS_VH_OFFSET 1024 #define HFS_VH_SIGNATURE 0x482b //"H+" #define HFS_VH_VERSION 4 typedef struct s_HfsVH { uint16_t signature; // "H+" uint16_t version; // Currently 4 for HFS+ uint32_t unused01[9]; uint32_t block_size; uint32_t total_blocks; uint32_t free_blocks; uint32_t unused02[15]; uint64_t alloc_file_size; uint32_t alloc_file_clump_size; uint32_t alloc_file_total_blocks; ts_HfsExtend alloc_file_extends[8]; } __attribute__ ((packed)) ts_HfsVH, *pts_HfsVH; // HFS handle typedef struct s_HfsHandle { te_HfsType hfs_type; pts_HfsVH p_hfs_vh; uint8_t *p_alloc_file; uint8_t debug; } ts_HfsHandle, *pts_HfsHandle; int ReadHfsHeader(pts_HfsHandle p_hfs_handle, pts_LibXmountMorphingInputFunctions p_input_functions, uint8_t debug); void FreeHfsHeader(pts_HfsHandle p_hfs_handle); int ReadHfsAllocFile(pts_HfsHandle p_hfs_handle, pts_LibXmountMorphingInputFunctions p_input_functions); int BuildHfsBlockMap(pts_HfsHandle p_hfs_handle, uint64_t **pp_free_block_map, uint64_t *p_free_block_map_size, uint64_t *p_block_size); +int GetHfsInfos(pts_HfsHandle p_hfs_handle, char **pp_buf); #endif // HFS_FUNCTIONS_H diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c index 6745a96..2529d4c 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated.c @@ -1,524 +1,511 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #include #include #include #include "libxmount_morphing_unallocated.h" #include "libxmount_morphing_unallocated_retvalues.h" #define LOG_DEBUG(...) { \ LIBXMOUNT_LOG_DEBUG(p_unallocated_handle->debug,__VA_ARGS__); \ } /******************************************************************************* * LibXmount_Morphing API implementation ******************************************************************************/ /* * LibXmount_Morphing_GetApiVersion */ uint8_t LibXmount_Morphing_GetApiVersion() { return LIBXMOUNT_MORPHING_API_VERSION; } /* * LibXmount_Morphing_GetSupportedFormats */ const char* LibXmount_Morphing_GetSupportedTypes() { return "unallocated\0\0"; } /* * LibXmount_Morphing_GetFunctions */ void LibXmount_Morphing_GetFunctions(ts_LibXmountMorphingFunctions *p_functions) { p_functions->CreateHandle=&UnallocatedCreateHandle; p_functions->DestroyHandle=&UnallocatedDestroyHandle; p_functions->Morph=&UnallocatedMorph; p_functions->Size=&UnallocatedSize; p_functions->Read=&UnallocatedRead; p_functions->OptionsHelp=&UnallocatedOptionsHelp; p_functions->OptionsParse=&UnallocatedOptionsParse; p_functions->GetInfofileContent=&UnallocatedGetInfofileContent; p_functions->GetErrorMessage=&UnallocatedGetErrorMessage; p_functions->FreeBuffer=&UnallocatedFreeBuffer; } /******************************************************************************* * Private ******************************************************************************/ /* * UnallocatedCreateHandle */ static int UnallocatedCreateHandle(void **pp_handle, const char *p_format, uint8_t debug) { pts_UnallocatedHandle p_unallocated_handle; // Alloc new handle. Using calloc in order to set everything to 0x00 p_unallocated_handle=calloc(1,sizeof(ts_UnallocatedHandle)); if(p_unallocated_handle==NULL) return UNALLOCATED_MEMALLOC_FAILED; // Init handle values p_unallocated_handle->debug=debug; p_unallocated_handle->fs_type=UnallocatedFsType_Unknown; LOG_DEBUG("Created new LibXmount_Morphing_Unallocated handle\n"); // Return new handle *pp_handle=p_unallocated_handle; return UNALLOCATED_OK; } /* * UnallocatedDestroyHandle */ static int UnallocatedDestroyHandle(void **pp_handle) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)*pp_handle; LOG_DEBUG("Destroying LibXmount_Morphing_Unallocated handle\n"); // TODO: Return if p_unallocated_handle==NULL // Free fs handle switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_Hfs: { FreeHfsHeader(&(p_unallocated_handle->hfs_handle)); break; } case UnallocatedFsType_Fat: { FreeFatHeader(&(p_unallocated_handle->fat_handle)); break; } case UnallocatedFsType_Unknown: default: break; } // Free handle values and handle if(p_unallocated_handle->p_free_block_map!=NULL) free(p_unallocated_handle->p_free_block_map); free(p_unallocated_handle); *pp_handle=NULL; return UNALLOCATED_OK; } /* * UnallocatedMorph */ static int UnallocatedMorph( void *p_handle, pts_LibXmountMorphingInputFunctions p_input_functions) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; uint64_t input_images_count; int ret; LOG_DEBUG("Initializing LibXmount_Morphing_Unallocated\n"); // Set input functions and get image count p_unallocated_handle->p_input_functions=p_input_functions; if(p_unallocated_handle-> p_input_functions-> ImageCount(&input_images_count)!=0) { return UNALLOCATED_CANNOT_GET_IMAGECOUNT; } // Make sure there is exactly one input image if(input_images_count==0 || input_images_count>1) { return UNALLOCATED_WRONG_INPUT_IMAGE_COUNT; } // Read filesystem header switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_Hfs: { // Read HFS VH ret=ReadHfsHeader(&(p_unallocated_handle->hfs_handle), p_unallocated_handle->p_input_functions, p_unallocated_handle->debug); if(ret!=UNALLOCATED_OK) return ret; break; } case UnallocatedFsType_Fat: { // Read FAT VH ret=ReadFatHeader(&(p_unallocated_handle->fat_handle), p_unallocated_handle->p_input_functions, p_unallocated_handle->debug); if(ret!=UNALLOCATED_OK) return ret; break; } case UnallocatedFsType_Unknown: { // Filesystem wasn't specified. Try to autodetect it by reading all // available fs headers + LOG_DEBUG("Autodetecting filesystem\n"); + LOG_DEBUG("Trying HFS\n"); ret=ReadHfsHeader(&(p_unallocated_handle->hfs_handle), p_unallocated_handle->p_input_functions, p_unallocated_handle->debug); if(ret==UNALLOCATED_OK) { - LOG_DEBUG("Detected HFS+ fs\n"); + LOG_DEBUG("Detected HFS fs\n"); p_unallocated_handle->fs_type=UnallocatedFsType_Hfs; break; } + LOG_DEBUG("Trying FAT\n"); ret=ReadFatHeader(&(p_unallocated_handle->fat_handle), p_unallocated_handle->p_input_functions, p_unallocated_handle->debug); if(ret==UNALLOCATED_OK) { LOG_DEBUG("Detected FAT fs\n"); p_unallocated_handle->fs_type=UnallocatedFsType_Fat; break; } LOG_DEBUG("Unable to autodetect fs\n"); return UNALLOCATED_NO_SUPPORTED_FS_DETECTED; } default: { return UNALLOCATED_INTERNAL_ERROR; } } // Extract unallocated blocks from input image switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_Hfs: { // Read HFS alloc file ret=ReadHfsAllocFile(&(p_unallocated_handle->hfs_handle), p_unallocated_handle->p_input_functions); if(ret!=UNALLOCATED_OK) return ret; // Build free block map ret=BuildHfsBlockMap(&(p_unallocated_handle->hfs_handle), &(p_unallocated_handle->p_free_block_map), &(p_unallocated_handle->free_block_map_size), &(p_unallocated_handle->block_size)); if(ret!=UNALLOCATED_OK) return ret; break; } case UnallocatedFsType_Fat: { - // TODO + // Read FAT + ret=ReadFat(&(p_unallocated_handle->fat_handle), + p_unallocated_handle->p_input_functions); + if(ret!=UNALLOCATED_OK) return ret; + // Build free block map + ret=BuildFatBlockMap(&(p_unallocated_handle->fat_handle), + &(p_unallocated_handle->p_free_block_map), + &(p_unallocated_handle->free_block_map_size), + &(p_unallocated_handle->block_size)); + if(ret!=UNALLOCATED_OK) return ret; break; } case UnallocatedFsType_Unknown: default: return UNALLOCATED_INTERNAL_ERROR; } // Calculate morphed image size p_unallocated_handle->morphed_image_size=p_unallocated_handle->block_size* p_unallocated_handle->free_block_map_size; LOG_DEBUG("Total size of unallocated blocks is %" PRIu64 " bytes\n", p_unallocated_handle->morphed_image_size); return UNALLOCATED_OK; } /* * UnallocatedSize */ static int UnallocatedSize(void *p_handle, uint64_t *p_size) { *p_size=((pts_UnallocatedHandle)(p_handle))->morphed_image_size; return UNALLOCATED_OK; } /* * UnallocatedRead */ static int UnallocatedRead(void *p_handle, char *p_buf, off_t offset, size_t count, size_t *p_read) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; uint64_t cur_block; off_t cur_block_offset; off_t cur_image_offset; size_t cur_count; int ret; size_t bytes_read; LOG_DEBUG("Reading %zu bytes at offset %zu from morphed image\n", count, offset); // Make sure read parameters are within morphed image bounds if(offset>=p_unallocated_handle->morphed_image_size || offset+count>p_unallocated_handle->morphed_image_size) { return UNALLOCATED_READ_BEYOND_END_OF_IMAGE; } // Calculate starting block and block offset cur_block=offset/p_unallocated_handle->block_size; cur_block_offset=offset-(cur_block*p_unallocated_handle->block_size); // Init p_read *p_read=0; while(count!=0) { // Calculate input image offset to read from cur_image_offset= p_unallocated_handle->p_free_block_map[cur_block]+cur_block_offset; // Calculate how many bytes to read from current block if(cur_block_offset+count>p_unallocated_handle->block_size) { cur_count=p_unallocated_handle->block_size-cur_block_offset; } else { cur_count=count; } LOG_DEBUG("Reading %zu bytes at offset %zu (block %" PRIu64 ")\n", cur_count, cur_image_offset+cur_block_offset, cur_block); // Read bytes ret=p_unallocated_handle->p_input_functions-> Read(0, p_buf, cur_image_offset+cur_block_offset, cur_count, &bytes_read); if(ret!=0 || bytes_read!=cur_count) return UNALLOCATED_CANNOT_READ_DATA; p_buf+=cur_count; cur_block_offset=0; count-=cur_count; cur_block++; (*p_read)+=cur_count; } return UNALLOCATED_OK; } /* * UnallocatedOptionsHelp */ static int UnallocatedOptionsHelp(const char **pp_help) { int ok; char *p_buf; ok=asprintf(&p_buf, " unallocated_fs : Specify the filesystem to extract " "unallocated blocks from. Supported filesystems are: " "'hfs', 'fat'. " "Default: autodetect.\n"); if(ok<0 || p_buf==NULL) { *pp_help=NULL; return UNALLOCATED_MEMALLOC_FAILED; } *pp_help=p_buf; return UNALLOCATED_OK; } /* * UnallocatedOptionsParse */ static int UnallocatedOptionsParse(void *p_handle, uint32_t options_count, const pts_LibXmountOptions *pp_options, const char **pp_error) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; int ok; char *p_buf; for(uint32_t i=0;ip_key,"unallocated_fs")==0) { if(strcmp(pp_options[i]->p_value,"hfs")==0) { p_unallocated_handle->fs_type=UnallocatedFsType_Hfs; } else if(strcmp(pp_options[i]->p_value,"fat")==0) { p_unallocated_handle->fs_type=UnallocatedFsType_Fat; } else { ok=asprintf(&p_buf, "Unsupported filesystem '%s' specified", pp_options[i]->p_value); if(ok<0 || p_buf==NULL) { *pp_error=NULL; return UNALLOCATED_MEMALLOC_FAILED; } *pp_error=p_buf; return UNALLOCATED_UNSUPPORTED_FS_SPECIFIED; } LOG_DEBUG("Setting fs to %s\n",pp_options[i]->p_value); pp_options[i]->valid=1; } } return UNALLOCATED_OK; } /* * UnallocatedGetInfofileContent */ static int UnallocatedGetInfofileContent(void *p_handle, const char **pp_info_buf) { pts_UnallocatedHandle p_unallocated_handle=(pts_UnallocatedHandle)p_handle; int ret=-1; + char *p_fs_buf=NULL; char *p_buf=NULL; switch(p_unallocated_handle->fs_type) { case UnallocatedFsType_Hfs: { - // TODO -/* - pts_HfsPlusVH p_hfsplus_vh=p_unallocated_handle->p_hfsplus_vh; - ret=asprintf(&p_buf, - "HFS+ VH signature: 0x%04X\n" - "HFS+ VH version: %" PRIu16 "\n" - "HFS+ block size: %" PRIu32 " bytes\n" - "HFS+ total blocks: %" PRIu32 "\n" - "HFS+ free blocks: %" PRIu32 "\n" - "HFS+ allocation file size: %" PRIu64 " bytes\n" - "HFS+ allocation file blocks: %" PRIu32 "\n" - "Discovered free blocks: %" PRIu64 "\n" - "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", - p_hfsplus_vh->signature, - p_hfsplus_vh->version, - p_hfsplus_vh->block_size, - p_hfsplus_vh->total_blocks, - p_hfsplus_vh->free_blocks, - p_hfsplus_vh->alloc_file_size, - p_hfsplus_vh->alloc_file_total_blocks, - p_unallocated_handle->free_block_map_size, - p_unallocated_handle->free_block_map_size* - p_unallocated_handle->block_size, - (p_unallocated_handle->free_block_map_size* - p_unallocated_handle->block_size)/(1024.0*1024.0*1024.0)); -*/ + ret=GetHfsInfos(&(p_unallocated_handle->hfs_handle),&p_fs_buf); break; } case UnallocatedFsType_Fat: { - // TODO -/* - pts_FatVH p_fat_vh=p_unallocated_handle->p_fat_vh; - ret=asprintf(&p_buf, - "FAT bytes per sector: %" PRIu16 "\n" - "FAT sectors per cluster: %" PRIu8 "\n" - "FAT reserved sectors: %" PRIu16 "\n" - "FAT count: %" PRIu8 "\n" - "FAT root entry count: %" PRIu16 "\n" - "FAT media type: %02X\n" - "FAT total sector count (16bit): %" PRIu16 "\n" - "FAT sectors per FAT (16bit): %" PRIu16 "\n" - "FAT total sector count (32bit): %" PRIu32 "\n" - "FAT sectors per FAT (32bit): %" PRIu32 "\n" - "Discovered free blocks: %" PRIu64 "\n" - "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", - p_fat_vh->bytes_per_sector, - p_fat_vh->sectors_per_cluster, - p_fat_vh->reserved_sectors, - p_fat_vh->fat_count, - p_fat_vh->root_entry_count, - p_fat_vh->media_type, - p_fat_vh->total_sectors_16, - p_fat_vh->fat16_sectors, - p_fat_vh->total_sectors_32, - p_fat_vh->fat32_sectors, - p_unallocated_handle->free_block_map_size, - p_unallocated_handle->free_block_map_size* - p_unallocated_handle->block_size, - (p_unallocated_handle->free_block_map_size* - p_unallocated_handle->block_size)/(1024.0*1024.0*1024.0)); -*/ + ret=GetFatInfos(&(p_unallocated_handle->fat_handle),&p_fs_buf); break; } case UnallocatedFsType_Unknown: default: return UNALLOCATED_INTERNAL_ERROR; } + if(ret!=UNALLOCATED_OK) return ret; + + if(p_fs_buf!=NULL) { + ret=asprintf(&p_buf, + "%s\n" + "Discovered free blocks: %" PRIu64 "\n" + "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", + p_fs_buf, + p_unallocated_handle->free_block_map_size, + p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size, + (p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size)/(1024.0*1024.0*1024.0)); + free(p_fs_buf); + } else { + ret=asprintf(&p_buf, + "Discovered free blocks: %" PRIu64 "\n" + "Total unallocated size: %" PRIu64 " bytes (%0.3f GiB)\n", + p_unallocated_handle->free_block_map_size, + p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size, + (p_unallocated_handle->free_block_map_size* + p_unallocated_handle->block_size)/(1024.0*1024.0*1024.0)); + } // Check if asprintf worked if(ret<0 || p_buf==NULL) return UNALLOCATED_MEMALLOC_FAILED; *pp_info_buf=p_buf; return UNALLOCATED_OK; } /* * UnallocatedGetErrorMessage */ static const char* UnallocatedGetErrorMessage(int err_num) { switch(err_num) { case UNALLOCATED_MEMALLOC_FAILED: return "Unable to allocate memory"; break; case UNALLOCATED_NO_SUPPORTED_FS_DETECTED: return "Unable to detect a supported file system"; break; case UNALLOCATED_UNSUPPORTED_FS_SPECIFIED: return "Unsupported fs specified"; break; case UNALLOCATED_INTERNAL_ERROR: return "Internal error"; break; case UNALLOCATED_CANNOT_GET_IMAGECOUNT: return "Unable to get input image count"; break; case UNALLOCATED_WRONG_INPUT_IMAGE_COUNT: return "Only 1 input image is supported"; break; case UNALLOCATED_CANNOT_GET_IMAGESIZE: return "Unable to get input image size"; break; case UNALLOCATED_READ_BEYOND_END_OF_IMAGE: return "Unable to read data: Attempt to read past EOF"; break; case UNALLOCATED_CANNOT_READ_DATA: return "Unable to read data"; break; case UNALLOCATED_CANNOT_PARSE_OPTION: return "Unable to parse library option"; break; // HFS errors case UNALLOCATED_HFS_CANNOT_READ_HEADER: return "Unable to read HFS volume header"; break; case UNALLOCATED_HFS_INVALID_HEADER: return "Found invalid HFS volume header"; break; case UNALLOCATED_HFS_CANNOT_READ_ALLOC_FILE: return "Unable to read HFS allocation file"; break; case UNALLOCATED_HFS_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS: return "HFS allocation file has more than 8 extends. " "This is unsupported"; break; // FAT errors case UNALLOCATED_FAT_CANNOT_READ_HEADER: return "Unable to read FAT volume header"; break; case UNALLOCATED_FAT_INVALID_HEADER: return "Found invalid FAT volume header"; break; + case UNALLOCATED_FAT_UNSUPPORTED_FS_TYPE: + return "Found unsupported FAT type"; + break; + case UNALLOCATED_FAT_CANNOT_READ_FAT: + return "Unable to read FAT"; + break; default: return "Unknown error"; } } /* * UnallocatedFreeBuffer */ static void UnallocatedFreeBuffer(void *p_buf) { free(p_buf); } diff --git a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated_retvalues.h b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated_retvalues.h index 6beda99..af24799 100644 --- a/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated_retvalues.h +++ b/trunk/libxmount_morphing/libxmount_morphing_unallocated/libxmount_morphing_unallocated_retvalues.h @@ -1,45 +1,47 @@ /******************************************************************************* * xmount Copyright (c) 2008-2014 by Gillen Daniel * * * * 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 3 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 . * *******************************************************************************/ #ifndef LIBXMOUNT_MORPHING_UNALLOCATED_RETVALUES_H #define LIBXMOUNT_MORPHING_UNALLOCATED_RETVALUES_H // Error codes enum { UNALLOCATED_OK=0, UNALLOCATED_MEMALLOC_FAILED, UNALLOCATED_NO_SUPPORTED_FS_DETECTED, UNALLOCATED_UNSUPPORTED_FS_SPECIFIED, UNALLOCATED_INTERNAL_ERROR, UNALLOCATED_CANNOT_GET_IMAGECOUNT, UNALLOCATED_WRONG_INPUT_IMAGE_COUNT, UNALLOCATED_CANNOT_GET_IMAGESIZE, UNALLOCATED_READ_BEYOND_END_OF_IMAGE, UNALLOCATED_CANNOT_READ_DATA, UNALLOCATED_CANNOT_PARSE_OPTION, // HFS return values UNALLOCATED_HFS_CANNOT_READ_HEADER, UNALLOCATED_HFS_INVALID_HEADER, UNALLOCATED_HFS_CANNOT_READ_ALLOC_FILE, UNALLOCATED_HFS_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS, // FAT return values UNALLOCATED_FAT_CANNOT_READ_HEADER, - UNALLOCATED_FAT_INVALID_HEADER + UNALLOCATED_FAT_INVALID_HEADER, + UNALLOCATED_FAT_UNSUPPORTED_FS_TYPE, + UNALLOCATED_FAT_CANNOT_READ_FAT }; #endif // LIBXMOUNT_MORPHING_UNALLOCATED_RETVALUES_H