📄 vpc.c
字号:
/* * vpc.c * Layered data source for Virtual PC hard disk images. * * Copyright (c) 2003 Christoph Pfisterer * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */#include "detect.h"/* * types */typedef struct vhd_chunk { int present; U64 off; U8 bitmap[1];}VHD_CHUNK;typedef struct vhd_source { SOURCE c; U64 off; U32 chunk_size; U32 chunk_count; U32 *raw_map; VHD_CHUNK **chunks;}VHD_SOURCE;/* * helper functions */static SOURCE *init_vhd_source(SECTION *section, int level, U64 total_size, U64 sparse_offset);static int read_block_vhd(SOURCE *s, U64 pos, void *buf);static void close_vhd(SOURCE *s);/* * cd image detection */void detect_vhd(SECTION *section, int level) { unsigned char *buf; int found, type; U64 sparse_offset, total_size; char s[256]; SOURCE *src; found = 0; /* check for info block at the beginning */ if (get_buffer(section, 0, 511, (void **)&buf) < 511) return; if (memcmp(buf, "conectix", 8) == 0) { found = 1; } /* check for info block at the end if possible */ if (!found && section->size > 1024 && !section->source->sequential) { if (get_buffer(section, section->size - 511, 511, (void **)&buf) < 511) return; if (memcmp(buf, "conectix", 8) == 0) { found = 1; } } if (!found) return; /* okay, now buf points to the info block, wherever it was found */ type = get_be_long(buf + 0x3c); total_size = get_be_quad(buf + 0x28); /* copy at 0x30 ... ??? */ if (type == 2) { print_line(level, "Connectix Virtual PC hard disk image, fixed size"); } else if (type == 3) { print_line(level, "Connectix Virtual PC hard disk image, dynamic size"); } else if (type == 4) { print_line(level, "Connectix Virtual PC hard disk image, differential"); } else { print_line(level, "Connectix Virtual PC hard disk image, unknown type %d", type); } format_size_verbose(s, total_size); print_line(level + 1, "Disk size %s", s); if (type == 3) { /* dynamically sized, set up a mapping data source */ sparse_offset = get_be_quad(buf + 16); src = init_vhd_source(section, level, total_size, sparse_offset); if (src != NULL) { /* analyze it */ analyze_source(src, level); close_source(src); } } if (type == 3 || type == 4) stop_detect();}/* * initialize the mapping source */static SOURCE *init_vhd_source(SECTION *section, int level, U64 total_size, U64 sparse_offset) { VHD_SOURCE *vs; unsigned char *buf; U64 map_offset; U32 map_size; char s[256]; /* allocate and init source structure */ vs = (VHD_SOURCE *)malloc(sizeof(VHD_SOURCE)); if (vs == NULL) bailout("Out of memory"); memset(vs, 0, sizeof(VHD_SOURCE)); vs->c.size_known = 1; vs->c.size = total_size; vs->c.blocksize = 512; vs->c.foundation = section->source; vs->c.read_block = read_block_vhd; vs->c.close = close_vhd; vs->off = section->pos; /* read sparse information block */ if (get_buffer(section, sparse_offset, 512, (void **)&buf) < 512) { print_line(level + 1, "Error reading the sparse image info block"); goto errorexit; } map_offset = get_be_quad(buf + 16); vs->chunk_count = get_be_long(buf + 28); vs->chunk_size = get_be_long(buf + 32); format_size(s, vs->chunk_size); print_line(level + 1, "Dynamic sizing uses %lu chunks of %s", vs->chunk_count, s); if ((U64)vs->chunk_count * vs->chunk_size < total_size) { print_line(level + 1, "Error: Sparse parameters don't match total size"); goto errorexit; } if (vs->chunk_size < 4096) { print_line(level + 1, "Error: Sparse chunk size too small (%lu bytes)", vs->chunk_size); goto errorexit; } if (vs->chunk_size > 2*1024*1024) { /* written-to bitmap wouldn't fit in one sector */ print_line(level + 1, "Error: Sparse chunk size too large (%lu bytes)", vs->chunk_size); goto errorexit; } /* allocate further data structures */ map_size = vs->chunk_count * 4; vs->raw_map = (U32 *)malloc(map_size); if (vs->raw_map == NULL) bailout("Out of memory"); vs->chunks = (VHD_CHUNK **)malloc(vs->chunk_count * sizeof(VHD_CHUNK *)); if (vs->chunks == NULL) bailout("Out of memory"); memset(vs->chunks, 0, vs->chunk_count * sizeof(VHD_CHUNK *)); /* read the chunk map */ if (get_buffer_real(section->source, vs->off + map_offset, map_size, (void *)vs->raw_map, NULL) < map_size) { print_line(level + 1, "Error reading the sparse image map"); goto errorexit; } return (SOURCE *)vs;errorexit: close_vhd((SOURCE *)vs); free(vs); return NULL;}/* * mapping read */static int read_block_vhd(SOURCE *s, U64 pos, void *buf) { VHD_SOURCE *vs = (VHD_SOURCE *)s; SOURCE *fs = s->foundation; U32 chunk, chunk_start_sector, sector; U64 chunk_disk_off, sector_pos; unsigned char *filebuf; int present; chunk = (U32)(pos / vs->chunk_size); if (chunk >= vs->chunk_count) return 0; if (vs->chunks[chunk] == NULL) { /* create data structure for the chunk */ chunk_start_sector = get_be_long(vs->raw_map + chunk); /* NOTE: raw_map is a U32*, so C does the arithmetics for us */ if (chunk_start_sector == 0xffffffff) { present = 0; } else { chunk_disk_off = vs->off + (U64)chunk_start_sector * 512; if (get_buffer_real(fs, chunk_disk_off, 512, NULL, (void **)&filebuf) < 512) present = 0; else present = 1; } if (!present) { vs->chunks[chunk] = (VHD_CHUNK *)malloc(sizeof(VHD_CHUNK)); if (vs->chunks[chunk] == NULL) bailout("Out of memory"); vs->chunks[chunk]->present = 0; } else { vs->chunks[chunk] = (VHD_CHUNK *)malloc(sizeof(VHD_CHUNK) + 512); if (vs->chunks[chunk] == NULL) bailout("Out of memory"); vs->chunks[chunk]->present = 1; vs->chunks[chunk]->off = chunk_disk_off + 512; memcpy(vs->chunks[chunk]->bitmap, filebuf, 512); } } if (!vs->chunks[chunk]->present) { /* whole chunk is missing */ memset(buf, 0, 512); return 1; } sector = (U32)((pos - (U64)chunk * vs->chunk_size) / 512); if (vs->chunks[chunk]->bitmap[sector >> 3] & (128 >> (sector & 7))) { /* sector is present and in use */ sector_pos = vs->chunks[chunk]->off + (U64)sector * 512; if (get_buffer_real(fs, sector_pos, 512, buf, NULL) < 512) return 0; } else { /* sector has not been written to (although it's present on disk) */ memset(buf, 0, 512); } return 1;}/* * cleanup */static void close_vhd(SOURCE *s) { VHD_SOURCE *vs = (VHD_SOURCE *)s; U32 chunk; /* free raw chunk map */ if (vs->raw_map != NULL) free(vs->raw_map); /* free chunk info data */ if (vs->chunks != NULL) { for (chunk = 0; chunk < vs->chunk_count; chunk++) { if (vs->chunks[chunk] != NULL) free(vs->chunks[chunk]); } free(vs->chunks); }}/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -