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;
}
Exemple #2
0
static int vhd_util_check_depth(const char *name, int *depth)
{
    int err;
    vhd_context_t vhd;

    err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
    if (err)
        return err;

    err = vhd_chain_depth(&vhd, depth);
    vhd_close(&vhd);

    return err;
}
int
vhd_util_repair(int argc, char **argv)
{
	char *name;
	int err, c;
	off64_t eof;
	vhd_context_t vhd;

	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_write_footer(&vhd, &vhd.footer);
	if (err)
		printf("error writing footer: %d\n", err);

	vhd_close(&vhd);
	return err;

usage:
	printf("options: <-n name> [-h help]\n");
	return -EINVAL;
}
Exemple #4
0
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;
}
Exemple #5
0
int vhd_util_snapshot(int argc, char **argv)
{
    vhd_flag_creat_t flags;
    int c, err, prt_raw, limit, empty_check;
    char *name, *pname, *backing;
    char *ppath, __ppath[PATH_MAX];
    uint64_t size, msize;
    vhd_context_t vhd;

    name = NULL;
    pname = NULL;
    ppath = NULL;
    backing = NULL;
    size = 0;
    msize = 0;
    flags = 0;
    limit = 0;
    empty_check = 1;

    if (!argc || !argv) {
        err = -EINVAL;
        goto usage;
    }

    optind = 0;
    while ((c = getopt(argc, argv, "n:p:S:l:meh")) != -1) {

        switch (c) {
        case 'n':
            name = optarg;
            break;
        case 'p':
            pname = optarg;
            break;
        case 'S':
            msize = strtoull(optarg, NULL, 10);
        case 'l':
            limit = strtol(optarg, NULL, 10);
            break;
        case 'm':
            vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
            break;
        case 'e':
            empty_check = 0;
            break;
        case 'h':
            err = 0;
            goto usage;
        default:
            err = -EINVAL;
            goto usage;
        }
    }

    if (!name || !pname || optind != argc) {
        err = -EINVAL;
        goto usage;
    }

    ppath = realpath(pname, __ppath);
    if (!ppath)
        return -errno;

    if (vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW) || !empty_check) {
        backing = strdup(ppath);
        if (!backing) {
            err = -ENOMEM;
            goto out;
        }
    } else {
        err = vhd_util_find_snapshot_target(ppath, &backing, &prt_raw);
        if (err) {
            backing = NULL;
            goto out;
        }

        /* 
         * if the sizes of the parent chain are non-uniform, we need to 
         * pick the right size: that of the supplied parent
         */
        if (strcmp(ppath, backing)) {
            err = vhd_open(&vhd, ppath, VHD_OPEN_RDONLY);
            if (err)
                goto out;
            size = vhd.footer.curr_size;
            vhd_close(&vhd);
        }

        if (prt_raw)
            vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
    }

    if (limit && !vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
        int depth;

        err = vhd_util_check_depth(backing, &depth);
        if (err)
            printf("error checking snapshot depth: %d\n", err);
        else if (depth + 1 > limit) {
            err = -ENOSPC;
            printf("snapshot depth exceeded: "
                   "current depth: %d, limit: %d\n", depth, limit);
        }

        if (err)
            goto out;
    }

    err = vhd_snapshot(name, size, backing, msize << 20, flags);

  out:
    free(backing);

    return err;

  usage:
    printf("options: <-n name> <-p parent name> [-l snapshot depth limit]"
           " [-m parent_is_raw] [-S size (MB) for metadata preallocation "
           "(see vhd-util resize)] [-e link to supplied parent name even "
           "if it's empty] [-h help]\n");
    return err;
}
Exemple #6
0
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;
}
Exemple #7
0
/*
 * revert indicates the transaction failed
 * and we should revert any changes via the undo log
 */
int
vhd_journal_revert(vhd_journal_t *j)
{
	int i, err;
	char *file;
	void *buf;
	vhd_context_t *vhd;
	vhd_journal_entry_t entry;

	err  = 0;
	vhd  = &j->vhd;
	buf  = NULL;

	file = strdup(vhd->file);
	if (!file)
		return -ENOMEM;

	vhd_close(&j->vhd);
	j->vhd.fd = open(file, O_RDWR | O_DIRECT | O_LARGEFILE);
	if (j->vhd.fd == -1) {
		free(file);
		return -errno;
	}

	err = vhd_test_file_fixed(file, &vhd->is_block);
	if (err) {
		free(file);
		return err;
	}

	err  = vhd_journal_restore_metadata(j);
	if (err) {
		free(file);
		return err;
	}

	close(vhd->fd);
	free(vhd->bat.bat);
	free(vhd->batmap.map);

	err = vhd_open(vhd, file, VHD_OPEN_RDWR);
	free(file);
	if (err)
		return err;

	err = vhd_journal_seek(j, j->header.journal_data_offset, SEEK_SET);
	if (err)
		return err;

	for (i = 0; i < j->header.journal_data_entries; i++) {
		err = vhd_journal_read_entry(j, &entry);
		if (err)
			goto end;

		err = posix_memalign(&buf, VHD_SECTOR_SIZE, entry.size);
		if (err) {
			err = -err;
			buf = NULL;
			goto end;
		}

		err = vhd_journal_read(j, buf, entry.size);
		if (err)
			goto end;

		err = vhd_journal_validate_entry_data(&entry, buf);
		if (err)
			goto end;

		err = vhd_seek(vhd, entry.offset, SEEK_SET);
		if (err)
			goto end;

		err = vhd_write(vhd, buf, entry.size);
		if (err)
			goto end;

		err = 0;

	end:
		free(buf);
		buf = NULL;
		if (err)
			break;
	}

	if (err)
		return err;

	if (!vhd->is_block) {
		err = ftruncate(vhd->fd, j->header.vhd_footer_offset +
				sizeof(vhd_footer_t));
		if (err)
			return -errno;
	}

	return vhd_journal_sync(j);
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}
Exemple #11
0
int
vhd_util_set_field(int argc, char **argv)
{
	long value;
	int err, c;
	vhd_context_t vhd;
	char *name, *field;

	err   = -EINVAL;
	value = 0;
	name  = NULL;
	field = NULL;

	if (!argc || !argv)
		goto usage;

	optind = 0;
	while ((c = getopt(argc, argv, "n:f:v:h")) != -1) {
		switch (c) {
		case 'n':
			name = optarg;
			break;
		case 'f':
			field = optarg;
			break;
		case 'v':
			err   = 0;
			value = strtol(optarg, NULL, 10);
			break;
		case 'h':
		default:
			goto usage;
		}
	}

	if (!name || !field || optind != argc || err)
		goto usage;

	if (strnlen(field, 25) >= 25) {
		printf("invalid field\n");
		goto usage;
	}

	if (strcmp(field, "hidden") && strcmp(field, "marker")) {
		printf("invalid field %s\n", field);
		goto usage;
	}

	if (value < 0 || value > 255) {
		printf("invalid value %ld\n", value);
		goto usage;
	}

	err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
	if (err) {
		printf("error opening %s: %d\n", name, err);
		return err;
	}

	if (!strcmp(field, "hidden")) {
		vhd.footer.hidden = (char)value;
		err = vhd_write_footer(&vhd, &vhd.footer);
		if (err == -ENOSPC && vhd_type_dynamic(&vhd) && value)
			/* if no space to write the primary footer, at least write the 
			 * backup footer so that it's possible to delete the VDI */
			err = vhd_write_footer_at(&vhd, &vhd.footer, 0);
	} else {
		err = vhd_set_marker(&vhd, (char)value);
	}
		
 	vhd_close(&vhd);
	return err;

usage:
	printf("options: <-n name> <-f field> <-v value> [-h help]\n");
	return -EINVAL;
}