?? libvhd.c
字號:
return vhd_write_header_at(ctx, header, off);
}
int
vhd_write_bat(vhd_context_t *ctx, vhd_bat_t *bat)
{
int err;
off64_t off;
vhd_bat_t b;
size_t size;
if (!vhd_type_dynamic(ctx))
return -EINVAL;
err = vhd_validate_bat(&ctx->bat);
if (err)
return err;
err = vhd_validate_bat(bat);
if (err)
return err;
memset(&b, 0, sizeof(vhd_bat_t));
off = ctx->header.table_offset;
size = vhd_bytes_padded(bat->entries * sizeof(uint32_t));
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
return err;
err = posix_memalign((void **)&b.bat, VHD_SECTOR_SIZE, size);
if (err)
return -err;
memcpy(b.bat, bat->bat, size);
b.spb = bat->spb;
b.entries = bat->entries;
vhd_bat_out(&b);
err = vhd_write(ctx, b.bat, size);
free(b.bat);
return err;
}
int
vhd_write_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
{
int err;
off64_t off;
vhd_batmap_t b;
char *buf, *map;
size_t size, map_size;
buf = NULL;
map = NULL;
if (!vhd_has_batmap(ctx)) {
err = -EINVAL;
goto out;
}
b.header = batmap->header;
b.map = batmap->map;
b.header.checksum = vhd_checksum_batmap(&b);
err = vhd_validate_batmap(&b);
if (err)
goto out;
off = b.header.batmap_offset;
map_size = vhd_sectors_to_bytes(b.header.batmap_size);
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto out;
err = posix_memalign((void **)&map, VHD_SECTOR_SIZE, map_size);
if (err) {
map = NULL;
err = -err;
goto out;
}
memcpy(map, b.map, map_size);
err = vhd_write(ctx, map, map_size);
if (err)
goto out;
err = vhd_batmap_header_offset(ctx, &off);
if (err)
goto out;
size = vhd_bytes_padded(sizeof(vhd_batmap_header_t));
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
goto out;
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err) {
err = -err;
buf = NULL;
goto out;
}
vhd_batmap_header_out(&b);
memset(buf, 0, size);
memcpy(buf, &b.header, sizeof(vhd_batmap_header_t));
err = vhd_write(ctx, buf, size);
out:
if (err)
VHDLOG("%s: failed writing batmap: %d\n", ctx->file, err);
free(buf);
free(map);
return 0;
}
int
vhd_write_bitmap(vhd_context_t *ctx, uint32_t block, char *bitmap)
{
int err;
off64_t off;
uint64_t blk;
size_t secs, size;
if (!vhd_type_dynamic(ctx))
return -EINVAL;
err = vhd_validate_bat(&ctx->bat);
if (err)
return err;
if (block >= ctx->bat.entries)
return -ERANGE;
if ((unsigned long)bitmap & (VHD_SECTOR_SIZE - 1))
return -EINVAL;
blk = ctx->bat.bat[block];
if (blk == DD_BLK_UNUSED)
return -EINVAL;
off = vhd_sectors_to_bytes(blk);
size = vhd_sectors_to_bytes(ctx->bm_secs);
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
return err;
err = vhd_write(ctx, bitmap, size);
if (err)
return err;
return 0;
}
int
vhd_write_block(vhd_context_t *ctx, uint32_t block, char *data)
{
int err;
off64_t off;
size_t size;
uint64_t blk;
if (!vhd_type_dynamic(ctx))
return -EINVAL;
err = vhd_validate_bat(&ctx->bat);
if (err)
return err;
if (block >= ctx->bat.entries)
return -ERANGE;
if ((unsigned long)data & ~(VHD_SECTOR_SIZE -1))
return -EINVAL;
blk = ctx->bat.bat[block];
if (blk == DD_BLK_UNUSED)
return -EINVAL;
off = vhd_sectors_to_bytes(blk + ctx->bm_secs);
size = vhd_sectors_to_bytes(ctx->spb);
err = vhd_seek(ctx, off, SEEK_SET);
if (err)
return err;
err = vhd_write(ctx, data, size);
if (err)
return err;
return 0;
}
static inline int
namedup(char **dup, const char *name)
{
*dup = NULL;
if (strnlen(name, MAX_NAME_LEN) >= MAX_NAME_LEN)
return -ENAMETOOLONG;
*dup = strdup(name);
if (*dup == NULL)
return -ENOMEM;
return 0;
}
int
vhd_seek(vhd_context_t *ctx, off64_t offset, int whence)
{
off64_t off;
off = lseek64(ctx->fd, offset, whence);
if (off == (off64_t)-1) {
VHDLOG("%s: seek(0x%08"PRIx64", %d) failed: %d\n",
ctx->file, offset, whence, -errno);
return -errno;
}
return 0;
}
off64_t
vhd_position(vhd_context_t *ctx)
{
return lseek64(ctx->fd, 0, SEEK_CUR);
}
int
vhd_read(vhd_context_t *ctx, void *buf, size_t size)
{
size_t ret;
errno = 0;
ret = read(ctx->fd, buf, size);
if (ret == size)
return 0;
VHDLOG("%s: read of %zu returned %zd, errno: %d\n",
ctx->file, size, ret, -errno);
return (errno ? -errno : -EIO);
}
int
vhd_write(vhd_context_t *ctx, void *buf, size_t size)
{
size_t ret;
errno = 0;
ret = write(ctx->fd, buf, size);
if (ret == size)
return 0;
VHDLOG("%s: write of %zu returned %zd, errno: %d\n",
ctx->file, size, ret, -errno);
return (errno ? -errno : -EIO);
}
int
vhd_offset(vhd_context_t *ctx, uint32_t sector, uint32_t *offset)
{
int err;
uint32_t block;
if (!vhd_type_dynamic(ctx))
return sector;
err = vhd_get_bat(ctx);
if (err)
return err;
block = sector / ctx->spb;
if (ctx->bat.bat[block] == DD_BLK_UNUSED)
*offset = DD_BLK_UNUSED;
else
*offset = ctx->bat.bat[block] +
ctx->bm_secs + (sector % ctx->spb);
return 0;
}
int
vhd_open_fast(vhd_context_t *ctx)
{
int err;
char *buf;
size_t size;
size = sizeof(vhd_footer_t) + sizeof(vhd_header_t);
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
if (err) {
VHDLOG("failed allocating %s: %d\n", ctx->file, -err);
return -err;
}
err = vhd_read(ctx, buf, size);
if (err) {
VHDLOG("failed reading %s: %d\n", ctx->file, err);
goto out;
}
memcpy(&ctx->footer, buf, sizeof(vhd_footer_t));
vhd_footer_in(&ctx->footer);
err = vhd_validate_footer(&ctx->footer);
if (err)
goto out;
if (vhd_type_dynamic(ctx)) {
if (ctx->footer.data_offset != sizeof(vhd_footer_t))
err = vhd_read_header(ctx, &ctx->header);
else {
memcpy(&ctx->header,
buf + sizeof(vhd_footer_t),
sizeof(vhd_header_t));
vhd_header_in(&ctx->header);
err = vhd_validate_header(&ctx->header);
}
if (err)
goto out;
ctx->spb = ctx->header.block_size >> VHD_SECTOR_SHIFT;
ctx->bm_secs = secs_round_up_no_zero(ctx->spb >> 3);
}
out:
free(buf);
return err;
}
int
vhd_open(vhd_context_t *ctx, const char *file, int flags)
{
int err, oflags;
if (flags & VHD_OPEN_STRICT)
vhd_flag_clear(flags, VHD_OPEN_FAST);
memset(ctx, 0, sizeof(vhd_context_t));
ctx->fd = -1;
ctx->oflags = flags;
err = namedup(&ctx->file, file);
if (err)
return err;
oflags = O_DIRECT | O_LARGEFILE;
if (flags & VHD_OPEN_RDONLY)
oflags |= O_RDONLY;
if (flags & VHD_OPEN_RDWR)
oflags |= O_RDWR;
ctx->fd = open(ctx->file, oflags, 0644);
if (ctx->fd == -1) {
err = -errno;
VHDLOG("failed to open %s: %d\n", ctx->file, err);
goto fail;
}
err = vhd_test_file_fixed(ctx->file, &ctx->is_block);
if (err)
goto fail;
if (flags & VHD_OPEN_FAST) {
err = vhd_open_fast(ctx);
if (err)
goto fail;
return 0;
}
err = vhd_read_footer(ctx, &ctx->footer);
if (err)
goto fail;
if (!(flags & VHD_OPEN_IGNORE_DISABLED) && vhd_disabled(ctx)) {
err = -EINVAL;
goto fail;
}
if (vhd_type_dynamic(ctx)) {
err = vhd_read_header(ctx, &ctx->header);
if (err)
goto fail;
ctx->spb = ctx->header.block_size >> VHD_SECTOR_SHIFT;
ctx->bm_secs = secs_round_up_no_zero(ctx->spb >> 3);
}
return 0;
fail:
if (ctx->fd != -1)
close(ctx->fd);
free(ctx->file);
memset(ctx, 0, sizeof(vhd_context_t));
return err;
}
void
vhd_close(vhd_context_t *ctx)
{
if (ctx->file)
close(ctx->fd);
free(ctx->file);
free(ctx->bat.bat);
free(ctx->batmap.map);
memset(ctx, 0, sizeof(vhd_context_t));
}
static inline void
vhd_initialize_footer(vhd_context_t *ctx, int type, uint64_t size)
{
memset(&ctx->footer, 0, sizeof(vhd_footer_t));
memcpy(ctx->footer.cookie, HD_COOKIE, sizeof(ctx->footer.cookie));
ctx->footer.features = HD_RESERVED;
ctx->footer.ff_version = HD_FF_VERSION;
ctx->footer.timestamp = vhd_time(time(NULL));
ctx->footer.crtr_ver = VHD_CURRENT_VERSION;
ctx->footer.crtr_os = 0x00000000;
ctx->footer.orig_size = size;
ctx->footer.curr_size = size;
ctx->footer.geometry = vhd_chs(size);
ctx->footer.type = type;
ctx->footer.saved = 0;
ctx->footer.data_offset = 0xFFFFFFFFFFFFFFFF;
strcpy(ctx->footer.crtr_app, "tap");
uuid_generate(ctx->footer.uuid);
}
static int
vhd_initialize_header_parent_name(vhd_context_t *ctx, const char *parent_path)
{
int err;
iconv_t cd;
size_t ibl, obl;
char *pname, *ppath, *dst;
err = 0;
pname = NULL;
ppath = NULL;
/*
* MICROSOFT_COMPAT
* big endian unicode here
*/
cd = iconv_open(UTF_16BE, "ASCII");
if (cd == (iconv_t)-1) {
err = -errno;
goto out;
}
ppath = strdup(parent_path);
if (!ppath) {
err = -ENOMEM;
goto out;
}
pname = basename(ppath);
if (!strcmp(pname, "")) {
err = -EINVAL;
goto out;
}
ibl = strlen(pname);
obl = sizeof(ctx->header.prt_name);
dst = ctx->header.prt_name;
memset(dst, 0, obl);
if (iconv(cd, &pname, &ibl, &dst, &obl) == (size_t)-1 || ibl)
err = (errno ? -errno : -EINVAL);
out:
iconv_close(cd);
free(ppath);
return err;
}
static off64_t
get_file_size(const char *name)
{
int fd;
off64_t end;
fd = open(name, O_LARGEFILE | O_RDONLY);
if (fd == -1) {
VHDLOG("unable to open '%s': %d\n", name, errno);
return -errno;
}
end = lseek64(fd, 0, SEEK_END);
close(fd);
return end;
}
static int
vhd_initialize_header(vhd_context_t *ctx, const char *parent_path,
uint64_t size, int raw)
{
int err;
struct stat stats;
vhd_context_t parent;
if (!vhd_type_dynamic(ctx))
return -EINVAL;
memset(&ctx->header, 0, sizeof(vhd_header_t));
memcpy(ctx->header.cookie, DD_COOKIE, sizeof(ctx->header.cookie));
ctx->header.data_offset = (uint64_t)-1;
ctx->header.table_offset = VHD_SECTOR_SIZE * 3; /* 1 ftr + 2 hdr */
ctx->header.hdr_ver = DD_VERSION;
ctx->header.block_size = VHD_BLOCK_SIZE;
ctx->header.prt_ts = 0;
ctx->header.res1 = 0;
ctx->header.max_bat_size = (ctx->footer.curr_size +
VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
ctx->footer.data_offset = VHD_SECTOR_SIZE;
if (ctx->footer.type == HD_TYPE_DYNAMIC)
return 0;
err = stat(parent_path, &stats);
if (err == -1)
return -errno;
if (raw) {
ctx->header.prt_ts = vhd_time(stats.st_mtime);
if (!size)
size = get_file_size(parent_path);
}
else {
err = vhd_open(&parent, parent_path, VHD_OPEN_RDONLY);
if (err)
return err;
ctx->header.prt_ts = vhd_time(stats.st_mtime);
uuid_copy(ctx->header.prt_uuid, parent.footer.uuid);
if (!size)
size = parent.footer.curr_size;
vhd_close(&parent);
}
ctx->footer.orig_size = size;
ctx->footer.curr_size = size;
ctx->footer.geometry = vhd_chs(size);
ctx->header.max_bat_size =
(size + VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
return vhd_initialize_header_parent_name(ctx, parent_path);
}
static int
vhd_write_parent_locators(vhd_context_t *ctx, const char *parent)
{
int i, err;
off64_t off;
uint32_t code;
code = PLAT_CODE_NONE;
if (ctx->footer.type != HD_TYPE_DIFF)
return -EINVAL;
off = ctx->batmap.header.batmap_offset +
vhd_sectors_to_bytes(ctx->batmap.header.batmap_size);
if (off & (VHD_SECTOR_SIZE - 1))
off = vhd_bytes_padded(off);
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
code = PLAT_CODE_MACX;
break;
case 1:
code = PLAT_CODE_W2KU;
break;
case 2:
code = PLAT_CODE_W2RU;
break;
}
err = vhd_parent_locator_write_at(ctx, parent, off, code,
0, ctx->header.loc + i);
if (err)
return err;
off += vhd_parent_locator_size(ctx->header.loc + i);
}
return 0;
}
int
vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
{
int i, err;
char *ppath;
struct stat stats;
vhd_context_t parent;
ppath = realpath(parent_path, NULL);
if (!ppath) {
VHDLOG("error resolving parent path %s for %s: %d\n",
parent_path, child->file, errno);
return -errno;
}
err = stat(ppath, &stats);
if (err == -1) {
err = -errno;
goto out;
}
if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
err = -EINVAL;
goto out;
}
if (raw) {
uuid_clear(child->header.prt_uuid);
} else {
err = vhd_open(&parent, ppath, VHD_OPEN_RDONLY);
if (err) {
VHDLOG("error opening parent %s for %s: %d\n",
ppath, child->file, err);
goto out;
}
uuid_copy(child->header.prt_uuid, parent.footer.uuid);
vhd_close(&parent);
}
vhd_initialize_header_parent_name(child, ppath);
child->header.prt_ts = vhd_time(stats.st_mtime);
for (i = 0; i < vhd_parent_locator_count(child); i++) {
vhd_parent_locator_t *loc = child->header.loc + i;
size_t max = vhd_parent_locator_size(loc);
switch (loc->code) {
case PLAT_CODE_MACX:
case PLAT_CODE_W2KU:
case PLAT_CODE_W2RU:
break;
default:
continue;
}
err = vhd_parent_locator_write_at(child, ppath,
loc->data_offset,
loc->code, max, loc);
if (err) {
VHDLOG("error writing parent locator %d for %s: %d\n",
i, child->file, err);
goto out;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -