?? libvhd.c
字號:
return -errno;
*end = max - sizeof(vhd_footer_t);
return 0;
}
err = vhd_end_of_headers(ctx, &max);
if (err)
return err;
err = vhd_get_bat(ctx);
if (err)
return err;
max >>= VHD_SECTOR_SHIFT;
for (i = 0; i < ctx->bat.entries; i++) {
blk = ctx->bat.bat[i];
if (blk != DD_BLK_UNUSED) {
blk += ctx->spb + ctx->bm_secs;
max = MAX(blk, max);
}
}
*end = vhd_sectors_to_bytes(max);
return 0;
}
uint32_t
vhd_time(time_t time)
{
struct tm tm;
time_t micro_epoch;
memset(&tm, 0, sizeof(struct tm));
tm.tm_year = 100;
tm.tm_mon = 0;
tm.tm_mday = 1;
micro_epoch = mktime(&tm);
return (uint32_t)(time - micro_epoch);
}
/*
* Stringify the VHD timestamp for printing.
* As with ctime_r, target must be >=26 bytes.
*/
size_t
vhd_time_to_string(uint32_t timestamp, char *target)
{
char *cr;
struct tm tm;
time_t t1, t2;
memset(&tm, 0, sizeof(struct tm));
/* VHD uses an epoch of 12:00AM, Jan 1, 2000. */
/* Need to adjust this to the expected epoch of 1970. */
tm.tm_year = 100;
tm.tm_mon = 0;
tm.tm_mday = 1;
t1 = mktime(&tm);
t2 = t1 + (time_t)timestamp;
ctime_r(&t2, target);
/* handle mad ctime_r newline appending. */
if ((cr = strchr(target, '\n')) != NULL)
*cr = '\0';
return (strlen(target));
}
/*
* nabbed from vhd specs.
*/
uint32_t
vhd_chs(uint64_t size)
{
uint32_t secs, cylinders, heads, spt, cth;
secs = secs_round_up_no_zero(size);
if (secs > 65535 * 16 * 255)
secs = 65535 * 16 * 255;
if (secs >= 65535 * 16 * 63) {
spt = 255;
cth = secs / spt;
heads = 16;
} else {
spt = 17;
cth = secs / spt;
heads = (cth + 1023) / 1024;
if (heads < 4)
heads = 4;
if (cth >= (heads * 1024) || heads > 16) {
spt = 31;
cth = secs / spt;
heads = 16;
}
if (cth >= heads * 1024) {
spt = 63;
cth = secs / spt;
heads = 16;
}
}
cylinders = cth / heads;
return GEOM_ENCODE(cylinders, heads, spt);
}
int
vhd_get_footer(vhd_context_t *ctx)
{
if (!vhd_validate_footer(&ctx->footer))
return 0;
return vhd_read_footer(ctx, &ctx->footer);
}
int
vhd_get_header(vhd_context_t *ctx)
{
if (!vhd_type_dynamic(ctx))
return -EINVAL;
if (!vhd_validate_header(&ctx->header))
return 0;
return vhd_read_header(ctx, &ctx->header);
}
int
vhd_get_bat(vhd_context_t *ctx)
{
if (!vhd_type_dynamic(ctx))
return -EINVAL;
if (!vhd_validate_bat(&ctx->bat))
return 0;
vhd_put_bat(ctx);
return vhd_read_bat(ctx, &ctx->bat);
}
int
vhd_get_batmap(vhd_context_t *ctx)
{
if (!vhd_has_batmap(ctx))
return -EINVAL;
if (!vhd_validate_batmap(&ctx->batmap))
return 0;
vhd_put_batmap(ctx);
return vhd_read_batmap(ctx, &ctx->batmap);
}
void
vhd_put_footer(vhd_context_t *ctx)
{
memset(&ctx->footer, 0, sizeof(vhd_footer_t));
}
void
vhd_put_header(vhd_context_t *ctx)
{
memset(&ctx->header, 0, sizeof(vhd_header_t));
}
void
vhd_put_bat(vhd_context_t *ctx)
{
if (!vhd_type_dynamic(ctx))
return;
free(ctx->bat.bat);
memset(&ctx->bat, 0, sizeof(vhd_bat_t));
}
void
vhd_put_batmap(vhd_context_t *ctx)
{
if (!vhd_type_dynamic(ctx))
return;
if (!vhd_has_batmap(ctx))
return;
free(ctx->batmap.map);
memset(&ctx->batmap, 0, sizeof(vhd_batmap_t));
}
/*
* look for 511 byte footer at end of file
*/
int
vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer)
{
int err;
char *buf;
off64_t eof;
buf = NULL;
err = vhd_seek(ctx, 0, SEEK_END);
if (err)
goto out;
eof = vhd_position(ctx);
if (eof == (off64_t)-1) {
err = -errno;
goto out;
}
err = vhd_seek(ctx, eof - 511, SEEK_SET);
if (err)
goto out;
err = posix_memalign((void **)&buf,
VHD_SECTOR_SIZE, sizeof(vhd_footer_t));
if (err) {
buf = NULL;
err = -err;
goto out;
}
memset(buf, 0, sizeof(vhd_footer_t));
/*
* expecting short read here
*/
vhd_read(ctx, buf, sizeof(vhd_footer_t));
memcpy(footer, buf, sizeof(vhd_footer_t));
vhd_footer_in(footer);
err = vhd_validate_footer(footer);
out:
if (err)
VHDLOG("%s: failed reading short footer: %d\n",
ctx->file, err);
free(buf);
return err;
}
int
vhd_read_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off)
{
int err;
char *buf;
buf = NULL;
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto out;
err = posix_memalign((void **)&buf,
VHD_SECTOR_SIZE, sizeof(vhd_footer_t));
if (err) {
buf = NULL;
err = -err;
goto out;
}
err = vhd_read(ctx, buf, sizeof(vhd_footer_t));
if (err)
goto out;
memcpy(footer, buf, sizeof(vhd_footer_t));
vhd_footer_in(footer);
err = vhd_validate_footer(footer);
out:
if (err)
VHDLOG("%s: reading footer at 0x%08"PRIx64" failed: %d\n",
ctx->file, off, err);
free(buf);
return err;
}
int
vhd_read_footer(vhd_context_t *ctx, vhd_footer_t *footer)
{
int err;
off64_t off;
err = vhd_seek(ctx, 0, SEEK_END);
if (err)
return err;
off = vhd_position(ctx);
if (off == (off64_t)-1)
return -errno;
err = vhd_read_footer_at(ctx, footer, off - 512);
if (err != -EINVAL)
return err;
err = vhd_read_short_footer(ctx, footer);
if (err != -EINVAL)
return err;
if (ctx->oflags & VHD_OPEN_STRICT)
return -EINVAL;
return vhd_read_footer_at(ctx, footer, 0);
}
int
vhd_read_header_at(vhd_context_t *ctx, vhd_header_t *header, off64_t off)
{
int err;
char *buf;
buf = NULL;
if (!vhd_type_dynamic(ctx)) {
err = -EINVAL;
goto out;
}
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto out;
err = posix_memalign((void **)&buf,
VHD_SECTOR_SIZE, sizeof(vhd_header_t));
if (err) {
buf = NULL;
err = -err;
goto out;
}
err = vhd_read(ctx, buf, sizeof(vhd_header_t));
if (err)
goto out;
memcpy(header, buf, sizeof(vhd_header_t));
vhd_header_in(header);
err = vhd_validate_header(header);
out:
if (err)
VHDLOG("%s: reading header at 0x%08"PRIx64" failed: %d\n",
ctx->file, off, err);
free(buf);
return err;
}
int
vhd_read_header(vhd_context_t *ctx, vhd_header_t *header)
{
int err;
off64_t off;
if (!vhd_type_dynamic(ctx)) {
VHDLOG("%s is not dynamic!\n", ctx->file);
return -EINVAL;
}
off = ctx->footer.data_offset;
return vhd_read_header_at(ctx, header, off);
}
int
vhd_read_bat(vhd_context_t *ctx, vhd_bat_t *bat)
{
int err;
char *buf;
off64_t off;
size_t size;
buf = NULL;
if (!vhd_type_dynamic(ctx)) {
err = -EINVAL;
goto fail;
}
off = ctx->header.table_offset;
size = vhd_bytes_padded(ctx->header.max_bat_size * sizeof(uint32_t));
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err) {
buf = NULL;
err = -err;
goto fail;
}
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto fail;
err = vhd_read(ctx, buf, size);
if (err)
goto fail;
bat->spb = ctx->header.block_size >> VHD_SECTOR_SHIFT;
bat->entries = ctx->header.max_bat_size;
bat->bat = (uint32_t *)buf;
vhd_bat_in(bat);
return 0;
fail:
free(buf);
memset(bat, 0, sizeof(vhd_bat_t));
VHDLOG("%s: failed to read bat: %d\n", ctx->file, err);
return err;
}
static int
vhd_read_batmap_header(vhd_context_t *ctx, vhd_batmap_t *batmap)
{
int err;
char *buf;
off64_t off;
size_t size;
buf = NULL;
err = vhd_batmap_header_offset(ctx, &off);
if (err)
goto fail;
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto fail;
size = vhd_bytes_padded(sizeof(vhd_batmap_header_t));
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err) {
buf = NULL;
err = -err;
goto fail;
}
err = vhd_read(ctx, buf, size);
if (err)
goto fail;
memcpy(&batmap->header, buf, sizeof(vhd_batmap_header_t));
free(buf);
buf = NULL;
vhd_batmap_header_in(batmap);
return 0;
fail:
free(buf);
memset(&batmap->header, 0, sizeof(vhd_batmap_header_t));
VHDLOG("%s: failed to read batmap header: %d\n", ctx->file, err);
return err;
}
static int
vhd_read_batmap_map(vhd_context_t *ctx, vhd_batmap_t *batmap)
{
int err;
char *buf;
off64_t off;
size_t map_size;
map_size = vhd_sectors_to_bytes(batmap->header.batmap_size);
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, map_size);
if (err) {
buf = NULL;
err = -err;
goto fail;
}
off = batmap->header.batmap_offset;
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto fail;
err = vhd_read(ctx, buf, map_size);
if (err)
goto fail;
batmap->map = buf;
return 0;
fail:
free(buf);
batmap->map = NULL;
VHDLOG("%s: failed to read batmap: %d\n", ctx->file, err);
return err;
}
int
vhd_read_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
{
int err;
if (!vhd_has_batmap(ctx))
return -EINVAL;
memset(batmap, 0, sizeof(vhd_batmap_t));
err = vhd_read_batmap_header(ctx, batmap);
if (err)
return err;
err = vhd_validate_batmap_header(batmap);
if (err)
return err;
err = vhd_read_batmap_map(ctx, batmap);
if (err)
return err;
err = vhd_validate_batmap(batmap);
if (err)
goto fail;
return 0;
fail:
free(batmap->map);
memset(batmap, 0, sizeof(vhd_batmap_t));
return err;
}
int
vhd_has_batmap(vhd_context_t *ctx)
{
if (!vhd_type_dynamic(ctx))
return 0;
if (!vhd_creator_tapdisk(ctx))
return 0;
if (ctx->footer.crtr_ver <= VHD_VERSION(0, 1))
return 0;
if (ctx->footer.crtr_ver >= VHD_VERSION(1, 2))
return 1;
/*
* VHDs of version 1.1 probably have a batmap, but may not
* if they were updated from version 0.1 via vhd-update.
*/
if (!vhd_validate_batmap_header(&ctx->batmap))
return 1;
if (vhd_read_batmap_header(ctx, &ctx->batmap))
return 0;
return (!vhd_validate_batmap_header(&ctx->batmap));
}
/*
* Is this a block device (with a fixed size)? This affects whether the file
* can be truncated and where the footer is written for VHDs.
*/
int
vhd_test_file_fixed(const char *file, int *is_block)
{
int err;
struct stat stats;
err = stat(file, &stats);
if (err == -1)
return -errno;
*is_block = !!(S_ISBLK(stats.st_mode));
return err;
}
int
vhd_find_parent(vhd_context_t *ctx, const char *parent, char **_location)
{
int err;
char *location, *cpath, *cdir, *path;
err = 0;
path = NULL;
cpath = NULL;
location = NULL;
*_location = NULL;
if (!parent)
return -EINVAL;
if (parent[0] == '/') {
if (!access(parent, R_OK)) {
path = strdup(parent);
if (!path)
return -ENOMEM;
*_location = path;
return 0;
}
}
/* check parent path relative to child's directory */
cpath = realpath(ctx->file, NULL);
if (!cpath) {
err = -errno;
goto out;
}
cdir = dirname(cpath);
if (asprintf(&location, "%s/%s", cdir, parent) == -1) {
err = -errno;
location = NULL;
goto out;
}
if (!access(location, R_OK)) {
path = realpath(location, NULL);
if (path) {
*_location = path;
return 0;
}
}
err = -errno;
out:
free(location);
free(cpath);
return err;
}
static int
vhd_macx_encode_location(char *name, char **out, int *outlen)
{
iconv_t cd;
int len, err;
size_t ibl, obl;
char *uri, *urip, *uri_utf8, *uri_utf8p, *ret;
err = 0;
ret = NULL;
*out = NULL;
*outlen = 0;
len = strlen(name) + strlen("file://");
ibl = len;
obl = len;
uri = urip = malloc(ibl + 1);
uri_utf8 = uri_utf8p = malloc(obl);
if (!uri || !uri_utf8)
return -ENOMEM;
cd = iconv_open("UTF-8", "ASCII");
if (cd == (iconv_t)-1) {
err = -errno;
goto out;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -