Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F4324621
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
21 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/trunk/libxmount_morphing/libxmount_morphing_freespace/libxmount_morphing_freespace.c b/trunk/libxmount_morphing/libxmount_morphing_freespace/libxmount_morphing_freespace.c
index 9ee8fbd..5593843 100644
--- a/trunk/libxmount_morphing/libxmount_morphing_freespace/libxmount_morphing_freespace.c
+++ b/trunk/libxmount_morphing/libxmount_morphing_freespace/libxmount_morphing_freespace.c
@@ -1,591 +1,605 @@
/*******************************************************************************
* xmount Copyright (c) 2008-2014 by Gillen Daniel <gillen.dan@pinguin.lu> *
* *
* 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 <http://www.gnu.org/licenses/>. *
*******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../libxmount_morphing.h"
#include "libxmount_morphing_freespace.h"
/*******************************************************************************
* 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 "freespace\0\0";
}
/*
* LibXmount_Morphing_GetFunctions
*/
void LibXmount_Morphing_GetFunctions(ts_LibXmountMorphingFunctions *p_functions)
{
p_functions->CreateHandle=&FreespaceCreateHandle;
p_functions->DestroyHandle=&FreespaceDestroyHandle;
p_functions->Morph=&FreespaceMorph;
p_functions->Size=&FreespaceSize;
p_functions->Read=&FreespaceRead;
p_functions->OptionsHelp=&FreespaceOptionsHelp;
p_functions->OptionsParse=&FreespaceOptionsParse;
p_functions->GetInfofileContent=&FreespaceGetInfofileContent;
p_functions->GetErrorMessage=&FreespaceGetErrorMessage;
p_functions->FreeBuffer=&FreespaceFreeBuffer;
}
/*******************************************************************************
* Private
******************************************************************************/
/*
* FreespaceCreateHandle
*/
static int FreespaceCreateHandle(void **pp_handle,
char *p_format,
uint8_t debug)
{
pts_FreespaceHandle p_freespace_handle;
// Alloc new handle
p_freespace_handle=malloc(sizeof(ts_FreespaceHandle));
if(p_freespace_handle==NULL) return FREESPACE_MEMALLOC_FAILED;
// Init handle values
p_freespace_handle->debug=debug;
//p_freespace_handle->fs_type=FreespaceFsType_Unknown;
// DEBUG
p_freespace_handle->fs_type=FreespaceFsType_HfsPlus;
p_freespace_handle->p_input_functions=NULL;
p_freespace_handle->morphed_image_size=0;
p_freespace_handle->hfsplus.p_vh=NULL;
p_freespace_handle->hfsplus.p_alloc_file=NULL;
p_freespace_handle->hfsplus.free_block_map_size=0;
p_freespace_handle->hfsplus.p_free_block_map=NULL;
LOG_DEBUG("Created new LibXmount_Morphing_Freespace handle\n");
// Return new handle
*pp_handle=p_freespace_handle;
return FREESPACE_OK;
}
/*
* FreespaceDestroyHandle
*/
static int FreespaceDestroyHandle(void **pp_handle) {
pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)*pp_handle;
LOG_DEBUG("Destroying LibXmount_Morphing_Freespace handle\n");
// Free fs data
switch(p_freespace_handle->fs_type) {
case FreespaceFsType_HfsPlus: {
if(p_freespace_handle->hfsplus.p_vh!=NULL)
free(p_freespace_handle->hfsplus.p_vh);
if(p_freespace_handle->hfsplus.p_alloc_file!=NULL)
free(p_freespace_handle->hfsplus.p_alloc_file);
if(p_freespace_handle->hfsplus.p_free_block_map!=NULL)
free(p_freespace_handle->hfsplus.p_free_block_map);
break;
}
case FreespaceFsType_Unknown:
default:
break;
}
// Free handle
free(p_freespace_handle);
*pp_handle=NULL;
return FREESPACE_OK;
}
/*
* FreespaceMorph
*/
static int FreespaceMorph(void *p_handle,
pts_LibXmountMorphingInputFunctions p_input_functions)
{
pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)p_handle;
uint64_t input_images_count;
int ret;
LOG_DEBUG("Initializing LibXmount_Morphing_Raid\n");
// Make sure freespace_fs was given
if(p_freespace_handle->fs_type==FreespaceFsType_Unknown) {
return FREESPACE_NO_FS_SPECIFIED;
}
// Set input functions and get image count
p_freespace_handle->p_input_functions=p_input_functions;
if(p_freespace_handle->
p_input_functions->
ImageCount(&input_images_count)!=0)
{
return FREESPACE_CANNOT_GET_IMAGECOUNT;
}
// Make sure there is exactly one input image
if(input_images_count==0 || input_images_count>1) {
return FREESPACE_WRONG_INPUT_IMAGE_COUNT;
}
// Extract unallocated blocks from input image
switch(p_freespace_handle->fs_type) {
case FreespaceFsType_HfsPlus: {
// Read HFS+ VH
ret=FreespaceReadHfsPlusHeader(p_freespace_handle);
if(ret!=FREESPACE_OK) return ret;
// Read HFS+ alloc file
ret=FreespaceReadHfsPlusAllocFile(p_freespace_handle);
if(ret!=FREESPACE_OK) return ret;
// Build free block map
ret=FreespaceBuildHfsPlusBlockMap(p_freespace_handle);
if(ret!=FREESPACE_OK) return ret;
// Calculate morphed image size
p_freespace_handle->morphed_image_size=
p_freespace_handle->hfsplus.p_vh->block_size*
p_freespace_handle->hfsplus.free_block_map_size;
break;
}
case FreespaceFsType_Unknown:
default:
return FREESPACE_UNSUPPORTED_FS_SPECIFIED;
}
LOG_DEBUG("Total size of unallocated blocks is %" PRIu64 " bytes\n",
p_freespace_handle->morphed_image_size);
return FREESPACE_OK;
}
/*
* FreespaceSize
*/
static int FreespaceSize(void *p_handle, uint64_t *p_size) {
*p_size=((pts_FreespaceHandle)(p_handle))->morphed_image_size;
return FREESPACE_OK;
}
/*
* FreespaceRead
*/
static int FreespaceRead(void *p_handle,
char *p_buf,
off_t offset,
size_t count,
size_t *p_read)
{
pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)p_handle;
int ret;
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_freespace_handle->morphed_image_size ||
offset+count>p_freespace_handle->morphed_image_size)
{
return FREESPACE_READ_BEYOND_END_OF_IMAGE;
}
// Read data
switch(p_freespace_handle->fs_type) {
case FreespaceFsType_HfsPlus: {
ret=FreespaceReadHfsPlusBlock(p_freespace_handle,
p_buf,
offset,
count,
p_read);
if(ret!=FREESPACE_OK) return ret;
break;
}
case FreespaceFsType_Unknown:
default:
return FREESPACE_UNSUPPORTED_FS_SPECIFIED;
}
return FREESPACE_OK;
}
/*
* FreespaceOptionsHelp
*/
static const char* FreespaceOptionsHelp() {
return " freespace_fs : Specify the filesystem to extract unallocated "
"blocks from. Supported filesystems are: 'hfs+'";
}
/*
* FreespaceOptionsParse
*/
static int FreespaceOptionsParse(void *p_handle,
uint32_t options_count,
pts_LibXmountOptions *pp_options,
char **pp_error)
{
pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)p_handle;
int ok;
for(uint32_t i=0;i<options_count;i++) {
if(strcmp(pp_options[i]->p_key,"freespace_fs")==0) {
if(strcmp(pp_options[i]->p_value,"hfs+")==0) {
p_freespace_handle->fs_type=FreespaceFsType_HfsPlus;
} else {
ok=asprintf(pp_error,
"Unsupported filesystem '%s' specified",
pp_options[i]->p_value);
if(ok<0 || *pp_error==NULL) {
*pp_error=NULL;
return FREESPACE_MEMALLOC_FAILED;
}
return FREESPACE_UNSUPPORTED_FS_SPECIFIED;
}
LOG_DEBUG("Setting fs to %s\n",pp_options[i]->p_value);
pp_options[i]->valid=1;
}
}
return FREESPACE_OK;
}
/*
* FreespaceGetInfofileContent
*/
static int FreespaceGetInfofileContent(void *p_handle, char **pp_info_buf) {
- //pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)p_handle;
- //int ret;
+ pts_FreespaceHandle p_freespace_handle=(pts_FreespaceHandle)p_handle;
+ pts_FreespaceHfsPlusData p_hfs_data=&(p_freespace_handle->hfsplus);
+ int ret;
- *pp_info_buf=NULL;
- // TODO
-/*
ret=asprintf(pp_info_buf,
- "Simulating RAID level 0 over %" PRIu64 " disks.\n"
- "Chunk size: %" PRIu32 " bytes\n"
- "Chunks per disk: %" PRIu64 "\n"
- "Total capacity: %" PRIu64 " bytes (%0.3f GiB)\n",
- p_raid_handle->input_images_count,
- p_raid_handle->chunk_size,
- p_raid_handle->chunks_per_image,
- p_raid_handle->morphed_image_size,
- p_raid_handle->morphed_image_size/(1024.0*1024.0*1024.0));
- if(ret<0 || *pp_info_buf==NULL) return RAID_MEMALLOC_FAILED;
-*/
+ "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_hfs_data->p_vh->signature,
+ p_hfs_data->p_vh->version,
+ p_hfs_data->p_vh->block_size,
+ p_hfs_data->p_vh->total_blocks,
+ p_hfs_data->p_vh->free_blocks,
+ p_hfs_data->p_vh->alloc_file_size,
+ p_hfs_data->p_vh->alloc_file_total_blocks,
+ (uint64_t)(p_hfs_data->free_block_map_size*
+ p_hfs_data->p_vh->block_size),
+ (p_hfs_data->free_block_map_size*p_hfs_data->p_vh->block_size)/
+ (1024.0*1024.0*1024.0));
+ if(ret<0 || *pp_info_buf==NULL) return FREESPACE_MEMALLOC_FAILED;
+
return FREESPACE_OK;
}
/*
* FreespaceGetErrorMessage
*/
static const char* FreespaceGetErrorMessage(int err_num) {
switch(err_num) {
case FREESPACE_MEMALLOC_FAILED:
return "Unable to allocate memory";
break;
case FREESPACE_NO_FS_SPECIFIED:
return "No filesystem specified using option freespace_fs";
break;
case FREESPACE_UNSUPPORTED_FS_SPECIFIED:
return "Unsupported fs specified";
case FREESPACE_CANNOT_GET_IMAGECOUNT:
return "Unable to get input image count";
break;
case FREESPACE_WRONG_INPUT_IMAGE_COUNT:
return "Only 1 input image is supported";
break;
case FREESPACE_CANNOT_GET_IMAGESIZE:
return "Unable to get input image size";
break;
case FREESPACE_READ_BEYOND_END_OF_IMAGE:
return "Unable to read data: Attempt to read past EOF";
break;
case FREESPACE_CANNOT_READ_DATA:
return "Unable to read data";
break;
case FREESPACE_CANNOT_PARSE_OPTION:
return "Unable to parse library option";
break;
case FREESPACE_CANNOT_READ_HFSPLUS_HEADER:
return "Unable to read HFS+ volume header";
break;
case FREESPACE_INVALID_HFSPLUS_HEADER:
return "Found invalid HFS+ volume header";
break;
case FREESPACE_CANNOT_READ_HFSPLUS_ALLOC_FILE:
return "Unable to read HFS+ allocation file";
break;
case FREESPACE_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS:
return "HFS+ allocation file has more then 8 extends. This is unsupported";
break;
default:
return "Unknown error";
}
}
/*
* FreespaceFreeBuffer
*/
static void FreespaceFreeBuffer(void *p_buf) {
free(p_buf);
}
/*******************************************************************************
* Private helper functions
******************************************************************************/
/*
* FreespaceReadHfsPlusHeader
*/
static int FreespaceReadHfsPlusHeader(pts_FreespaceHandle p_freespace_handle) {
pts_FreespaceHfsPlusData p_hfs_data=&(p_freespace_handle->hfsplus);
int ret;
size_t bytes_read;
pts_FreespaceHfsPlusExtend p_extend;
LOG_DEBUG("Reading HFS+ volume header\n");
// Alloc buffer for header
p_hfs_data->p_vh=calloc(1,sizeof(ts_FreespaceHfsPlusVH));
if(p_hfs_data->p_vh==NULL) return FREESPACE_MEMALLOC_FAILED;
// Read VH from input image
ret=p_freespace_handle->
p_input_functions->
Read(0,
(char*)(p_hfs_data->p_vh),
FREESPACE_HFSPLUS_VH_OFFSET,
sizeof(ts_FreespaceHfsPlusVH),
&bytes_read);
if(ret!=0 || bytes_read!=sizeof(ts_FreespaceHfsPlusVH)) {
free(p_hfs_data->p_vh);
p_hfs_data->p_vh=NULL;
return FREESPACE_CANNOT_READ_HFSPLUS_HEADER;
}
// Convert VH to host endianness
p_hfs_data->p_vh->signature=be16toh(p_hfs_data->p_vh->signature);
p_hfs_data->p_vh->version=be16toh(p_hfs_data->p_vh->version);
p_hfs_data->p_vh->block_size=be32toh(p_hfs_data->p_vh->block_size);
p_hfs_data->p_vh->total_blocks=be32toh(p_hfs_data->p_vh->total_blocks);
p_hfs_data->p_vh->free_blocks=be32toh(p_hfs_data->p_vh->free_blocks);
p_hfs_data->p_vh->alloc_file_size=be64toh(p_hfs_data->p_vh->alloc_file_size);
p_hfs_data->p_vh->alloc_file_clump_size=
be32toh(p_hfs_data->p_vh->alloc_file_clump_size);
p_hfs_data->p_vh->alloc_file_total_blocks=
be32toh(p_hfs_data->p_vh->alloc_file_total_blocks);
for(int i=0;i<8;i++) {
p_extend=&(p_hfs_data->p_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_data->p_vh->signature);
LOG_DEBUG("HFS+ VH version: %" PRIu16 "\n",p_hfs_data->p_vh->version);
LOG_DEBUG("HFS+ block size: %" PRIu32 " bytes\n",p_hfs_data->p_vh->block_size);
LOG_DEBUG("HFS+ total blocks: %" PRIu32 "\n",p_hfs_data->p_vh->total_blocks);
LOG_DEBUG("HFS+ free blocks: %" PRIu32 "\n",p_hfs_data->p_vh->free_blocks);
LOG_DEBUG("HFS+ allocation file size: %" PRIu64 " bytes\n",
p_hfs_data->p_vh->alloc_file_size);
LOG_DEBUG("HFS+ allocation file blocks: %" PRIu32 "\n",
p_hfs_data->p_vh->alloc_file_total_blocks);
// Check header signature and version
if(p_hfs_data->p_vh->signature!=FREESPACE_HFSPLUS_VH_SIGNATURE ||
p_hfs_data->p_vh->version!=FREESPACE_HFSPLUS_VH_VERSION)
{
free(p_hfs_data->p_vh);
p_hfs_data->p_vh=NULL;
return FREESPACE_INVALID_HFSPLUS_HEADER;
}
return FREESPACE_OK;
}
/*
* FreespaceReadHfsPlusAllocFile
*/
static int FreespaceReadHfsPlusAllocFile(pts_FreespaceHandle p_freespace_handle)
{
pts_FreespaceHfsPlusData p_hfs_data=&(p_freespace_handle->hfsplus);
pts_FreespaceHfsPlusExtend p_extend;
int ret;
char *p_buf;
size_t bytes_read;
uint64_t total_bytes_read=0;
LOG_DEBUG("Reading HFS+ allocation file\n");
// Alloc buffer for file
p_hfs_data->p_alloc_file=calloc(1,p_hfs_data->p_vh->alloc_file_size);
if(p_hfs_data->p_alloc_file==NULL) return FREESPACE_MEMALLOC_FAILED;
// Loop over extends and read data
p_buf=(char*)(p_hfs_data->p_alloc_file);
for(int i=0;i<8;i++) {
p_extend=&(p_hfs_data->p_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;ii<p_extend->block_count;ii++) {
LOG_DEBUG("Reading %" PRIu32 " bytes from block %" PRIu32
" at offset %" PRIu64 "\n",
p_hfs_data->p_vh->block_size,
p_extend->start_block+ii,
(uint64_t)((p_extend->start_block+ii)*
p_hfs_data->p_vh->block_size));
ret=p_freespace_handle->
p_input_functions->
Read(0,
p_buf,
(p_extend->start_block+ii)*p_hfs_data->p_vh->block_size,
p_hfs_data->p_vh->block_size,
&bytes_read);
if(ret!=0 || bytes_read!=p_hfs_data->p_vh->block_size) {
free(p_hfs_data->p_alloc_file);
p_hfs_data->p_alloc_file=NULL;
return FREESPACE_CANNOT_READ_HFSPLUS_ALLOC_FILE;
}
p_buf+=p_hfs_data->p_vh->block_size;
total_bytes_read+=p_hfs_data->p_vh->block_size;
}
}
// Alloc files with more then 8 extends aren't supported yet
if(total_bytes_read!=p_hfs_data->p_vh->alloc_file_size) {
free(p_hfs_data->p_alloc_file);
p_hfs_data->p_alloc_file=NULL;
return FREESPACE_ALLOC_FILE_HAS_TOO_MUCH_EXTENDS;
}
return FREESPACE_OK;
}
/*
* FreespaceBuildHfsPlusBlockMap
*/
static int FreespaceBuildHfsPlusBlockMap(pts_FreespaceHandle p_freespace_handle)
{
pts_FreespaceHfsPlusData p_hfs_data=&(p_freespace_handle->hfsplus);
LOG_DEBUG("Searching unallocated HFS+ blocks\n");
// Save offset of every unallocated block in block map
for(uint32_t cur_block=0;
cur_block<p_hfs_data->p_vh->total_blocks;
cur_block++)
{
if((p_hfs_data->p_alloc_file[cur_block/8] & (1<<(7-(cur_block%8))))==0) {
p_hfs_data->p_free_block_map=realloc(p_hfs_data->p_free_block_map,
(p_hfs_data->free_block_map_size+1)*
sizeof(uint64_t));
if(p_hfs_data->p_free_block_map==NULL) {
p_hfs_data->free_block_map_size=0;
return FREESPACE_MEMALLOC_FAILED;
}
p_hfs_data->p_free_block_map[p_hfs_data->free_block_map_size]=
cur_block*p_hfs_data->p_vh->block_size;
p_hfs_data->free_block_map_size++;
}
}
- LOG_DEBUG("According to VH, there should be %" PRIu64 " unallocated blocks\n",
- p_hfs_data->p_vh->free_blocks);
LOG_DEBUG("Found %" PRIu64 " unallocated HFS+ blocks\n",
p_hfs_data->free_block_map_size);
+ if(p_hfs_data->p_vh->free_blocks!=p_hfs_data->free_block_map_size) {
+ LOG_WARNING("According to VH, there should be %" PRIu64
+ " unallocated blocks but I found %" PRIu64 "\n",
+ p_hfs_data->p_vh->free_blocks,
+ p_hfs_data->free_block_map_size);
+ }
+
return FREESPACE_OK;
}
/*
* FreespaceReadHfsPlusBlock
*/
static int FreespaceReadHfsPlusBlock(pts_FreespaceHandle p_freespace_handle,
char *p_buf,
off_t offset,
size_t count,
size_t *p_read)
{
pts_FreespaceHfsPlusData p_hfs_data=&(p_freespace_handle->hfsplus);
uint64_t cur_block;
off_t cur_block_offset;
off_t cur_image_offset;
size_t cur_count;
int ret;
size_t bytes_read;
// Calculate starting block and block offset
cur_block=offset/p_hfs_data->p_vh->block_size;
cur_block_offset=offset-(cur_block*p_hfs_data->p_vh->block_size);
// Init p_read
*p_read=0;
while(count!=0) {
// Calculate input image offset to read from
cur_image_offset=p_hfs_data->p_free_block_map[cur_block]+cur_block_offset;
// Calculate how many bytes to read from current block
if(cur_block_offset+count>p_hfs_data->p_vh->block_size) {
cur_count=p_hfs_data->p_vh->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_freespace_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 FREESPACE_CANNOT_READ_DATA;
p_buf+=cur_count;
cur_block_offset=0;
count-=cur_count;
cur_block++;
(*p_read)+=cur_count;
}
return FREESPACE_OK;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Dec 24, 3:13 AM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1177004
Default Alt Text
(21 KB)
Attached To
Mode
rXMOUNT xmount
Attached
Detach File
Event Timeline
Log In to Comment