static int vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw) { int i, err; char *target; vhd_context_t vhd; *parent_raw = 0; *result = NULL; target = strdup(name); if (!target) return -ENOMEM; for (;;) { err = vhd_open(&vhd, target, VHD_OPEN_RDONLY); if (err) { free(target); return err; } if (vhd.footer.type != HD_TYPE_DIFF) goto out; err = vhd_get_bat(&vhd); if (err) goto out; for (i = 0; i < vhd.bat.entries; i++) if (vhd.bat.bat[i] != DD_BLK_UNUSED) goto out; free(target); err = vhd_parent_locator_get(&vhd, &target); if (err) goto out; if (vhd_parent_raw(&vhd)) { *parent_raw = 1; goto out; } vhd_close(&vhd); } out: vhd_close(&vhd); if (err) free(target); else *result = target; return err; }
int vhd_util_read(int argc, char **argv) { char *name; vhd_context_t vhd; int c, err, headers, hex, bat_str, cache, flags; uint64_t bat, bitmap, tbitmap, ebitmap, batmap, tbatmap, data, lsec, count, read; uint64_t bread; err = 0; hex = 0; cache = 0; headers = 0; bat_str = 0; count = 1; bat = -1; bitmap = -1; tbitmap = -1; ebitmap = -1; batmap = -1; tbatmap = -1; data = -1; lsec = -1; read = -1; bread = -1; name = NULL; if (!argc || !argv) goto usage; optind = 0; while ((c = getopt(argc, argv, "n:pt:b:Bm:i:e:aj:d:c:r:R:xCh")) != -1) { switch(c) { case 'n': name = optarg; break; case 'p': headers = 1; break; case 'C': cache = 1; break; case 'B': bat_str = 1; break; case 't': lsec = strtoul(optarg, NULL, 10); break; case 'b': bat = strtoull(optarg, NULL, 10); break; case 'm': bitmap = strtoull(optarg, NULL, 10); break; case 'i': tbitmap = strtoul(optarg, NULL, 10); break; case 'e': ebitmap = strtoul(optarg, NULL, 10); break; case 'a': batmap = 1; break; case 'j': tbatmap = strtoull(optarg, NULL, 10); break; case 'd': data = strtoull(optarg, NULL, 10); break; case 'r': read = strtoull(optarg, NULL, 10); break; case 'R': bread = strtoull(optarg, NULL, 10); break; case 'c': count = strtoul(optarg, NULL, 10); break; case 'x': hex = 1; break; case 'h': default: goto usage; } } if (!name || optind != argc) goto usage; flags = VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED; if (cache) flags |= VHD_OPEN_CACHED | VHD_OPEN_FAST; err = vhd_open(&vhd, name, flags); if (err) { printf("Failed to open %s: %d\n", name, err); vhd_dump_headers(name, hex); return err; } err = vhd_get_bat(&vhd); if (err) { printf("Failed to get bat for %s: %d\n", name, err); goto out; } if (headers) vhd_print_headers(&vhd, hex); if (lsec != -1) { err = vhd_print_logical_to_physical(&vhd, lsec, count, hex); if (err) goto out; } if (bat != -1) { err = vhd_print_bat(&vhd, bat, count, hex); if (err) goto out; } if (bat_str) { err = vhd_print_bat_str(&vhd); if (err) goto out; } if (bitmap != -1) { err = vhd_print_bitmap(&vhd, bitmap, count, hex); if (err) goto out; } if (tbitmap != -1) { err = vhd_test_bitmap(&vhd, tbitmap, count, hex); if (err) goto out; } if (ebitmap != -1) { err = vhd_print_bitmap_extents(&vhd, ebitmap, count, hex); if (err) goto out; } if (batmap != -1) { err = vhd_print_batmap(&vhd); if (err) goto out; } if (tbatmap != -1) { err = vhd_test_batmap(&vhd, tbatmap, count, hex); if (err) goto out; } if (data != -1) { err = vhd_print_data(&vhd, data, count, hex); if (err) goto out; } if (read != -1) { err = vhd_read_data(&vhd, read, count, hex); if (err) goto out; } if (bread != -1) { err = vhd_read_bytes(&vhd, bread, count, hex); if (err) goto out; } err = 0; out: vhd_close(&vhd); return err; usage: printf("options:\n" "-h help\n" "-n name\n" "-p print VHD headers\n" "-t sec translate logical sector to VHD location\n" "-b blk print bat entry\n" "-B print entire bat as a bitmap\n" "-m blk print bitmap\n" "-i sec test bitmap for logical sector\n" "-e sec output extent list of allocated logical sectors\n" "-a print batmap\n" "-j blk test batmap for block\n" "-d blk print data\n" "-c num num units\n" "-r sec read num sectors at sec\n" "-R byte read num bytes at byte\n" "-x print in hex\n"); return EINVAL; }
int vhd_util_fill(int argc, char **argv) { int err, c; char *name; void *buf; vhd_context_t vhd; uint64_t i, sec, secs, from_sector, to_sector; int init_bat; bool ignore_2tb_limit; buf = NULL; name = NULL; init_bat = 0; from_sector = ULLONG_MAX; to_sector = ULLONG_MAX; ignore_2tb_limit = false; if (!argc || !argv) goto usage; optind = 0; while ((c = getopt(argc, argv, "n:f:t:bBh")) != -1) { switch (c) { case 'n': name = optarg; break; case 'f': from_sector = strtoull(optarg, NULL, 10); break; case 't': to_sector = strtoull(optarg, NULL, 10); break; case 'b': init_bat = 1; break; case 'B': ignore_2tb_limit = true; break; case 'h': default: goto usage; } } if (!name || optind != argc) goto usage; if ((from_sector != ULLONG_MAX || to_sector != ULLONG_MAX) && !init_bat) { printf("-f/-t can only be used with -b\n"); goto usage; } if (from_sector != ULLONG_MAX && to_sector != ULLONG_MAX) { if (to_sector < from_sector) { printf("invalid sector range %llu-%llu\n", (unsigned long long)from_sector, (unsigned long long)to_sector); goto usage; } } if (ignore_2tb_limit && !init_bat) { printf("-B can only be used with -b\n"); goto usage; } err = vhd_open(&vhd, name, VHD_OPEN_RDWR); if (err) { printf("error opening %s: %d\n", name, err); return err; } err = vhd_get_bat(&vhd); if (err) goto done; if (init_bat) { uint32_t from_extent; uint32_t to_extent; if (from_sector != ULLONG_MAX) from_extent = from_sector / vhd.spb; else from_extent = 0; if (to_sector != ULLONG_MAX) to_extent = to_sector / vhd.spb; else to_extent = vhd.bat.entries - 1; err = vhd_io_allocate_blocks_fast(&vhd, from_extent, to_extent, ignore_2tb_limit); if (err) goto done; } else { err = posix_memalign(&buf, 4096, vhd.header.block_size); if (err) { err = -err; goto done; } sec = 0; secs = vhd.header.block_size >> VHD_SECTOR_SHIFT; for (i = 0; i < vhd.header.max_bat_size; i++) { err = vhd_io_read(&vhd, buf, sec, secs); if (err) goto done; err = vhd_io_write(&vhd, buf, sec, secs); if (err) goto done; sec += secs; } err = 0; } done: free(buf); vhd_close(&vhd); return err; usage: printf("options: <-n name> [-h help] [-b initialise the BAT and bitmaps, " "don't write to the data blocks (much faster)] [-f start " "intialisation from this sector, only usable with -b] [-t " "intialise up to this sector (inclusive), only usable with -b] " "[-B ignore the 2 TB limit, only usable with -b]\n"); return -EINVAL; }
int vhd_journal_add_block(vhd_journal_t *j, uint32_t block, char mode) { int err; char *buf; off64_t off; size_t size; uint64_t blk; vhd_context_t *vhd; buf = NULL; vhd = &j->vhd; if (!vhd_type_dynamic(vhd)) return -EINVAL; err = vhd_get_bat(vhd); if (err) return err; if (block >= vhd->bat.entries) return -ERANGE; blk = vhd->bat.bat[block]; if (blk == DD_BLK_UNUSED) return 0; off = vhd_sectors_to_bytes(blk); if (mode & VHD_JOURNAL_METADATA) { size = vhd_sectors_to_bytes(vhd->bm_secs); err = vhd_read_bitmap(vhd, block, &buf); if (err) return err; err = vhd_journal_update(j, off, buf, size, VHD_JOURNAL_ENTRY_TYPE_DATA); free(buf); if (err) return err; } if (mode & VHD_JOURNAL_DATA) { off += vhd_sectors_to_bytes(vhd->bm_secs); size = vhd_sectors_to_bytes(vhd->spb); err = vhd_read_block(vhd, block, &buf); if (err) return err; err = vhd_journal_update(j, off, buf, size, VHD_JOURNAL_ENTRY_TYPE_DATA); free(buf); if (err) return err; } return vhd_journal_sync(j); }
int vhd_journal_create(vhd_journal_t *j, const char *file, const char *jfile) { int err; memset(j, 0, sizeof(vhd_journal_t)); j->jfd = -1; j->jname = strdup(jfile); if (j->jname == NULL) { err = -ENOMEM; goto fail1; } if (access(j->jname, F_OK) == 0) { err = vhd_test_file_fixed(j->jname, &j->is_block); if (err) goto fail1; if (!j->is_block) { err = -EEXIST; goto fail1; } } if (j->is_block) j->jfd = open(j->jname, O_LARGEFILE | O_RDWR, 0644); else j->jfd = open(j->jname, O_CREAT | O_TRUNC | O_LARGEFILE | O_RDWR, 0644); if (j->jfd == -1) { err = -errno; goto fail1; } err = vhd_open(&j->vhd, file, VHD_OPEN_RDWR | VHD_OPEN_STRICT); if (err) goto fail1; err = vhd_get_bat(&j->vhd); if (err) goto fail2; if (vhd_has_batmap(&j->vhd)) { err = vhd_get_batmap(&j->vhd); if (err) goto fail2; } err = vhd_journal_add_journal_header(j); if (err) goto fail2; err = vhd_journal_add_metadata(j); if (err) goto fail2; err = vhd_journal_disable_vhd(j); if (err) goto fail2; err = vhd_journal_sync(j); if (err) goto fail2; return 0; fail1: if (j->jfd != -1) { close(j->jfd); if (!j->is_block) unlink(j->jname); } free(j->jname); memset(j, 0, sizeof(vhd_journal_t)); return err; fail2: vhd_journal_remove(j); return err; }
int vhd_journal_open(vhd_journal_t *j, const char *file, const char *jfile) { int err; vhd_context_t *vhd; memset(j, 0, sizeof(vhd_journal_t)); j->jfd = -1; vhd = &j->vhd; j->jname = strdup(jfile); if (j->jname == NULL) return -ENOMEM; j->jfd = open(j->jname, O_LARGEFILE | O_RDWR); if (j->jfd == -1) { err = -errno; goto fail; } err = vhd_test_file_fixed(j->jname, &j->is_block); if (err) goto fail; vhd->fd = open(file, O_LARGEFILE | O_RDWR | O_DIRECT); if (vhd->fd == -1) { err = -errno; goto fail; } err = vhd_test_file_fixed(file, &vhd->is_block); if (err) goto fail; err = vhd_journal_read_journal_header(j, &j->header); if (err) goto fail; err = vhd_journal_restore_metadata(j); if (err) goto fail; close(vhd->fd); free(vhd->bat.bat); free(vhd->batmap.map); err = vhd_open(vhd, file, VHD_OPEN_RDWR); if (err) goto fail; err = vhd_get_bat(vhd); if (err) goto fail; if (vhd_has_batmap(vhd)) { err = vhd_get_batmap(vhd); if (err) goto fail; } err = vhd_journal_disable_vhd(j); if (err) goto fail; return 0; fail: vhd_journal_close(j); return err; }
int vhd_util_fill(int argc, char **argv) { int err, c; char *name; void *buf; vhd_context_t vhd; uint64_t i, sec, secs; buf = NULL; name = NULL; if (!argc || !argv) goto usage; optind = 0; while ((c = getopt(argc, argv, "n:h")) != -1) { switch (c) { case 'n': name = optarg; break; case 'h': default: goto usage; } } if (!name || optind != argc) goto usage; err = vhd_open(&vhd, name, VHD_OPEN_RDWR); if (err) { printf("error opening %s: %d\n", name, err); return err; } err = vhd_get_bat(&vhd); if (err) goto done; err = posix_memalign(&buf, 4096, vhd.header.block_size); if (err) { err = -err; goto done; } sec = 0; secs = vhd.header.block_size >> VHD_SECTOR_SHIFT; for (i = 0; i < vhd.header.max_bat_size; i++) { err = vhd_io_read(&vhd, buf, sec, secs); if (err) goto done; err = vhd_io_write(&vhd, buf, sec, secs); if (err) goto done; sec += secs; } err = 0; done: free(buf); vhd_close(&vhd); return err; usage: printf("options: <-n name> [-h help]\n"); return -EINVAL; }