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

📄 vhd-util-check.c

📁 xen source 推出最新的VHD操作工具VHD-UTIL 实现源码,超强
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (c) 2008, XenSource Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of XenSource Inc. nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <inttypes.h>
#include <sys/stat.h>

#include "libvhd.h"
#include "vhd-util.h"

// allow the VHD timestamp to be at most this many seconds into the future to 
// account for time skew with NFS servers
#define TIMESTAMP_MAX_SLACK 1800

static int
vhd_util_check_zeros(void *buf, size_t size)
{
	int i;
	char *p;

	p = buf;
	for (i = 0; i < size; i++)
		if (p[i])
			return i;

	return 0;
}

static int
vhd_util_check_footer_opened(vhd_footer_t *footer)
{
	int i, n;
	uint32_t *buf;

	buf = (uint32_t *)footer;
	n = sizeof(*footer) / sizeof(uint32_t);

	for (i = 0; i < n; i++)
		if (buf[i] != 0xc7c7c7c7)
			return 0;

	return 1;
}

static char *
vhd_util_check_validate_footer(vhd_footer_t *footer)
{
	int size;
	uint32_t checksum, now;

	size = sizeof(footer->cookie);
	if (memcmp(footer->cookie, HD_COOKIE, size))
		return "invalid cookie";

	checksum = vhd_checksum_footer(footer);
	if (checksum != footer->checksum) {
		if (footer->hidden &&
		    !strncmp(footer->crtr_app, "tap", 3) &&
		    (footer->crtr_ver == VHD_VERSION(0, 1) ||
		     footer->crtr_ver == VHD_VERSION(1, 1))) {
			char tmp = footer->hidden;
			footer->hidden = 0;
			checksum = vhd_checksum_footer(footer);
			footer->hidden = tmp;

			if (checksum == footer->checksum)
				goto ok;
		}

		return "invalid checksum";
	}

ok:
	if (!(footer->features & HD_RESERVED))
		return "invalid 'reserved' feature";

	if (footer->features & ~(HD_TEMPORARY | HD_RESERVED))
		return "invalid extra features";

	if (footer->ff_version != HD_FF_VERSION)
		return "invalid file format version";

	if (footer->type != HD_TYPE_DYNAMIC &&
	    footer->type != HD_TYPE_DIFF    &&
	    footer->data_offset != ~(0ULL))
		return "invalid data offset";

	now = vhd_time(time(NULL));
	if (footer->timestamp > now + TIMESTAMP_MAX_SLACK)
		return "creation time in future";

	if (!strncmp(footer->crtr_app, "tap", 3) &&
	    footer->crtr_ver > VHD_CURRENT_VERSION)
		return "unsupported tap creator version";

	if (vhd_chs(footer->curr_size) < footer->geometry)
		return "geometry too large";

	if (footer->type != HD_TYPE_FIXED   &&
	    footer->type != HD_TYPE_DYNAMIC &&
	    footer->type != HD_TYPE_DIFF)
		return "invalid type";

	if (footer->saved && footer->saved != 1)
		return "invalid 'saved' state";

	if (footer->hidden && footer->hidden != 1)
		return "invalid 'hidden' state";

	if (vhd_util_check_zeros(footer->reserved,
				 sizeof(footer->reserved)))
		return "invalid 'reserved' bits";

	return NULL;
}

static char *
vhd_util_check_validate_header(int fd, vhd_header_t *header)
{
	off64_t eof;
	int i, cnt, size;
	uint32_t checksum;

	size = sizeof(header->cookie);
	if (memcmp(header->cookie, DD_COOKIE, size))
		return "invalid cookie";

	checksum = vhd_checksum_header(header);
	if (checksum != header->checksum)
		return "invalid checksum";

	if (header->hdr_ver != 0x00010000)
		return "invalid header version";

	if (header->data_offset != ~(0ULL))
		return "invalid data offset";

	eof = lseek64(fd, 0, SEEK_END);
	if (eof == (off64_t)-1)
		return "error finding eof";

	if (header->table_offset <= 0  ||
	    header->table_offset % 512 ||
	    (header->table_offset +
	     (header->max_bat_size * sizeof(uint32_t)) >
	     eof - sizeof(vhd_footer_t)))
		return "invalid table offset";

	for (cnt = 0, i = 0; i < sizeof(header->block_size) * 8; i++)
		if ((header->block_size >> i) & 1)
			cnt++;

	if (cnt != 1)
		return "invalid block size";

	if (header->res1)
		return "invalid reserved bits";

	if (vhd_util_check_zeros(header->res2, sizeof(header->res2)))
		return "invalid reserved bits";

	return NULL;
}

static char *
vhd_util_check_validate_differencing_header(vhd_context_t *vhd)
{
	vhd_header_t *header;

	header = &vhd->header;

	if (vhd->footer.type == HD_TYPE_DIFF) {
		char *parent;
		uint32_t now;

		now = vhd_time(time(NULL));
		if (header->prt_ts > now + TIMESTAMP_MAX_SLACK)
			return "parent creation time in future";

		if (vhd_header_decode_parent(vhd, header, &parent))
			return "invalid parent name";

		free(parent);
	} else {
		if (vhd_util_check_zeros(header->prt_name,
					 sizeof(header->prt_name)))
			return "invalid non-null parent name";

		if (vhd_util_check_zeros(header->loc, sizeof(header->loc)))
			return "invalid non-null parent locators";

		if (!uuid_is_null(header->prt_uuid))
			return "invalid non-null parent uuid";

		if (header->prt_ts)
			return "invalid non-zero parent timestamp";
	}

	return NULL;
}

static char *
vhd_util_check_validate_batmap(vhd_context_t *vhd, vhd_batmap_t *batmap)
{
	int size;
	off64_t eof;
	uint32_t checksum;

	size = sizeof(batmap->header.cookie);
	if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, size))
		return "invalid cookie";

	if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION)
		return "unsupported batmap version";

	checksum = vhd_checksum_batmap(batmap);
	if (checksum != batmap->header.checksum)
		return "invalid checksum";

	if (!batmap->header.batmap_size)
		return "invalid size zero";

	eof = lseek64(vhd->fd, 0, SEEK_END);
	if (eof == (off64_t)-1)
		return "error finding eof";

	if (!batmap->header.batmap_offset ||
	    batmap->header.batmap_offset % 512)
		return "invalid batmap offset";

	if ((batmap->header.batmap_offset +
	     vhd_sectors_to_bytes(batmap->header.batmap_size)) >
	    eof - sizeof(vhd_footer_t))
		return "invalid batmap size";

	return NULL;
}

static char *
vhd_util_check_validate_parent_locator(vhd_context_t *vhd,
				       vhd_parent_locator_t *loc)
{
	off64_t eof;

	if (vhd_validate_platform_code(loc->code))
		return "invalid platform code";

	if (loc->code == PLAT_CODE_NONE) {
		if (vhd_util_check_zeros(loc, sizeof(*loc)))
			return "non-zero locator";

		return NULL;
	}

	if (!loc->data_offset)
		return "invalid data offset";

	if (!loc->data_space)
		return "invalid data space";

	if (!loc->data_len)
		return "invalid data length";

	eof = lseek64(vhd->fd, 0, SEEK_END);
	if (eof == (off64_t)-1)
		return "error finding eof";

	if (loc->data_offset + vhd_parent_locator_size(loc) >
	    eof - sizeof(vhd_footer_t))
		return "invalid size";

	if (loc->res)
		return "invalid reserved bits";

	return NULL;
}

static char *
vhd_util_check_validate_parent(vhd_context_t *vhd, const char *ppath)
{
	char *msg;
	vhd_context_t parent;

	msg = NULL;

	if (vhd_parent_raw(vhd))
		return msg;

	if (vhd_open(&parent, ppath,
				VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED))
		return "error opening parent";

	if (uuid_compare(vhd->header.prt_uuid, parent.footer.uuid)) {
		msg = "invalid parent uuid";
		goto out;
	}

out:
	vhd_close(&parent);
	return msg;
}

static int
vhd_util_check_footer(int fd, vhd_footer_t *footer, int ignore)
{
	size_t size;
	int err, opened;
	char *msg, *buf;
	off64_t eof, off;
	vhd_footer_t primary, backup;

	memset(&primary, 0, sizeof(primary));
	memset(&backup, 0, sizeof(backup));

	err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(primary));
	if (err) {
		printf("error allocating buffer: %d\n", err);
		return -err;
	}

	memset(buf, 0, sizeof(primary));

	eof = lseek64(fd, 0, SEEK_END);
	if (eof == (off64_t)-1) {
		err = -errno;
		printf("error calculating end of file: %d\n", err);
		goto out;
	}

	size = ((eof % 512) ? 511 : 512);
	eof  = lseek64(fd, eof - size, SEEK_SET);
	if (eof == (off64_t)-1) {
		err = -errno;
		printf("error calculating end of file: %d\n", err);
		goto out;
	}

	err = read(fd, buf, 512);
	if (err != size) {
		err = (errno ? -errno : -EIO);
		printf("error reading primary footer: %d\n", err);
		goto out;
	}

	memcpy(&primary, buf, sizeof(primary));
	opened = vhd_util_check_footer_opened(&primary);
	vhd_footer_in(&primary);

	msg = vhd_util_check_validate_footer(&primary);
	if (msg) {
		if (opened && ignore)
			goto check_backup;

		err = -EINVAL;
		printf("primary footer invalid: %s\n", msg);
		goto out;
	}

	if (primary.type == HD_TYPE_FIXED) {
		err = 0;
		goto out;
	}

check_backup:
	off = lseek64(fd, 0, SEEK_SET);
	if (off == (off64_t)-1) {
		err = -errno;
		printf("error seeking to backup footer: %d\n", err);
		goto out;
	}

	size = 512;
	memset(buf, 0, sizeof(primary));

	err = read(fd, buf, size);
	if (err != size) {
		err = (errno ? -errno : -EIO);
		printf("error reading backup footer: %d\n", err);
		goto out;
	}

	memcpy(&backup, buf, sizeof(backup));
	vhd_footer_in(&backup);

	msg = vhd_util_check_validate_footer(&backup);
	if (msg) {
		err = -EINVAL;
		printf("backup footer invalid: %s\n", msg);
		goto out;
	}

	if (memcmp(&primary, &backup, sizeof(primary))) {
		if (opened && ignore) {
			memcpy(&primary, &backup, sizeof(primary));
			goto ok;
		}

		if (backup.hidden &&
		    !strncmp(backup.crtr_app, "tap", 3) &&
		    (backup.crtr_ver == VHD_VERSION(0, 1) ||
		     backup.crtr_ver == VHD_VERSION(1, 1))) {
			char cmp, tmp = backup.hidden;
			backup.hidden = 0;
			cmp = memcmp(&primary, &backup, sizeof(primary));
			backup.hidden = tmp;
			if (!cmp)
				goto ok;
		}

		err = -EINVAL;
		printf("primary and backup footers do not match\n");
		goto out;
	}

ok:
	err = 0;
	memcpy(footer, &primary, sizeof(primary));

out:
	free(buf);
	return err;
}

static int
vhd_util_check_header(int fd, vhd_footer_t *footer)
{
	int err;
	off64_t off;
	char *msg, *buf;
	vhd_header_t header;

	err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(header));
	if (err) {
		printf("error allocating header: %d\n", err);
		return err;
	}

	off = footer->data_offset;
	off = lseek64(fd, off, SEEK_SET);
	if (off == (off64_t)-1) {
		err = -errno;
		printf("error seeking to header: %d\n", err);
		goto out;
	}

	err = read(fd, buf, sizeof(header));
	if (err != sizeof(header)) {
		err = (errno ? -errno : -EIO);
		printf("error reading header: %d\n", err);
		goto out;
	}

	memcpy(&header, buf, sizeof(header));
	vhd_header_in(&header);

	msg = vhd_util_check_validate_header(fd, &header);
	if (msg) {
		err = -EINVAL;
		printf("header is invalid: %s\n", msg);
		goto out;
	}

⌨️ 快捷键说明

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