⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vhd-util-check.c

📁 xen source 推出最新的VHD操作工具VHD-UTIL 实现源码,超强
💻 C
📖 第 1 页 / 共 2 页
字号:

	err = 0;

out:
	free(buf);
	return err;
}

static int
vhd_util_check_differencing_header(vhd_context_t *vhd)
{
	char *msg;

	msg = vhd_util_check_validate_differencing_header(vhd);
	if (msg) {
		printf("differencing header is invalid: %s\n", msg);
		return -EINVAL;
	}

	return 0;
}

static int
vhd_util_check_bat(vhd_context_t *vhd)
{
	off64_t eof, eoh;
	int i, j, err, block_size;

	err = vhd_seek(vhd, 0, SEEK_END);
	if (err) {
		printf("error calculating eof: %d\n", err);
		return err;
	}

	eof = vhd_position(vhd);
	if (eof == (off64_t)-1) {
		printf("error calculating eof: %d\n", -errno);
		return -errno;
	}

	/* adjust eof for vhds with short footers */
	if (eof % 512) {
		if (eof % 512 != 511) {
			printf("invalid file size: 0x%"PRIx64"\n", eof);
			return -EINVAL;
		}

		eof++;
	}

	err = vhd_get_bat(vhd);
	if (err) {
		printf("error reading bat: %d\n", err);
		return err;
	}

	err = vhd_end_of_headers(vhd, &eoh);
	if (err) {
		printf("error calculating end of metadata: %d\n", err);
		return err;
	}

	eof  -= sizeof(vhd_footer_t);
	eof >>= VHD_SECTOR_SHIFT;
	eoh >>= VHD_SECTOR_SHIFT;
	block_size = vhd->spb + vhd->bm_secs;

	for (i = 0; i < vhd->header.max_bat_size; i++) {
		uint32_t off = vhd->bat.bat[i];
		if (off == DD_BLK_UNUSED)
			continue;

		if (off < eoh) {
			printf("block %d (offset 0x%x) clobbers headers\n",
			       i, off);
			return -EINVAL;
		}

		if (off + block_size > eof) {
			printf("block %d (offset 0x%x) clobbers footer\n",
			       i, off);
			return -EINVAL;
		}

		for (j = 0; j < vhd->header.max_bat_size; j++) {
			uint32_t joff = vhd->bat.bat[j];

			if (i == j)
				continue;

			if (joff == DD_BLK_UNUSED)
				continue;

			if (off == joff)
				err = -EINVAL;

			if (off > joff && off < joff + block_size)
				err = -EINVAL;

			if (off + block_size > joff &&
			    off + block_size < joff + block_size)
				err = -EINVAL;

			if (err) {
				printf("block %d (offset 0x%x) clobbers "
				       "block %d (offset 0x%x)\n",
				       i, off, j, joff);
				return err;
			}
		}
	}

	return 0;
}

static int
vhd_util_check_batmap(vhd_context_t *vhd)
{
	char *msg;
	int i, err;

	err = vhd_get_bat(vhd);
	if (err) {
		printf("error reading bat: %d\n", err);
		return err;
	}

	err = vhd_get_batmap(vhd);
	if (err) {
		printf("error reading batmap: %d\n", err);
		return err;
	}

	msg = vhd_util_check_validate_batmap(vhd, &vhd->batmap);
	if (msg) {
		printf("batmap is invalid: %s\n", msg);
		return -EINVAL;
	}

	for (i = 0; i < vhd->header.max_bat_size; i++) {
		if (!vhd_batmap_test(vhd, &vhd->batmap, i))
			continue;

		if (vhd->bat.bat[i] == DD_BLK_UNUSED) {
			printf("batmap shows unallocated block %d full\n", i);
			return -EINVAL;
		}
	}

	return 0;
}

static int
vhd_util_check_parent_locators(vhd_context_t *vhd)
{
	int i, n, err;
	vhd_parent_locator_t *loc;
	char *msg, *file, *ppath, *location, *pname;
	int mac, macx, w2ku, w2ru, wi2r, wi2k, found;

	mac      = 0;
	macx     = 0;
	w2ku     = 0;
	w2ru     = 0;
	wi2r     = 0;
	wi2k     = 0;
	found    = 0;
	pname    = NULL;
	ppath    = NULL;
	location = NULL;

	err = vhd_header_decode_parent(vhd, &vhd->header, &pname);
	if (err) {
		printf("error decoding parent name: %d\n", err);
		return err;
	}

	n = sizeof(vhd->header.loc) / sizeof(vhd->header.loc[0]);
	for (i = 0; i < n; i++) {
		ppath    = NULL;
		location = NULL;
		loc = vhd->header.loc + i;

		msg = vhd_util_check_validate_parent_locator(vhd, loc);
		if (msg) {
			err = -EINVAL;
			printf("invalid parent locator %d: %s\n", i, msg);
			goto out;
		}

		if (loc->code == PLAT_CODE_NONE)
			continue;

		switch (loc->code) {
		case PLAT_CODE_MACX:
			if (macx++)
				goto dup;
			break;

		case PLAT_CODE_MAC:
			if (mac++)
				goto dup;
			break;

		case PLAT_CODE_W2KU:
			if (w2ku++)
				goto dup;
			break;

		case PLAT_CODE_W2RU:
			if (w2ru++)
				goto dup;
			break;

		case PLAT_CODE_WI2R:
			if (wi2r++)
				goto dup;
			break;

		case PLAT_CODE_WI2K:
			if (wi2k++)
				goto dup;
			break;

		default:
			err = -EINVAL;
			printf("invalid  platform code for locator %d\n", i);
			goto out;
		}

		if (loc->code != PLAT_CODE_MACX &&
		    loc->code != PLAT_CODE_W2RU &&
		    loc->code != PLAT_CODE_W2KU)
			continue;

		err = vhd_parent_locator_read(vhd, loc, &ppath);
		if (err) {
			printf("error reading parent locator %d: %d\n", i, err);
			goto out;
		}

		file = basename(ppath);
		if (strcmp(pname, file)) {
			err = -EINVAL;
			printf("parent locator %d name (%s) does not match "
			       "header name (%s)\n", i, file, pname);
			goto out;
		}

		err = vhd_find_parent(vhd, ppath, &location);
		if (err) {
			printf("error resolving %s: %d\n", ppath, err);
			goto out;
		}

		err = access(location, R_OK);
		if (err && loc->code == PLAT_CODE_MACX) {
			err = -errno;
			printf("parent locator %d points to missing file %s "
				"(resolved to %s)\n", i, ppath, location);
			goto out;
		}

		msg = vhd_util_check_validate_parent(vhd, location);
		if (msg) {
			err = -EINVAL;
			printf("invalid parent %s: %s\n", location, msg);
			goto out;
		}

		found++;
		free(ppath);
		free(location);
		ppath = NULL;
		location = NULL;

		continue;

	dup:
		printf("duplicate platform code in locator %d: 0x%x\n",
		       i, loc->code);
		err = -EINVAL;
		goto out;
	}

	if (!found) {
		err = -EINVAL;
		printf("could not find parent %s\n", pname);
		goto out;
	}

	err = 0;

out:
	free(pname);
	free(ppath);
	free(location);
	return err;
}

static void
vhd_util_dump_headers(const char *name)
{
	char *argv[] = { "read", "-p", "-n", (char *)name };
	int argc = sizeof(argv) / sizeof(argv[0]);

	printf("%s appears invalid; dumping metadata\n", name);
	vhd_util_read(argc, argv);
}

static int
vhd_util_check_vhd(const char *name, int ignore)
{
	int fd, err;
	vhd_context_t vhd;
	struct stat stats;
	vhd_footer_t footer;

	fd = -1;
	memset(&vhd, 0, sizeof(vhd));

	err = stat(name, &stats);
	if (err == -1) {
		printf("cannot stat %s: %d\n", name, errno);
		return -errno;
	}

	if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
		printf("%s is not a regular file or block device\n", name);
		return -EINVAL;
	}

	fd = open(name, O_RDONLY | O_DIRECT | O_LARGEFILE);
	if (fd == -1) {
		printf("error opening %s\n", name);
		return -errno;
	}

	err = vhd_util_check_footer(fd, &footer, ignore);
	if (err)
		goto out;

	if (footer.type != HD_TYPE_DYNAMIC && footer.type != HD_TYPE_DIFF)
		goto out;

	err = vhd_util_check_header(fd, &footer);
	if (err)
		goto out;

	err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
	if (err)
		goto out;

	err = vhd_util_check_differencing_header(&vhd);
	if (err)
		goto out;

	err = vhd_util_check_bat(&vhd);
	if (err)
		goto out;

	if (vhd_has_batmap(&vhd)) {
		err = vhd_util_check_batmap(&vhd);
		if (err)
			goto out;
	}

	if (vhd.footer.type == HD_TYPE_DIFF) {
		err = vhd_util_check_parent_locators(&vhd);
		if (err)
			goto out;
	}

	err = 0;
	printf("%s is valid\n", name);

out:
	if (err)
		vhd_util_dump_headers(name);
	if (fd != -1)
		close(fd);
	vhd_close(&vhd);
	return err;
}

static int
vhd_util_check_parents(const char *name, int ignore)
{
	int err;
	vhd_context_t vhd;
	char *cur, *parent;

	cur = (char *)name;

	for (;;) {
		err = vhd_open(&vhd, cur, 
				VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
		if (err)
			goto out;

		if (vhd.footer.type != HD_TYPE_DIFF || vhd_parent_raw(&vhd)) {
			vhd_close(&vhd);
			goto out;
		}

		err = vhd_parent_locator_get(&vhd, &parent);
		vhd_close(&vhd);

		if (err) {
			printf("error getting parent: %d\n", err);
			goto out;
		}

		if (cur != name)
			free(cur);
		cur = parent;

		err = vhd_util_check_vhd(cur, ignore);
		if (err)
			goto out;
	}

out:
	if (err)
		printf("error checking parents: %d\n", err);
	if (cur != name)
		free(cur);
	return err;
}

int
vhd_util_check(int argc, char **argv)
{
	char *name;
	vhd_context_t vhd;
	int c, err, ignore, parents;

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

	ignore  = 0;
	parents = 0;
	name    = NULL;

	optind = 0;
	while ((c = getopt(argc, argv, "n:iph")) != -1) {
		switch (c) {
		case 'n':
			name = optarg;
			break;
		case 'i':
			ignore = 1;
			break;
		case 'p':
			parents = 1;
			break;
		case 'h':
			err = 0;
			goto usage;
		default:
			err = -EINVAL;
			goto usage;
		}
	}

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

	err = vhd_util_check_vhd(name, ignore);
	if (err)
		goto out;

	if (parents)
		err = vhd_util_check_parents(name, ignore);

out:
	return err;

usage:
	printf("options: -n <file> [-i ignore missing primary footers] "
	       "[-p check parents] [-h help]\n");
	return err;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -